diff --git a/.all-contributorsrc b/.all-contributorsrc index 0c02eac92..8a9cc8163 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1,9 +1,19 @@ { "files": [ - "README.md" + "README.basque.md", + "README.brazilian-portuguese.md", + "README.chinese.md", + "README.french.md", + "README.indonesian.md", + "README.japanese.md", + "README.korean.md", + "README.md", + "README.polish.md", + "README.russian.md" ], "imageSize": 100, "contributorsPerLine": 7, + "contributorTemplate": "\">\" width=\"<%= options.imageSize %>px;\" alt=\"<%= contributor.name %>\"style=\"max-width:<%= options.imageSize %>px;min-width:<%= options.imageSize %>px;\" />
<%= contributor.name %>

<%= contributions %>", "badgeTemplate": "[![All Contributors](https://img.shields.io/badge/all_contributors-<%= contributors.length %>-orange.svg?style=flat-square)](#contributors)", "contributors": [ { @@ -1505,11 +1515,247 @@ "contributions": [ "content" ] + }, + { + "login": "breno404", + "name": "Breno Macedo", + "avatar_url": "https://avatars.githubusercontent.com/u/48841329?v=4", + "profile": "https://www.linkedin.com/in/breno-macedo-ernani-de-s%C3%A1-110223158/", + "contributions": [ + "content" + ] + }, + { + "login": "JFernando122", + "name": "Fernando Flores", + "avatar_url": "https://avatars.githubusercontent.com/u/40414805?v=4", + "profile": "https://github.com/JFernando122", + "contributions": [ + "translation" + ] + }, + { + "login": "rafaelconcept", + "name": "Rafael Brito", + "avatar_url": "https://avatars.githubusercontent.com/u/43880669?v=4", + "profile": "https://www.linkedin.com/in/rafaelconcept/", + "contributions": [ + "translation" + ] + }, + { + "login": "emiperalta", + "name": "Emiliano Peralta", + "avatar_url": "https://avatars.githubusercontent.com/u/63617637?v=4", + "profile": "https://emiliano-peralta-portfolio.vercel.app/", + "contributions": [ + "translation" + ] + }, + { + "login": "lannex", + "name": "Shin, SJ", + "avatar_url": "https://avatars.githubusercontent.com/u/7369541?v=4", + "profile": "https://lannex.github.io", + "contributions": [ + "content" + ] + }, + { + "login": "e-e-e", + "name": "Benjamin Forster", + "avatar_url": "https://avatars.githubusercontent.com/u/12589522?v=4", + "profile": "http://www.benjaminforster.com", + "contributions": [ + "content" + ] + }, + { + "login": "DanieleFedeli", + "name": "Daniele Fedeli", + "avatar_url": "https://avatars.githubusercontent.com/u/37077048?v=4", + "profile": "https://github.com/DanieleFedeli", + "contributions": [ + "content" + ] + }, + { + "login": "djob195", + "name": "djob195", + "avatar_url": "https://avatars.githubusercontent.com/u/17146669?v=4", + "profile": "https://github.com/djob195", + "contributions": [ + "content" + ] + }, + { + "login": "antspk", + "name": "antspk", + "avatar_url": "https://avatars.githubusercontent.com/u/78955792?v=4", + "profile": "https://github.com/antspk", + "contributions": [ + "content" + ] + }, + { + "login": "jjy821", + "name": "정진영", + "avatar_url": "https://avatars.githubusercontent.com/u/88075341?v=4", + "profile": "https://jjy0821.tistory.com/", + "contributions": [ + "content" + ] + }, + { + "login": "kkk-cashwalk", + "name": "kkk-cashwalk", + "avatar_url": "https://avatars.githubusercontent.com/u/91455122?v=4", + "profile": "https://github.com/kkk-cashwalk", + "contributions": [ + "content" + ] + }, + { + "login": "apainintheneck", + "name": "apainintheneck", + "avatar_url": "https://avatars.githubusercontent.com/u/42982186?v=4", + "profile": "https://github.com/apainintheneck", + "contributions": [ + "content" + ] + }, + { + "login": "koyanyaroo", + "name": "Fajar Budhi Iswanda", + "avatar_url": "https://avatars.githubusercontent.com/u/9715368?v=4", + "profile": "https://github.com/koyanyaroo", + "contributions": [ + "content" + ] + }, + { + "login": "jutiger", + "name": "이주호", + "avatar_url": "https://avatars.githubusercontent.com/u/97490806?v=4", + "profile": "https://github.com/jutiger", + "contributions": [ + "content" + ] + }, + { + "login": "MisterSingh", + "name": "Singh", + "avatar_url": "https://avatars.githubusercontent.com/u/44462019?v=4", + "profile": "https://github.com/MisterSingh", + "contributions": [ + "content" + ] + }, + { + "login": "Alex-Dumitru", + "name": "Alex Dumitru", + "avatar_url": "https://avatars.githubusercontent.com/u/43738450?v=4", + "profile": "https://github.com/Alex-Dumitru", + "contributions": [ + "content" + ] + }, + { + "login": "lykhatskyi", + "name": "Anton Lykhatskyi", + "avatar_url": "https://avatars.githubusercontent.com/u/18104686?v=4", + "profile": "https://github.com/lykhatskyi", + "contributions": [ + "content" + ] + }, + { + "login": "EverythingAvailable", + "name": "sangwonlee", + "avatar_url": "https://avatars.githubusercontent.com/u/81002379?v=4", + "profile": "https://github.com/EverythingAvailable", + "contributions": [ + "content" + ] + }, + { + "login": "euberdeveloper", + "name": "Eugenio Berretta", + "avatar_url": "https://avatars.githubusercontent.com/u/33126163?v=4", + "profile": "https://github.com/euberdeveloper", + "contributions": [ + "content" + ] + }, + { + "login": "soranakk", + "name": "soranakk", + "avatar_url": "https://avatars.githubusercontent.com/u/3930307?v=4", + "profile": "https://github.com/soranakk", + "contributions": [ + "content" + ] + }, + { + "login": "backend-joonyoung", + "name": "고준영", + "avatar_url": "https://avatars.githubusercontent.com/u/94430145?v=4", + "profile": "https://github.com/backend-joonyoung", + "contributions": [ + "content", + "code" + ] + }, + { + "login": "GuilhermePortella", + "name": "Guilherme Portella ", + "avatar_url": "https://avatars.githubusercontent.com/u/59876059?v=4", + "profile": "https://github.com/GuilhermePortella", + "contributions": [ + "content" + ] + }, + { + "login": "Esser50K", + "name": "André Esser", + "avatar_url": "https://avatars.githubusercontent.com/u/18497570?v=4", + "profile": "https://www.youtube.com/channel/UCBxzOQd2v9wWfiMDrf_RQ7A", + "contributions": [ + "content" + ] + }, + { + "login": "ShiChenCong", + "name": "Scc", + "avatar_url": "https://avatars.githubusercontent.com/u/22486446?v=4", + "profile": "https://github.com/ShiChenCong", + "contributions": [ + "translation" + ] + }, + { + "login": "mauroaccornero", + "name": "Mauro Accornero", + "avatar_url": "https://avatars.githubusercontent.com/u/1875822?v=4", + "profile": "https://www.mauroaccornero.it", + "contributions": [ + "content" + ] + }, + { + "login": "no-yan", + "name": "no-yan", + "avatar_url": "https://avatars.githubusercontent.com/u/63000297?v=4", + "profile": "https://github.com/no-yan", + "contributions": [ + "content" + ] } ], "projectName": "nodebestpractices", "projectOwner": "goldbergyoni", "repoType": "github", "repoHost": "https://github.com", - "skipCi": true + "skipCi": true, + "commitConvention": "angular" } diff --git a/.github/workflows/automerge-prs.yml b/.github/workflows/automerge-prs.yml index 688899c29..3f8333e46 100644 --- a/.github/workflows/automerge-prs.yml +++ b/.github/workflows/automerge-prs.yml @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: automerge - uses: "pascalgn/automerge-action@v0.13.1" + uses: "pascalgn/automerge-action@v0.15.5" env: GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" MERGE_LABELS: "auto-merge,!work in progress" @@ -30,4 +30,4 @@ jobs: MERGE_FORKS: "false" MERGE_RETRIES: "6" MERGE_RETRY_SLEEP: "10000" - MERGE_DELETE_BRANCH: "true" \ No newline at end of file + MERGE_DELETE_BRANCH: "true" diff --git a/.github/workflows/lint-and-generate-html-from-markdown.yml b/.github/workflows/lint-and-generate-html-from-markdown.yml index e50557e2d..9c62c5b4b 100644 --- a/.github/workflows/lint-and-generate-html-from-markdown.yml +++ b/.github/workflows/lint-and-generate-html-from-markdown.yml @@ -18,32 +18,13 @@ jobs: NODE_ENV: test steps: - - name: Checkout - uses: actions/checkout@v1 + - name: Checkout + uses: actions/checkout@v3 - - name: Setup Node.js environment - uses: actions/setup-node@v2.1.2 - with: - node-version: '14' + - name: Setup Node.js environment + uses: actions/setup-node@v3 + with: + node-version: "18" - - run: npm install - - run: npm run lint - - build: - name: Build - runs-on: ubuntu-20.04 - - steps: - - name: Checkout - uses: actions/checkout@v1 - - - name: Setup Node.js environment - uses: actions/setup-node@v2.1.2 - with: - node-version: '14' - - - run: npm install - - run: npm run build - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - IS_FORK: ${{ github.repository != 'goldbergyoni/nodebestpractices' }} + - run: npm install + - run: npm run lint diff --git a/.github/workflows/update-date-in-last-update-badge.yml b/.github/workflows/update-date-in-last-update-badge.yml index 95873a926..c440307be 100644 --- a/.github/workflows/update-date-in-last-update-badge.yml +++ b/.github/workflows/update-date-in-last-update-badge.yml @@ -14,7 +14,7 @@ jobs: steps: - name: Checkout repo - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Update last update badge run: | @@ -24,7 +24,7 @@ jobs: "${GITHUB_WORKSPACE}/.github/workflows/update-last-update-badge.sh" "${GITHUB_WORKSPACE}/README.md" - name: Commit & Create Pull Request - uses: peter-evans/create-pull-request@v3 + uses: peter-evans/create-pull-request@v4 with: commit-message: update the last update badge to today [skip ci] author: Update Last Update Badge Action <${{ github.actor }}@users.noreply.github.com> diff --git a/.operations/.env.example b/.operations/.env.example deleted file mode 100644 index 77e1c98da..000000000 --- a/.operations/.env.example +++ /dev/null @@ -1 +0,0 @@ -GITHUB_TOKEN=REPLACEME \ No newline at end of file diff --git a/.operations/CONTRIBUTING.md b/.operations/CONTRIBUTING.md index 04139cc6f..2e9f76905 100644 --- a/.operations/CONTRIBUTING.md +++ b/.operations/CONTRIBUTING.md @@ -1,28 +1,50 @@ # Contribution guidelines -## What you should know first - -### Lovely & friendly atmosphere +## Lovely & friendly atmosphere Our code of conduct is 5 words long: we are all friends here We recognize that being professional and kind are the same thing and strive to maximize our professionalism -### Maintenance work +## Handling issues and PRs + +
+In a nutshell, every issue is an opprtunity to gain new knowledge and attract new contributor. Therefore we aim for vast response and welcoming words 💚 + +When merging a new PR, add the contributor to our credits list using the all-contributors bot. Just include this text as a PR comment: + +`@all-contributors please add @username for content` + +The specific PR/issue resolustion depends on its kind: + +**A. New best practice or fundamental changes to existing content -** In that case, involve at least 1 other members to solicit enough feedback for this change. Start by greeting the contributor, ensure the formalities are fine, ensure it conforms to our [writing guidelines](./writing-guidelines.md), ensure enough information was provided and then get at least 1 more collaborators and allow at least a week for comments + +**B. Plain text change (e.g. Grammar correctness) -** When super-simple wording edits are proposed (i.e. not new content rather language correctness), one can just greet, approve and merge immediately + +**C. Translations to a new (not existing) language -** When offered to add new language, greet the person and paste our [translation guidelines](./common-answers.md) + +**D. Edits to existing translations -** If the change can be inferred by the reviewer (e.g., a change of a symbol, number or just date update) then feel free to merge alone. If familiarity with the language is needed, tag the original translator and ask for feedback. The translators name can be found in the home page under "Translations" -Our operations manual [can be found here](https://github.com/goldbergyoni/nodebestpractices/blob/master/.operations/operations-manual.md) +**D. Dicussions and ideas -** When a technical discussion or just general conversation is brought into a new issue, apply your own judgements whether to tag other collaborators -### Writing guidelines -Our content writing guidelines [can be found here](https://github.com/goldbergyoni/nodebestpractices/blob/master/.operations/writing-guidelines.md) +## Assets to be aware of -### Handling issues and PRs +- Our content writing guidelines [can be found here](./writing-guidelines.md) +- Common questions and answers to issues/PRs [can be found here](./common-answers.md) -- Great the contributor with kindness -- If a straightforward fix is suggested (e.g., TYPO, linting fix, grammar improvement, etc) - Approve and merge -- When the proposed PR deals with a more opionionated topic - Encourage at least 2 reviewers, leave the PR open for a few days to allow more folks to chime-in -- Add the contributor to the contributor credit list with this command: `@all-contributors please add @username for content` +## Precommit +Before pushing, verify your Markdown passes [the linter](https://www.npmjs.com/package/markdownlint-cli) : + +```bash +npm run lint +``` +For example fix basic errors : + +```bash +npm run lint --fix +``` ## Contribution model @@ -37,15 +59,3 @@ Collaborators are members who are contributing to the repository on a regular ba The role is in place to help the steering committee ensure that the content provided is of high standard, up-to-date with the industry, and available in many languages. Members who frequently participate in these activities will be invited to become a collaborator, based on the quality of their contributions. The steering committee periodically reviews the collaborator list to identify inactive collaborators. Inactive collaborators can choose to either continue in or step down from their role, in which case they are acknowledged as a past collaborator. They may later request that the steering committee restore them to active status. - -### Other contributions ✨ - -This project follows the [All Contributors Specification](https://allcontributors.org/), which means we recognize all types of contributions, whether they are new suggested best practices/ideas, translations, or new content. - -If you have contributed to the project in some way and aren't listed, please add an entry for yourself by using the @all-contributors-bot in a Pull Request or issue. Examples: - -`@all-contributors-bot please add @js-kyle for code` - -`@all-contributors-bot please add @brunoscheufler for content` - -Contribution types are listed [here](https://allcontributors.org/docs/en/emoji-key). diff --git a/.operations/.common-answers.md b/.operations/common-answers.md similarity index 100% rename from .operations/.common-answers.md rename to .operations/common-answers.md diff --git a/.operations/gen-html.js b/.operations/gen-html.js deleted file mode 100644 index fa6808bcc..000000000 --- a/.operations/gen-html.js +++ /dev/null @@ -1,261 +0,0 @@ -const path = require('path'); -const cheerio = require('cheerio'); -const showdown = require('showdown'); -const Repository = require('github-api/dist/components/Repository'); -const { readdir, readFile, writeFile } = require('graceful-fs'); - -const imagemin = require('imagemin'); -const imageminJpegtran = require('imagemin-jpegtran'); -const imageminPngquant = require('imagemin-pngquant'); -const CIInfo = require('ci-info'); - -const converter = new showdown.Converter(); - -const templateFilePath = './.operations/res/template.html'; - -const imageminOpts = { - plugins: [ - imageminJpegtran(), - imageminPngquant({ quality: '65-80' }) - ] -}; - -console.info(`Working in [${process.cwd()}]`); - -const { isCI } = CIInfo; -const { GITHUB_TOKEN, OWNER_AND_REPO, BRANCH, IS_PR, IS_FORK } = getConfigFromEnv(); - -readDirPromise('./') - .then(async (fileNames) => { - const indexFileNames = fileNames.filter(fn => fn.includes('README.') && fn.includes('.md')); - - for (let fileName of indexFileNames) { - const startTime = new Date(); - console.info(`Beginning Generate Document [${fileName}] at [${startTime.toISOString()}]`); - try { - const templateHTML = await readFilePromise(templateFilePath); - const processedTemplateHTML = await inlineResources(templateHTML); - const outputHTML = await processMDFile(fileName, processedTemplateHTML); - console.info(`Completed Generation in [${computeElapsedTime(startTime)}s]`); - - const outFileName = path.parse(fileName).name + '.html'; - const outFilePath = path.join('.operations', 'out', outFileName); - console.info(`Writing output to [${outFilePath}]`); - await writeFilePromise(outFilePath, outputHTML); - - if(shouldUpdateGitHubPages()) { - const repo = new Repository(OWNER_AND_REPO, { - token: GITHUB_TOKEN - }); - - console.info(`Committing HTML file to branch [gh-pages]`); - await repo.writeFile('gh-pages', outFileName, outputHTML, ':loudspeaker: :robot: Automatically updating built HTML file', {}); - } - } catch (err) { - console.error(`Failed to generate from [${fileName}] in [${computeElapsedTime(startTime)}s]`, err); - process.exit(1); - } - } - }) - .then(() => { - console.log(`🎉 Finished gen-html 🎉`); - }) - -function getConfigFromEnv() { - if (CIInfo.GITHUB_ACTIONS) { - return getConfigFromGithubActionEnv() - } - return process.env; -} - -function getConfigFromGithubActionEnv() { - const config = { - ...process.env, - - OWNER_AND_REPO: process.env.GITHUB_REPOSITORY, - - IS_PR: CIInfo.IS_PR !== null ? CIInfo.IS_PR : process.env.GITHUB_EVENT_NAME === 'pull_request', - - // We assume we're in PR and and we get the source for the PR - BRANCH: process.env.GITHUB_HEAD_REF, - }; - - if(!config.IS_PR) { - // GITHUB_REF example: `refs/heads/main` - config.BRANCH = process.env.GITHUB_REF.substring('refs/heads/'.length); - } - - return config; -} - -function shouldUpdateGitHubPages() { - return isCI && !IS_FORK && !IS_PR && BRANCH === 'master'; -} - -function computeElapsedTime(startTime) { - return (Date.now() - startTime) / 1000; -} - - -async function processMDFile(filePath = '/', templateHTML = null) { - let mdSrc; - try { - mdSrc = await readFilePromise(filePath); - } catch (err) { - console.warn(`Failed to read file [${filePath}], does it exist?`); - return ''; - } - const generatedHTML = converter.makeHtml(mdSrc); - let nexHTML = generatedHTML; - if (templateHTML) { - const $ = cheerio.load(templateHTML); - $('.content').html(generatedHTML); - nexHTML = $.html(); - } - - const fileDir = path.parse(filePath).dir.replace(process.cwd(), '/') || '/'; - - console.log(`Processing file [${filePath}]`); - const outHtml = await ( - inlineLocalReferences(nexHTML, fileDir) - .then((html) => fixMdReferences(html)) - .then((html) => fixHashAs(html)) - .then((html) => inlineAssets(html, fileDir)) - ); - - return outHtml; -} - -const internalRefRegExp = /^((?!http)(?!#)(?!\/\/).)*$/; // Doesn't start with 'http', '//', or '#' -async function inlineLocalReferences(html, filePath = '/') { - const $ = cheerio.load(html); - const as = $('a'); - const internalAs = as.toArray().filter((a) => internalRefRegExp.test(a.attribs.href) && !a.attribs.href.includes('README')); - - const processedInternalRefs = await Promise.all( - internalAs.map((a) => processMDFile(path.resolve(filePath, a.attribs.href))) - ); - - processedInternalRefs.forEach((processedHTML, index) => { - const originalA = $(internalAs[index]); - - const contentId = originalA.text().replace(/[^A-Za-z0-9]/g, '_'); - $('.references').append([ - $('
'), - $('
') - .addClass('reference-section') - .attr('id', contentId) - .html(processedHTML) - ]); - - originalA.attr('href', `#${contentId}`); - }); - - return $.html(); -} - -async function fixMdReferences(html) { // Primarily for links to translations - const $ = cheerio.load(html); - const as = $('a'); - const mdReferences = as.toArray().filter((a) => internalRefRegExp.test(a.attribs.href) && a.attribs.href.includes('.md')); - - mdReferences - .forEach((a) => { - const $a = $(a); - const href = $a.attr('href') - const newHref = href.replace('.md', '.html'); - $a.attr('href', './' + newHref); - }) - - return $.html(); -} - -async function inlineAssets(html, filePath = '/') { - const $ = cheerio.load(html); - const imgs = $('img'); - const internalImgs = imgs.toArray().filter((img) => internalRefRegExp.test(img.attribs.src)); - - for (let img of internalImgs) { - const ext = path.parse(img.attribs.src).ext.slice(1); // parse().ext includes '.' - const imgPath = path.resolve('/', filePath, img.attribs.src); - const imgBuffer = await readFilePromise(imgPath, null); - const compressedImgBuffer = await imagemin.buffer(imgBuffer, imageminOpts); - const base64 = compressedImgBuffer.toString('base64'); - const mediaUri = `data:image/${ext};base64,${base64}`; - const originalImg = $(img); - originalImg.attr('src', mediaUri); - } - - return $.html(); -} - -async function fixHashAs(html) { - const $ = cheerio.load(html); - const as = $('a'); - - const hashAs = as.toArray().filter((a) => a.attribs.href[0] === '#'); - hashAs.forEach(a => { - $(a).attr('href', a.attribs.href.replace(/-/g, '')); - }); - - return $.html() -} - - - -async function inlineResources(html, filePath = '/') { - const $ = cheerio.load(html); - const scripts = $('script[src]'); - const links = $('link[href]'); - - const internalScripts = scripts.toArray().filter((script) => internalRefRegExp.test(script.attribs.src)); - const internalLinks = links.toArray().filter((link) => internalRefRegExp.test(link.attribs.href)); - - for (let scriptEl of internalScripts) { - const scriptPath = path.resolve('/', filePath, scriptEl.attribs.src); - const scriptBuffer = await readFilePromise(scriptPath, null); - const base64 = scriptBuffer.toString('base64'); - const mediaUri = `data:text/javascript;base64,${base64}`; - $(scriptEl).attr('src', mediaUri); - } - - for (let linkEl of internalLinks) { - const linkPath = path.resolve('/', filePath, linkEl.attribs.href); - const linkBuffer = await readFilePromise(linkPath, null); - const base64 = linkBuffer.toString('base64'); - const mediaUri = `data:text/css;base64,${base64}`; - $(linkEl).attr('href', mediaUri); - } - - return $.html(); -} - - - - -function readFilePromise(filePath, encoding = 'utf8') { - return new Promise((resolve, reject) => { - readFile(path.resolve(process.cwd(), './' + filePath), encoding, (err, content) => { - if (err) reject(err); - else resolve(content); - }); - }); -} - -function writeFilePromise(filePath, encoding = 'utf8') { - return new Promise((resolve, reject) => { - writeFile(path.resolve(process.cwd(), './' + filePath), encoding, (err, content) => { - if (err) reject(err); - else resolve(content); - }); - }); -} - -function readDirPromise(dirPath) { - return new Promise((resolve, reject) => { - readdir(path.resolve(process.cwd(), dirPath), (err, files) => { - if (err) reject(err); - else resolve(files); - }); - }); -} \ No newline at end of file diff --git a/.operations/operations-manual.md b/.operations/operations-manual.md index ee932284d..1c7595099 100644 --- a/.operations/operations-manual.md +++ b/.operations/operations-manual.md @@ -8,7 +8,7 @@ In a nutshell, every issue and PR should get tagged by one of our core team and There is no specific person on call who assigns inquiries rather we count on our core team to visit almost everyday and assign issues/PR - this way, the workflow is not depend upon any specific person rather on our entire team. -Any new content should conform to our [writing guidelines](https://github.com/goldbergyoni/nodebestpractices/blob/master/.operations/writing-guidelines.md) +Any new content should conform to our [writing guidelines](./writing-guidelines.md) ## Monthly maintenance diff --git a/.operations/out/.gitignore b/.operations/out/.gitignore deleted file mode 100644 index d6b7ef32c..000000000 --- a/.operations/out/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore diff --git a/.operations/res/github.css b/.operations/res/github.css deleted file mode 100644 index 791932b87..000000000 --- a/.operations/res/github.css +++ /dev/null @@ -1,99 +0,0 @@ -/* - -github.com style (c) Vasily Polovnyov - -*/ - -.hljs { - display: block; - overflow-x: auto; - padding: 0.5em; - color: #333; - background: #f8f8f8; -} - -.hljs-comment, -.hljs-quote { - color: #998; - font-style: italic; -} - -.hljs-keyword, -.hljs-selector-tag, -.hljs-subst { - color: #333; - font-weight: bold; -} - -.hljs-number, -.hljs-literal, -.hljs-variable, -.hljs-template-variable, -.hljs-tag .hljs-attr { - color: #008080; -} - -.hljs-string, -.hljs-doctag { - color: #d14; -} - -.hljs-title, -.hljs-section, -.hljs-selector-id { - color: #900; - font-weight: bold; -} - -.hljs-subst { - font-weight: normal; -} - -.hljs-type, -.hljs-class .hljs-title { - color: #458; - font-weight: bold; -} - -.hljs-tag, -.hljs-name, -.hljs-attribute { - color: #000080; - font-weight: normal; -} - -.hljs-regexp, -.hljs-link { - color: #009926; -} - -.hljs-symbol, -.hljs-bullet { - color: #990073; -} - -.hljs-built_in, -.hljs-builtin-name { - color: #0086b3; -} - -.hljs-meta { - color: #999; - font-weight: bold; -} - -.hljs-deletion { - background: #fdd; -} - -.hljs-addition { - background: #dfd; -} - -.hljs-emphasis { - font-style: italic; -} - -.hljs-strong { - font-weight: bold; -} diff --git a/.operations/res/highlight.pack.js b/.operations/res/highlight.pack.js deleted file mode 100644 index b64bd7d80..000000000 --- a/.operations/res/highlight.pack.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! highlight.js v9.13.1 | BSD3 License | git.io/hljslicense */ -!function(e){var n="object"==typeof window&&window||"object"==typeof self&&self;"undefined"!=typeof exports?e(exports):n&&(n.hljs=e({}),"function"==typeof define&&define.amd&&define([],function(){return n.hljs}))}(function(e){function n(e){return e.replace(/&/g,"&").replace(//g,">")}function t(e){return e.nodeName.toLowerCase()}function r(e,n){var t=e&&e.exec(n);return t&&0===t.index}function a(e){return k.test(e)}function i(e){var n,t,r,i,o=e.className+" ";if(o+=e.parentNode?e.parentNode.className:"",t=M.exec(o))return w(t[1])?t[1]:"no-highlight";for(o=o.split(/\s+/),n=0,r=o.length;r>n;n++)if(i=o[n],a(i)||w(i))return i}function o(e){var n,t={},r=Array.prototype.slice.call(arguments,1);for(n in e)t[n]=e[n];return r.forEach(function(e){for(n in e)t[n]=e[n]}),t}function c(e){var n=[];return function r(e,a){for(var i=e.firstChild;i;i=i.nextSibling)3===i.nodeType?a+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=r(i,a),t(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n}function u(e,r,a){function i(){return e.length&&r.length?e[0].offset!==r[0].offset?e[0].offset"}function c(e){l+=""}function u(e){("start"===e.event?o:c)(e.node)}for(var s=0,l="",f=[];e.length||r.length;){var g=i();if(l+=n(a.substring(s,g[0].offset)),s=g[0].offset,g===e){f.reverse().forEach(c);do u(g.splice(0,1)[0]),g=i();while(g===e&&g.length&&g[0].offset===s);f.reverse().forEach(o)}else"start"===g[0].event?f.push(g[0].node):f.pop(),u(g.splice(0,1)[0])}return l+n(a.substr(s))}function s(e){return e.v&&!e.cached_variants&&(e.cached_variants=e.v.map(function(n){return o(e,{v:null},n)})),e.cached_variants||e.eW&&[o(e)]||[e]}function l(e){function n(e){return e&&e.source||e}function t(t,r){return new RegExp(n(t),"m"+(e.cI?"i":"")+(r?"g":""))}function r(a,i){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var o={},c=function(n,t){e.cI&&(t=t.toLowerCase()),t.split(" ").forEach(function(e){var t=e.split("|");o[t[0]]=[n,t[1]?Number(t[1]):1]})};"string"==typeof a.k?c("keyword",a.k):B(a.k).forEach(function(e){c(e,a.k[e])}),a.k=o}a.lR=t(a.l||/\w+/,!0),i&&(a.bK&&(a.b="\\b("+a.bK.split(" ").join("|")+")\\b"),a.b||(a.b=/\B|\b/),a.bR=t(a.b),a.endSameAsBegin&&(a.e=a.b),a.e||a.eW||(a.e=/\B|\b/),a.e&&(a.eR=t(a.e)),a.tE=n(a.e)||"",a.eW&&i.tE&&(a.tE+=(a.e?"|":"")+i.tE)),a.i&&(a.iR=t(a.i)),null==a.r&&(a.r=1),a.c||(a.c=[]),a.c=Array.prototype.concat.apply([],a.c.map(function(e){return s("self"===e?a:e)})),a.c.forEach(function(e){r(e,a)}),a.starts&&r(a.starts,i);var u=a.c.map(function(e){return e.bK?"\\.?("+e.b+")\\.?":e.b}).concat([a.tE,a.i]).map(n).filter(Boolean);a.t=u.length?t(u.join("|"),!0):{exec:function(){return null}}}}r(e)}function f(e,t,a,i){function o(e){return new RegExp(e.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&"),"m")}function c(e,n){var t,a;for(t=0,a=n.c.length;a>t;t++)if(r(n.c[t].bR,e))return n.c[t].endSameAsBegin&&(n.c[t].eR=o(n.c[t].bR.exec(e)[0])),n.c[t]}function u(e,n){if(r(e.eR,n)){for(;e.endsParent&&e.parent;)e=e.parent;return e}return e.eW?u(e.parent,n):void 0}function s(e,n){return!a&&r(n.iR,e)}function p(e,n){var t=R.cI?n[0].toLowerCase():n[0];return e.k.hasOwnProperty(t)&&e.k[t]}function d(e,n,t,r){var a=r?"":j.classPrefix,i='',i+n+o}function h(){var e,t,r,a;if(!E.k)return n(k);for(a="",t=0,E.lR.lastIndex=0,r=E.lR.exec(k);r;)a+=n(k.substring(t,r.index)),e=p(E,r),e?(M+=e[1],a+=d(e[0],n(r[0]))):a+=n(r[0]),t=E.lR.lastIndex,r=E.lR.exec(k);return a+n(k.substr(t))}function b(){var e="string"==typeof E.sL;if(e&&!L[E.sL])return n(k);var t=e?f(E.sL,k,!0,B[E.sL]):g(k,E.sL.length?E.sL:void 0);return E.r>0&&(M+=t.r),e&&(B[E.sL]=t.top),d(t.language,t.value,!1,!0)}function v(){y+=null!=E.sL?b():h(),k=""}function m(e){y+=e.cN?d(e.cN,"",!0):"",E=Object.create(e,{parent:{value:E}})}function N(e,n){if(k+=e,null==n)return v(),0;var t=c(n,E);if(t)return t.skip?k+=n:(t.eB&&(k+=n),v(),t.rB||t.eB||(k=n)),m(t,n),t.rB?0:n.length;var r=u(E,n);if(r){var a=E;a.skip?k+=n:(a.rE||a.eE||(k+=n),v(),a.eE&&(k=n));do E.cN&&(y+=I),E.skip||E.sL||(M+=E.r),E=E.parent;while(E!==r.parent);return r.starts&&(r.endSameAsBegin&&(r.starts.eR=r.eR),m(r.starts,"")),a.rE?0:n.length}if(s(n,E))throw new Error('Illegal lexeme "'+n+'" for mode "'+(E.cN||"")+'"');return k+=n,n.length||1}var R=w(e);if(!R)throw new Error('Unknown language: "'+e+'"');l(R);var x,E=i||R,B={},y="";for(x=E;x!==R;x=x.parent)x.cN&&(y=d(x.cN,"",!0)+y);var k="",M=0;try{for(var C,A,S=0;;){if(E.t.lastIndex=S,C=E.t.exec(t),!C)break;A=N(t.substring(S,C.index),C[0]),S=C.index+A}for(N(t.substr(S)),x=E;x.parent;x=x.parent)x.cN&&(y+=I);return{r:M,value:y,language:e,top:E}}catch(O){if(O.message&&-1!==O.message.indexOf("Illegal"))return{r:0,value:n(t)};throw O}}function g(e,t){t=t||j.languages||B(L);var r={r:0,value:n(e)},a=r;return t.filter(w).filter(x).forEach(function(n){var t=f(n,e,!1);t.language=n,t.r>a.r&&(a=t),t.r>r.r&&(a=r,r=t)}),a.language&&(r.second_best=a),r}function p(e){return j.tabReplace||j.useBR?e.replace(C,function(e,n){return j.useBR&&"\n"===e?"
":j.tabReplace?n.replace(/\t/g,j.tabReplace):""}):e}function d(e,n,t){var r=n?y[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),-1===e.indexOf(r)&&a.push(r),a.join(" ").trim()}function h(e){var n,t,r,o,s,l=i(e);a(l)||(j.useBR?(n=document.createElementNS("http://www.w3.org/1999/xhtml","div"),n.innerHTML=e.innerHTML.replace(/\n/g,"").replace(//g,"\n")):n=e,s=n.textContent,r=l?f(l,s,!0):g(s),t=c(n),t.length&&(o=document.createElementNS("http://www.w3.org/1999/xhtml","div"),o.innerHTML=r.value,r.value=u(t,c(o),s)),r.value=p(r.value),e.innerHTML=r.value,e.className=d(e.className,l,r.language),e.result={language:r.language,re:r.r},r.second_best&&(e.second_best={language:r.second_best.language,re:r.second_best.r}))}function b(e){j=o(j,e)}function v(){if(!v.called){v.called=!0;var e=document.querySelectorAll("pre code");E.forEach.call(e,h)}}function m(){addEventListener("DOMContentLoaded",v,!1),addEventListener("load",v,!1)}function N(n,t){var r=L[n]=t(e);r.aliases&&r.aliases.forEach(function(e){y[e]=n})}function R(){return B(L)}function w(e){return e=(e||"").toLowerCase(),L[e]||L[y[e]]}function x(e){var n=w(e);return n&&!n.disableAutodetect}var E=[],B=Object.keys,L={},y={},k=/^(no-?highlight|plain|text)$/i,M=/\blang(?:uage)?-([\w-]+)\b/i,C=/((^(<[^>]+>|\t|)+|(?:\n)))/gm,I="
",j={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0};return e.highlight=f,e.highlightAuto=g,e.fixMarkup=p,e.highlightBlock=h,e.configure=b,e.initHighlighting=v,e.initHighlightingOnLoad=m,e.registerLanguage=N,e.listLanguages=R,e.getLanguage=w,e.autoDetection=x,e.inherit=o,e.IR="[a-zA-Z]\\w*",e.UIR="[a-zA-Z_]\\w*",e.NR="\\b\\d+(\\.\\d+)?",e.CNR="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BNR="\\b(0b[01]+)",e.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BE={b:"\\\\[\\s\\S]",r:0},e.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[e.BE]},e.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[e.BE]},e.PWM={b:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},e.C=function(n,t,r){var a=e.inherit({cN:"comment",b:n,e:t,c:[]},r||{});return a.c.push(e.PWM),a.c.push({cN:"doctag",b:"(?:TODO|FIXME|NOTE|BUG|XXX):",r:0}),a},e.CLCM=e.C("//","$"),e.CBCM=e.C("/\\*","\\*/"),e.HCM=e.C("#","$"),e.NM={cN:"number",b:e.NR,r:0},e.CNM={cN:"number",b:e.CNR,r:0},e.BNM={cN:"number",b:e.BNR,r:0},e.CSSNM={cN:"number",b:e.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},e.RM={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[e.BE,{b:/\[/,e:/\]/,r:0,c:[e.BE]}]},e.TM={cN:"title",b:e.IR,r:0},e.UTM={cN:"title",b:e.UIR,r:0},e.METHOD_GUARD={b:"\\.\\s*"+e.UIR,r:0},e});hljs.registerLanguage("xml",function(s){var e="[A-Za-z0-9\\._:-]+",t={eW:!0,i:/`]+/}]}]}]};return{aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist"],cI:!0,c:[{cN:"meta",b:"",r:10,c:[{b:"\\[",e:"\\]"}]},s.C("",{r:10}),{b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"meta",b:/<\?xml/,e:/\?>/,r:10},{b:/<\?(php)?/,e:/\?>/,sL:"php",c:[{b:"/\\*",e:"\\*/",skip:!0},{b:'b"',e:'"',skip:!0},{b:"b'",e:"'",skip:!0},s.inherit(s.ASM,{i:null,cN:null,c:null,skip:!0}),s.inherit(s.QSM,{i:null,cN:null,c:null,skip:!0})]},{cN:"tag",b:"|$)",e:">",k:{name:"style"},c:[t],starts:{e:"",rE:!0,sL:["css","xml"]}},{cN:"tag",b:"|$)",e:">",k:{name:"script"},c:[t],starts:{e:"",rE:!0,sL:["actionscript","javascript","handlebars","xml"]}},{cN:"tag",b:"",c:[{cN:"name",b:/[^\/><\s]+/,r:0},t]}]}});hljs.registerLanguage("nginx",function(e){var r={cN:"variable",v:[{b:/\$\d+/},{b:/\$\{/,e:/}/},{b:"[\\$\\@]"+e.UIR}]},b={eW:!0,l:"[a-z/_]+",k:{literal:"on off yes no true false none blocked debug info notice warn error crit select break last permanent redirect kqueue rtsig epoll poll /dev/poll"},r:0,i:"=>",c:[e.HCM,{cN:"string",c:[e.BE,r],v:[{b:/"/,e:/"/},{b:/'/,e:/'/}]},{b:"([a-z]+):/",e:"\\s",eW:!0,eE:!0,c:[r]},{cN:"regexp",c:[e.BE,r],v:[{b:"\\s\\^",e:"\\s|{|;",rE:!0},{b:"~\\*?\\s+",e:"\\s|{|;",rE:!0},{b:"\\*(\\.[a-z\\-]+)+"},{b:"([a-z\\-]+\\.)+\\*"}]},{cN:"number",b:"\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?\\b"},{cN:"number",b:"\\b\\d+[kKmMgGdshdwy]*\\b",r:0},r]};return{aliases:["nginxconf"],c:[e.HCM,{b:e.UIR+"\\s+{",rB:!0,e:"{",c:[{cN:"section",b:e.UIR}],r:0},{b:e.UIR+"\\s",e:";|{",rB:!0,c:[{cN:"attribute",b:e.UIR,starts:b}],r:0}],i:"[^\\s\\}]"}});hljs.registerLanguage("json",function(e){var i={literal:"true false null"},n=[e.QSM,e.CNM],r={e:",",eW:!0,eE:!0,c:n,k:i},t={b:"{",e:"}",c:[{cN:"attr",b:/"/,e:/"/,c:[e.BE],i:"\\n"},e.inherit(r,{b:/:/})],i:"\\S"},c={b:"\\[",e:"\\]",c:[e.inherit(r)],i:"\\S"};return n.splice(n.length,0,t,c),{c:n,k:i,i:"\\S"}});hljs.registerLanguage("javascript",function(e){var r="[A-Za-z$_][0-9A-Za-z$_]*",t={keyword:"in of if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const export super debugger as async await static import from as",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Promise"},a={cN:"number",v:[{b:"\\b(0[bB][01]+)"},{b:"\\b(0[oO][0-7]+)"},{b:e.CNR}],r:0},n={cN:"subst",b:"\\$\\{",e:"\\}",k:t,c:[]},c={cN:"string",b:"`",e:"`",c:[e.BE,n]};n.c=[e.ASM,e.QSM,c,a,e.RM];var s=n.c.concat([e.CBCM,e.CLCM]);return{aliases:["js","jsx"],k:t,c:[{cN:"meta",r:10,b:/^\s*['"]use (strict|asm)['"]/},{cN:"meta",b:/^#!/,e:/$/},e.ASM,e.QSM,c,e.CLCM,e.CBCM,a,{b:/[{,]\s*/,r:0,c:[{b:r+"\\s*:",rB:!0,r:0,c:[{cN:"attr",b:r,r:0}]}]},{b:"("+e.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[e.CLCM,e.CBCM,e.RM,{cN:"function",b:"(\\(.*?\\)|"+r+")\\s*=>",rB:!0,e:"\\s*=>",c:[{cN:"params",v:[{b:r},{b:/\(\s*\)/},{b:/\(/,e:/\)/,eB:!0,eE:!0,k:t,c:s}]}]},{b://,sL:"xml",c:[{b:/<\w+\s*\/>/,skip:!0},{b:/<\w+/,e:/(\/\w+|\w+\/)>/,skip:!0,c:[{b:/<\w+\s*\/>/,skip:!0},"self"]}]}],r:0},{cN:"function",bK:"function",e:/\{/,eE:!0,c:[e.inherit(e.TM,{b:r}),{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,c:s}],i:/\[|%/},{b:/\$[(.]/},e.METHOD_GUARD,{cN:"class",bK:"class",e:/[{;=]/,eE:!0,i:/[:"\[\]]/,c:[{bK:"extends"},e.UTM]},{bK:"constructor",e:/\{/,eE:!0}],i:/#(?!!)/}}); \ No newline at end of file diff --git a/.operations/res/normalize.css b/.operations/res/normalize.css deleted file mode 100644 index 81c6f31ea..000000000 --- a/.operations/res/normalize.css +++ /dev/null @@ -1,427 +0,0 @@ -/*! normalize.css v3.0.2 | MIT License | git.io/normalize */ - -/** - * 1. Set default font family to sans-serif. - * 2. Prevent iOS text size adjust after orientation change, without disabling - * user zoom. - */ - -html { - font-family: sans-serif; /* 1 */ - -ms-text-size-adjust: 100%; /* 2 */ - -webkit-text-size-adjust: 100%; /* 2 */ -} - -/** - * Remove default margin. - */ - -body { - margin: 0; -} - -/* HTML5 display definitions - ========================================================================== */ - -/** - * Correct `block` display not defined for any HTML5 element in IE 8/9. - * Correct `block` display not defined for `details` or `summary` in IE 10/11 - * and Firefox. - * Correct `block` display not defined for `main` in IE 11. - */ - -article, -aside, -details, -figcaption, -figure, -footer, -header, -hgroup, -main, -menu, -nav, -section, -summary { - display: block; -} - -/** - * 1. Correct `inline-block` display not defined in IE 8/9. - * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. - */ - -audio, -canvas, -progress, -video { - display: inline-block; /* 1 */ - vertical-align: baseline; /* 2 */ -} - -/** - * Prevent modern browsers from displaying `audio` without controls. - * Remove excess height in iOS 5 devices. - */ - -audio:not([controls]) { - display: none; - height: 0; -} - -/** - * Address `[hidden]` styling not present in IE 8/9/10. - * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. - */ - -[hidden], -template { - display: none; -} - -/* Links - ========================================================================== */ - -/** - * Remove the gray background color from active links in IE 10. - */ - -a { - background-color: transparent; -} - -/** - * Improve readability when focused and also mouse hovered in all browsers. - */ - -a:active, -a:hover { - outline: 0; -} - -/* Text-level semantics - ========================================================================== */ - -/** - * Address styling not present in IE 8/9/10/11, Safari, and Chrome. - */ - -abbr[title] { - border-bottom: 1px dotted; -} - -/** - * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. - */ - -b, -strong { - font-weight: bold; -} - -/** - * Address styling not present in Safari and Chrome. - */ - -dfn { - font-style: italic; -} - -/** - * Address variable `h1` font-size and margin within `section` and `article` - * contexts in Firefox 4+, Safari, and Chrome. - */ - -h1 { - font-size: 2em; - margin: 0.67em 0; -} - -/** - * Address styling not present in IE 8/9. - */ - -mark { - background: #ff0; - color: #000; -} - -/** - * Address inconsistent and variable font size in all browsers. - */ - -small { - font-size: 80%; -} - -/** - * Prevent `sub` and `sup` affecting `line-height` in all browsers. - */ - -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sup { - top: -0.5em; -} - -sub { - bottom: -0.25em; -} - -/* Embedded content - ========================================================================== */ - -/** - * Remove border when inside `a` element in IE 8/9/10. - */ - -img { - border: 0; -} - -/** - * Correct overflow not hidden in IE 9/10/11. - */ - -svg:not(:root) { - overflow: hidden; -} - -/* Grouping content - ========================================================================== */ - -/** - * Address margin not present in IE 8/9 and Safari. - */ - -figure { - margin: 1em 40px; -} - -/** - * Address differences between Firefox and other browsers. - */ - -hr { - -moz-box-sizing: content-box; - box-sizing: content-box; - height: 0; -} - -/** - * Contain overflow in all browsers. - */ - -pre { - overflow: auto; -} - -/** - * Address odd `em`-unit font size rendering in all browsers. - */ - -code, -kbd, -pre, -samp { - font-family: monospace, monospace; - font-size: 1em; -} - -/* Forms - ========================================================================== */ - -/** - * Known limitation: by default, Chrome and Safari on OS X allow very limited - * styling of `select`, unless a `border` property is set. - */ - -/** - * 1. Correct color not being inherited. - * Known issue: affects color of disabled elements. - * 2. Correct font properties not being inherited. - * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. - */ - -button, -input, -optgroup, -select, -textarea { - color: inherit; /* 1 */ - font: inherit; /* 2 */ - margin: 0; /* 3 */ -} - -/** - * Address `overflow` set to `hidden` in IE 8/9/10/11. - */ - -button { - overflow: visible; -} - -/** - * Address inconsistent `text-transform` inheritance for `button` and `select`. - * All other form control elements do not inherit `text-transform` values. - * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. - * Correct `select` style inheritance in Firefox. - */ - -button, -select { - text-transform: none; -} - -/** - * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` - * and `video` controls. - * 2. Correct inability to style clickable `input` types in iOS. - * 3. Improve usability and consistency of cursor style between image-type - * `input` and others. - */ - -button, -html input[type="button"], /* 1 */ -input[type="reset"], -input[type="submit"] { - -webkit-appearance: button; /* 2 */ - cursor: pointer; /* 3 */ -} - -/** - * Re-set default cursor for disabled elements. - */ - -button[disabled], -html input[disabled] { - cursor: default; -} - -/** - * Remove inner padding and border in Firefox 4+. - */ - -button::-moz-focus-inner, -input::-moz-focus-inner { - border: 0; - padding: 0; -} - -/** - * Address Firefox 4+ setting `line-height` on `input` using `!important` in - * the UA stylesheet. - */ - -input { - line-height: normal; -} - -/** - * It's recommended that you don't attempt to style these elements. - * Firefox's implementation doesn't respect box-sizing, padding, or width. - * - * 1. Address box sizing set to `content-box` in IE 8/9/10. - * 2. Remove excess padding in IE 8/9/10. - */ - -input[type="checkbox"], -input[type="radio"] { - box-sizing: border-box; /* 1 */ - padding: 0; /* 2 */ -} - -/** - * Fix the cursor style for Chrome's increment/decrement buttons. For certain - * `font-size` values of the `input`, it causes the cursor style of the - * decrement button to change from `default` to `text`. - */ - -input[type="number"]::-webkit-inner-spin-button, -input[type="number"]::-webkit-outer-spin-button { - height: auto; -} - -/** - * 1. Address `appearance` set to `searchfield` in Safari and Chrome. - * 2. Address `box-sizing` set to `border-box` in Safari and Chrome - * (include `-moz` to future-proof). - */ - -input[type="search"] { - -webkit-appearance: textfield; /* 1 */ - -moz-box-sizing: content-box; - -webkit-box-sizing: content-box; /* 2 */ - box-sizing: content-box; -} - -/** - * Remove inner padding and search cancel button in Safari and Chrome on OS X. - * Safari (but not Chrome) clips the cancel button when the search input has - * padding (and `textfield` appearance). - */ - -input[type="search"]::-webkit-search-cancel-button, -input[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; -} - -/** - * Define consistent border, margin, and padding. - */ - -fieldset { - border: 1px solid #c0c0c0; - margin: 0 2px; - padding: 0.35em 0.625em 0.75em; -} - -/** - * 1. Correct `color` not being inherited in IE 8/9/10/11. - * 2. Remove padding so people aren't caught out if they zero out fieldsets. - */ - -legend { - border: 0; /* 1 */ - padding: 0; /* 2 */ -} - -/** - * Remove default vertical scrollbar in IE 8/9/10/11. - */ - -textarea { - overflow: auto; -} - -/** - * Don't inherit the `font-weight` (applied by a rule above). - * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. - */ - -optgroup { - font-weight: bold; -} - -/* Tables - ========================================================================== */ - -/** - * Remove most spacing between table cells. - */ - -table { - border-collapse: collapse; - border-spacing: 0; -} - -td, -th { - padding: 0; -} \ No newline at end of file diff --git a/.operations/res/skeleton.css b/.operations/res/skeleton.css deleted file mode 100644 index f28bf6c59..000000000 --- a/.operations/res/skeleton.css +++ /dev/null @@ -1,418 +0,0 @@ -/* -* Skeleton V2.0.4 -* Copyright 2014, Dave Gamache -* www.getskeleton.com -* Free to use under the MIT license. -* http://www.opensource.org/licenses/mit-license.php -* 12/29/2014 -*/ - - -/* Table of contents -–––––––––––––––––––––––––––––––––––––––––––––––––– -- Grid -- Base Styles -- Typography -- Links -- Buttons -- Forms -- Lists -- Code -- Tables -- Spacing -- Utilities -- Clearing -- Media Queries -*/ - - -/* Grid -–––––––––––––––––––––––––––––––––––––––––––––––––– */ -.container { - position: relative; - width: 100%; - max-width: 960px; - margin: 0 auto; - padding: 0 20px; - box-sizing: border-box; } -.column, -.columns { - width: 100%; - float: left; - box-sizing: border-box; } - -/* For devices larger than 400px */ -@media (min-width: 400px) { - .container { - width: 85%; - padding: 0; } -} - -/* For devices larger than 550px */ -@media (min-width: 550px) { - .container { - width: 80%; } - .column, - .columns { - margin-left: 4%; } - .column:first-child, - .columns:first-child { - margin-left: 0; } - - .one.column, - .one.columns { width: 4.66666666667%; } - .two.columns { width: 13.3333333333%; } - .three.columns { width: 22%; } - .four.columns { width: 30.6666666667%; } - .five.columns { width: 39.3333333333%; } - .six.columns { width: 48%; } - .seven.columns { width: 56.6666666667%; } - .eight.columns { width: 65.3333333333%; } - .nine.columns { width: 74.0%; } - .ten.columns { width: 82.6666666667%; } - .eleven.columns { width: 91.3333333333%; } - .twelve.columns { width: 100%; margin-left: 0; } - - .one-third.column { width: 30.6666666667%; } - .two-thirds.column { width: 65.3333333333%; } - - .one-half.column { width: 48%; } - - /* Offsets */ - .offset-by-one.column, - .offset-by-one.columns { margin-left: 8.66666666667%; } - .offset-by-two.column, - .offset-by-two.columns { margin-left: 17.3333333333%; } - .offset-by-three.column, - .offset-by-three.columns { margin-left: 26%; } - .offset-by-four.column, - .offset-by-four.columns { margin-left: 34.6666666667%; } - .offset-by-five.column, - .offset-by-five.columns { margin-left: 43.3333333333%; } - .offset-by-six.column, - .offset-by-six.columns { margin-left: 52%; } - .offset-by-seven.column, - .offset-by-seven.columns { margin-left: 60.6666666667%; } - .offset-by-eight.column, - .offset-by-eight.columns { margin-left: 69.3333333333%; } - .offset-by-nine.column, - .offset-by-nine.columns { margin-left: 78.0%; } - .offset-by-ten.column, - .offset-by-ten.columns { margin-left: 86.6666666667%; } - .offset-by-eleven.column, - .offset-by-eleven.columns { margin-left: 95.3333333333%; } - - .offset-by-one-third.column, - .offset-by-one-third.columns { margin-left: 34.6666666667%; } - .offset-by-two-thirds.column, - .offset-by-two-thirds.columns { margin-left: 69.3333333333%; } - - .offset-by-one-half.column, - .offset-by-one-half.columns { margin-left: 52%; } - -} - - -/* Base Styles -–––––––––––––––––––––––––––––––––––––––––––––––––– */ -/* NOTE -html is set to 62.5% so that all the REM measurements throughout Skeleton -are based on 10px sizing. So basically 1.5rem = 15px :) */ -html { - font-size: 62.5%; } -body { - font-size: 1.5em; /* currently ems cause chrome bug misinterpreting rems on body element */ - line-height: 1.6; - font-weight: 400; - font-family: "Raleway", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif; - color: #222; } - - -/* Typography -–––––––––––––––––––––––––––––––––––––––––––––––––– */ -h1, h2, h3, h4, h5, h6 { - margin-top: 0; - margin-bottom: 2rem; - font-weight: 300; } -h1 { font-size: 4.0rem; line-height: 1.2; letter-spacing: -.1rem;} -h2 { font-size: 3.6rem; line-height: 1.25; letter-spacing: -.1rem; } -h3 { font-size: 3.0rem; line-height: 1.3; letter-spacing: -.1rem; } -h4 { font-size: 2.4rem; line-height: 1.35; letter-spacing: -.08rem; } -h5 { font-size: 1.8rem; line-height: 1.5; letter-spacing: -.05rem; } -h6 { font-size: 1.5rem; line-height: 1.6; letter-spacing: 0; } - -/* Larger than phablet */ -@media (min-width: 550px) { - h1 { font-size: 5.0rem; } - h2 { font-size: 4.2rem; } - h3 { font-size: 3.6rem; } - h4 { font-size: 3.0rem; } - h5 { font-size: 2.4rem; } - h6 { font-size: 1.5rem; } -} - -p { - margin-top: 0; } - - -/* Links -–––––––––––––––––––––––––––––––––––––––––––––––––– */ -a { - color: #1EAEDB; } -a:hover { - color: #0FA0CE; } - - -/* Buttons -–––––––––––––––––––––––––––––––––––––––––––––––––– */ -.button, -button, -input[type="submit"], -input[type="reset"], -input[type="button"] { - display: inline-block; - height: 38px; - padding: 0 30px; - color: #555; - text-align: center; - font-size: 11px; - font-weight: 600; - line-height: 38px; - letter-spacing: .1rem; - text-transform: uppercase; - text-decoration: none; - white-space: nowrap; - background-color: transparent; - border-radius: 4px; - border: 1px solid #bbb; - cursor: pointer; - box-sizing: border-box; } -.button:hover, -button:hover, -input[type="submit"]:hover, -input[type="reset"]:hover, -input[type="button"]:hover, -.button:focus, -button:focus, -input[type="submit"]:focus, -input[type="reset"]:focus, -input[type="button"]:focus { - color: #333; - border-color: #888; - outline: 0; } -.button.button-primary, -button.button-primary, -input[type="submit"].button-primary, -input[type="reset"].button-primary, -input[type="button"].button-primary { - color: #FFF; - background-color: #33C3F0; - border-color: #33C3F0; } -.button.button-primary:hover, -button.button-primary:hover, -input[type="submit"].button-primary:hover, -input[type="reset"].button-primary:hover, -input[type="button"].button-primary:hover, -.button.button-primary:focus, -button.button-primary:focus, -input[type="submit"].button-primary:focus, -input[type="reset"].button-primary:focus, -input[type="button"].button-primary:focus { - color: #FFF; - background-color: #1EAEDB; - border-color: #1EAEDB; } - - -/* Forms -–––––––––––––––––––––––––––––––––––––––––––––––––– */ -input[type="email"], -input[type="number"], -input[type="search"], -input[type="text"], -input[type="tel"], -input[type="url"], -input[type="password"], -textarea, -select { - height: 38px; - padding: 6px 10px; /* The 6px vertically centers text on FF, ignored by Webkit */ - background-color: #fff; - border: 1px solid #D1D1D1; - border-radius: 4px; - box-shadow: none; - box-sizing: border-box; } -/* Removes awkward default styles on some inputs for iOS */ -input[type="email"], -input[type="number"], -input[type="search"], -input[type="text"], -input[type="tel"], -input[type="url"], -input[type="password"], -textarea { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; } -textarea { - min-height: 65px; - padding-top: 6px; - padding-bottom: 6px; } -input[type="email"]:focus, -input[type="number"]:focus, -input[type="search"]:focus, -input[type="text"]:focus, -input[type="tel"]:focus, -input[type="url"]:focus, -input[type="password"]:focus, -textarea:focus, -select:focus { - border: 1px solid #33C3F0; - outline: 0; } -label, -legend { - display: block; - margin-bottom: .5rem; - font-weight: 600; } -fieldset { - padding: 0; - border-width: 0; } -input[type="checkbox"], -input[type="radio"] { - display: inline; } -label > .label-body { - display: inline-block; - margin-left: .5rem; - font-weight: normal; } - - -/* Lists -–––––––––––––––––––––––––––––––––––––––––––––––––– */ -ul { - list-style: circle inside; } -ol { - list-style: decimal inside; } -ol, ul { - padding-left: 0; - margin-top: 0; } -ul ul, -ul ol, -ol ol, -ol ul { - margin: 1.5rem 0 1.5rem 3rem; - font-size: 90%; } -li { - margin-bottom: 1rem; } - - -/* Code -–––––––––––––––––––––––––––––––––––––––––––––––––– */ -code { - padding: .2rem .5rem; - margin: 0 .2rem; - font-size: 90%; - white-space: nowrap; - background: #F1F1F1; - border: 1px solid #E1E1E1; - border-radius: 4px; } -pre > code { - display: block; - padding: 1rem 1.5rem; - white-space: pre; } - - -/* Tables -–––––––––––––––––––––––––––––––––––––––––––––––––– */ -th, -td { - padding: 12px 15px; - text-align: left; - border-bottom: 1px solid #E1E1E1; } -th:first-child, -td:first-child { - padding-left: 0; } -th:last-child, -td:last-child { - padding-right: 0; } - - -/* Spacing -–––––––––––––––––––––––––––––––––––––––––––––––––– */ -button, -.button { - margin-bottom: 1rem; } -input, -textarea, -select, -fieldset { - margin-bottom: 1.5rem; } -pre, -blockquote, -dl, -figure, -table, -p, -ul, -ol, -form { - margin-bottom: 2.5rem; } - - -/* Utilities -–––––––––––––––––––––––––––––––––––––––––––––––––– */ -.u-full-width { - width: 100%; - box-sizing: border-box; } -.u-max-full-width { - max-width: 100%; - box-sizing: border-box; } -.u-pull-right { - float: right; } -.u-pull-left { - float: left; } - - -/* Misc -–––––––––––––––––––––––––––––––––––––––––––––––––– */ -hr { - margin-top: 3rem; - margin-bottom: 3.5rem; - border-width: 0; - border-top: 1px solid #E1E1E1; } - - -/* Clearing -–––––––––––––––––––––––––––––––––––––––––––––––––– */ - -/* Self Clearing Goodness */ -.container:after, -.row:after, -.u-cf { - content: ""; - display: table; - clear: both; } - - -/* Media Queries -–––––––––––––––––––––––––––––––––––––––––––––––––– */ -/* -Note: The best way to structure the use of media queries is to create the queries -near the relevant code. For example, if you wanted to change the styles for buttons -on small devices, paste the mobile query code up in the buttons section and style it -there. -*/ - - -/* Larger than mobile */ -@media (min-width: 400px) {} - -/* Larger than phablet (also point when grid becomes active) */ -@media (min-width: 550px) {} - -/* Larger than tablet */ -@media (min-width: 750px) {} - -/* Larger than desktop */ -@media (min-width: 1000px) {} - -/* Larger than Desktop HD */ -@media (min-width: 1200px) {} diff --git a/.operations/res/template.html b/.operations/res/template.html deleted file mode 100644 index 735d4f393..000000000 --- a/.operations/res/template.html +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - Node Best Practices - - - - - - -
-
-
-
- - - - - - - - - \ No newline at end of file diff --git a/.operations/writing-guidelines.chinese.md b/.operations/writing-guidelines.chinese.md index 695658988..97629cc69 100644 --- a/.operations/writing-guidelines.chinese.md +++ b/.operations/writing-guidelines.chinese.md @@ -16,7 +16,7 @@ ## 4. 一致的格式 -内容是使用固定模板显示的。任何新的内容都必须遵守这一模板。如果希望添加新项目符号,请从现有项目符号复制项目符号格式,并将其扩展以满足您的需要。有关其他信息,请查看[模版](https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/template.md) +内容是使用固定模板显示的。任何新的内容都必须遵守这一模板。如果希望添加新项目符号,请从现有项目符号复制项目符号格式,并将其扩展以满足您的需要。有关其他信息,请查看[模版](../sections/template.md) ## 5. Node.js 相关 diff --git a/.operations/writing-guidelines.french.md b/.operations/writing-guidelines.french.md index 663a82ee8..2e46f05e2 100644 --- a/.operations/writing-guidelines.french.md +++ b/.operations/writing-guidelines.french.md @@ -16,7 +16,7 @@ En plus d'être d'une grande fiabilité et d'une grande qualité rédactionnelle ## 4. Formatage cohérent -Le contenu est présenté à l'aide de modèles prédéfinis. Tout contenu futur doit être conforme au même modèle. Si vous souhaitez ajouter de nouveaux points, copiez le format d'un point existant et complétez-le selon vos besoins. Pour plus d'informations, veuillez consulter [ce modèle](https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/template.md). +Le contenu est présenté à l'aide de modèles prédéfinis. Tout contenu futur doit être conforme au même modèle. Si vous souhaitez ajouter de nouveaux points, copiez le format d'un point existant et complétez-le selon vos besoins. Pour plus d'informations, veuillez consulter [ce modèle](../sections/template.md). ## 5. C'est à propos de Node.js diff --git a/.operations/writing-guidelines.indonesia.md b/.operations/writing-guidelines.indonesia.md index 3b65f7580..d33359121 100644 --- a/.operations/writing-guidelines.indonesia.md +++ b/.operations/writing-guidelines.indonesia.md @@ -16,7 +16,7 @@ Selain konten yang sangat diedit dan dapat diandalkan, membaca sekilas konten ju ## 4. Pemformatan yang konsisten -Konten disajikan menggunakan templat tetap. Setiap konten di masa mendatang harus sesuai dengan template yang sama. Jika Anda ingin menambahkan poin baru, salin format poin dari poin yang ada dan kembangkan sesuai kebutuhan Anda. Untuk informasi tambahan, silakan lihat [template ini] (https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/template.md). +Konten disajikan menggunakan templat tetap. Setiap konten di masa mendatang harus sesuai dengan template yang sama. Jika Anda ingin menambahkan poin baru, salin format poin dari poin yang ada dan kembangkan sesuai kebutuhan Anda. Untuk informasi tambahan, silakan lihat [template ini] (/sections/template.md). ## 5. Ini Tentang Node.js @@ -28,4 +28,4 @@ Terkadang berguna untuk memasukkan nama vendor yang dapat mengatasi tantangan da - Hanya 3 vendor teratas yang disarankan - vendor yang muncul di 3 hasil teratas dari mesin pencari (Google atau GitHub diurutkan berdasarkan popularitas) untuk kata kunci relevan tertentu dapat dimasukkan dalam rekomendasi kami. - Jika ini adalah paket npm, itu juga harus diunduh setidaknya rata-rata 750 kali sehari. -- Jika ini adalah proyek sumber terbuka, itu harus diperbarui setidaknya sekali dalam 6 bulan terakhir. \ No newline at end of file +- Jika ini adalah proyek sumber terbuka, itu harus diperbarui setidaknya sekali dalam 6 bulan terakhir. diff --git a/.operations/writing-guidelines.japanese.md b/.operations/writing-guidelines.japanese.md index 155b6bafa..23cfc416a 100644 --- a/.operations/writing-guidelines.japanese.md +++ b/.operations/writing-guidelines.japanese.md @@ -16,7 +16,7 @@ Apart from the content being greatly edited and reliable, skimming through it sh ## 4. Consistent formatting -The content is presented using fixed templates. Any future content must conform to the same template. If you wish to add new bullets copy a bullet format from an existing bullet and extend it to your needs. For additional information please view [this template](https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/template.md). +The content is presented using fixed templates. Any future content must conform to the same template. If you wish to add new bullets copy a bullet format from an existing bullet and extend it to your needs. For additional information please view [this template](../sections/template.md). ## 5. It's About Node.js diff --git a/.operations/writing-guidelines.md b/.operations/writing-guidelines.md index daae6b9cf..3b5163a35 100644 --- a/.operations/writing-guidelines.md +++ b/.operations/writing-guidelines.md @@ -16,7 +16,7 @@ Apart from the content being greatly edited and reliable, skimming through it sh ## 4. Consistent formatting -The content is presented using fixed templates. Any future content must conform to the same template. If you wish to add new bullets copy a bullet format from an existing bullet and extend it to your needs. For additional information please view [this template](https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/template.md). +The content is presented using fixed templates. Any future content must conform to the same template. If you wish to add new bullets copy a bullet format from an existing bullet and extend it to your needs. For additional information please view [this template](../sections/template.md). ## 5. It's About Node.js diff --git a/.operations/writing-guidelines.polish.md b/.operations/writing-guidelines.polish.md index 471525ade..e7ad37f4b 100644 --- a/.operations/writing-guidelines.polish.md +++ b/.operations/writing-guidelines.polish.md @@ -16,7 +16,7 @@ Oprócz tego, że treść jest znacznie edytowana i niezawodna, przeglądanie w ## 4. Spójne formatowanie -Treść jest prezentowana przy użyciu stałych szablonów. Wszelkie przyszłe treści muszą być zgodne z tym samym szablonem. Jeśli chcesz dodać nowe punktory, skopiuj format punktora z istniejącego i rozszerz go do swoich potrzeb. Aby uzyskać dodatkowe informacje, zobacz [ten szablon](https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/template.md). +Treść jest prezentowana przy użyciu stałych szablonów. Wszelkie przyszłe treści muszą być zgodne z tym samym szablonem. Jeśli chcesz dodać nowe punktory, skopiuj format punktora z istniejącego i rozszerz go do swoich potrzeb. Aby uzyskać dodatkowe informacje, zobacz [ten szablon](../sections/template.md). ## 5. To na temat Node.js diff --git a/.operations/writing-guidelines.russian.md b/.operations/writing-guidelines.russian.md index 0ef1389cf..8f42baff9 100644 --- a/.operations/writing-guidelines.russian.md +++ b/.operations/writing-guidelines.russian.md @@ -16,7 +16,7 @@ ## 4. Согласованное форматирование -Контент представлен с использованием фиксированных шаблонов. Любое будущее содержание должно соответствовать тому же шаблону. Если вы хотите добавить новые маркеры, скопируйте формат маркера из существующего маркера и расширьте его для своих нужд. Для получения дополнительной информации, пожалуйста, просмотрите [этот шаблон](https://github.com/goldbergyoni/nodebestpractices/blob/master/sections/template.md). +Контент представлен с использованием фиксированных шаблонов. Любое будущее содержание должно соответствовать тому же шаблону. Если вы хотите добавить новые маркеры, скопируйте формат маркера из существующего маркера и расширьте его для своих нужд. Для получения дополнительной информации, пожалуйста, просмотрите [этот шаблон](../sections/template.md). ## 5. Это про Node.js diff --git a/README.basque.md b/README.basque.md index bf3012f2c..eefa504a1 100644 --- a/README.basque.md +++ b/README.basque.md @@ -101,7 +101,7 @@ Irakurri beste hizkuntza batzuetan: [![EN](./assets/flags/EN.png)**EN**](./READM ## ![✔] 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) +**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 @@ -288,7 +288,7 @@ Ez dio axola instrukzioak bereizteko puntu eta koma erabiltzen duzun edo ez, ohi **Bestela:** aurreko atalean esan bezala, JavaScripteko interpreteak automatikoki “puntu eta koma” gehitzen du instrukzio baten amaieran “puntu 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 -### Kode adibidea +### Kode Adibidea ```javascript // Egin @@ -632,7 +632,7 @@ edo hornitzaileen lainoko zerbitzuak **Bestela:** konturatuko zara “diagnostiko-inplementazio“ asko egiten ari zarela, eta kodea produkziora bidaltzen duzula soilik informazioa lortzeko diagnostikoa egite aldera -🔗 [** Informazio gehiago: sortu ‘mantentze lanen amaiera puntua‘**](./sections/production/createmaintenanceendpoint.basque.md) +🔗 [**Informazio gehiago: sortu ‘mantentze lanen amaiera puntua‘**](./sections/production/createmaintenanceendpoint.basque.md)

@@ -1377,201 +1377,256 @@ 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

📖

Forresst

🖋

Jonathan Svenheden

🖋

AustrisC

🖋

kyeongtae kim

🌍

007

🖋

Ane Diaz de Tuesta

🌍 🖋

YukiOta

🌍

Frazer Smith

🖋

Raz Luvaton

🖋

Yuta Azumi

🖋

andrewjbarbour

🖋

mr

🖋

Aleksandar

🖋

Owl

🖋

Yedidya Schwartz

🖋 💡

ari

🖋

Thomas König

🖋

Kalle Lämsä

🖋

Wyatt

🖋

KHADIR Tayeb

🖋
Kevin Rambaud
Kevin Rambaud

🖋
Michael Fine
Michael Fine

🖋
Shreya Dahal
Shreya Dahal

🖋
Matheus Cruz Rocha
Matheus Cruz Rocha

🖋
Yog Mehta
Yog Mehta

🖋
Kudakwashe Paradzayi
Kudakwashe Paradzayi

🖋
t1st3
t1st3

🖋
mulijordan1976
mulijordan1976

🖋
Matan Kushner
Matan Kushner

🖋
Fabio Hiroki
Fabio Hiroki

🖋
James Sumners
James Sumners

🖋
Dan Gamble
Dan Gamble

🖋
PJ Trainor
PJ Trainor

🖋
Remek Ambroziak
Remek Ambroziak

🖋
Yoni Jah
Yoni Jah

🖋
Misha Khokhlov
Misha Khokhlov

🖋
Evgeny Orekhov
Evgeny Orekhov

🖋
-
-

🖋
Isaac Halvorson
Isaac Halvorson

🖋
Vedran Karačić
Vedran Karačić

🖋
lallenlowe
lallenlowe

🖋
Nathan Wells
Nathan Wells

🖋
Paulo Reis
Paulo Reis

🖋
syzer
syzer

🖋
David Sancho
David Sancho

🖋
Robert Manolea
Robert Manolea

🖋
Xavier Ho
Xavier Ho

🖋
Aaron
Aaron

🖋
Jan Charles Maghirang Adona
Jan Charles Maghirang Adona

🖋
Allen
Allen

🖋
Leonardo Villela
Leonardo Villela

🖋
Michał Załęcki
Michał Załęcki

🖋
Chris Nicola
Chris Nicola

🖋
Alejandro Corredor
Alejandro Corredor

🖋
cwar
cwar

🖋
Yuwei
Yuwei

🖋
Utkarsh Bhatt
Utkarsh Bhatt

🖋
Duarte Mendes
Duarte Mendes

🖋
Jason Kim
Jason Kim

🖋
Mitja O.
Mitja O.

🖋
Sandro Miguel Marques
Sandro Miguel Marques

🖋
Gabe
Gabe

🖋
Ron Gross
Ron Gross

🖋
Valeri Karpov
Valeri Karpov

🖋
Sergio Bernal
Sergio Bernal

🖋
Nikola Telkedzhiev
Nikola Telkedzhiev

🖋
Vitor Godoy
Vitor Godoy

🖋
Manish Saraan
Manish Saraan

🖋
Sangbeom Han
Sangbeom Han

🖋
blackmatch
blackmatch

🖋
Joe Reeve
Joe Reeve

🖋
Ryan Busby
Ryan Busby

🖋
Iman Mohamadi
Iman Mohamadi

🖋
Sergii Paryzhskyi
Sergii Paryzhskyi

🖋
Kapil Patel
Kapil Patel

🖋
迷渡
迷渡

🖋
Hozefa
Hozefa

🖋
Ethan
Ethan

🖋
Sam
Sam

🖋
Arlind
Arlind

🖋
Teddy Toussaint
Teddy Toussaint

🖋
Lewis
Lewis

🖋
Gabriel Lidenor
Gabriel Lidenor

🖋
Roman
Roman

🖋
Francozeira
Francozeira

🖋
Invvard
Invvard

🖋
Rômulo Garofalo
Rômulo Garofalo

🖋
Tho Q Luong
Tho Q Luong

🖋
Burak Shen
Burak Shen

🖋
Martin Muzatko
Martin Muzatko

🖋
Jared Collier
Jared Collier

🖋
Hilton Meyer
Hilton Meyer

🖋
ChangJoo Park(박창주)
ChangJoo Park(박창주)

🖋
Masahiro Sakaguchi
Masahiro Sakaguchi

🖋
Keith Holliday
Keith Holliday

🖋
coreyc
coreyc

🖋
Maximilian Berkmann
Maximilian Berkmann

🖋
Douglas Mariano Valero
Douglas Mariano Valero

🖋
Marcelo Melo
Marcelo Melo

🖋
Mehmet Perk
Mehmet Perk

🖋
ryan ouyang
ryan ouyang

🖋
Shabeer
Shabeer

🖋
Eduard Kyvenko
Eduard Kyvenko

🖋
Deyvison Rocha
Deyvison Rocha

🖋
George Mamer
George Mamer

🖋
Konstantinos Leimonis
Konstantinos Leimonis

🖋
Oliver Lluberes
Oliver Lluberes

🌍
Tien Do
Tien Do

🖋
Ranvir Singh
Ranvir Singh

🖋
Vadim Nicolaev
Vadim Nicolaev

🖋 🌍
German Gamboa Gonzalez
German Gamboa Gonzalez

🖋
Hafez
Hafez

🖋
Chandiran
Chandiran

🖋
VinayaSathyanarayana
VinayaSathyanarayana

🖋
Kim Kern
Kim Kern

🖋
Kenneth Freitas
Kenneth Freitas

🖋
songe
songe

🖋
Kirill Shekhovtsov
Kirill Shekhovtsov

🖋
Serge
Serge

🖋
keyrwinz
keyrwinz

🖋
Dmitry Nikitenko
Dmitry Nikitenko

🖋
bushuai
bushuai

👀 🖋
Benjamin Gruenbaum
Benjamin Gruenbaum

🖋
Ezequiel
Ezequiel

🌍
Juan José Rodríguez
Juan José Rodríguez

🌍
Or Bin
Or Bin

🖋
Andreo Vieira
Andreo Vieira

🖋
Michael Solomon
Michael Solomon

🖋
Jimmy Callin
Jimmy Callin

🖋
Siddharth
Siddharth

🖋
Ryan Smith
Ryan Smith

🖋
Tom Boettger
Tom Boettger

🖋
Joaquín Ormaechea
Joaquín Ormaechea

🌍
dfrzuz
dfrzuz

🌍
Victor Homyakov
Victor Homyakov

🖋
Josh
Josh

🖋 🛡️
Alec Francis
Alec Francis

🖋
arjun6610
arjun6610

🖋
Jan Osch
Jan Osch

🖋
Thiago Rotondo Sampaio
Thiago Rotondo Sampaio

🌍
Alexsey
Alexsey

🖋
Luis A. Acurero
Luis A. Acurero

🌍
Lucas Romano
Lucas Romano

🌍
Denise Case
Denise Case

🖋
Nick Ribal
Nick Ribal

🖋 👀
0xflotus
0xflotus

🖋
Jonathan Chen
Jonathan Chen

🖋
Dilan Srilal
Dilan Srilal

🖋
vladthelittleone
vladthelittleone

🌍
Nik Osvalds
Nik Osvalds

🖋
Daniel Kiss
Daniel Kiss

📖
Forresst
Forresst

🖋
Jonathan Svenheden
Jonathan Svenheden

🖋
AustrisC
AustrisC

🖋
kyeongtae kim
kyeongtae kim

🌍
007
007

🖋
Ane Diaz de Tuesta
Ane Diaz de Tuesta

🌍 🖋
YukiOta
YukiOta

🌍
Frazer Smith
Frazer Smith

🖋
Raz Luvaton
Raz Luvaton

🖋
Yuta Azumi
Yuta Azumi

🖋
andrewjbarbour
andrewjbarbour

🖋
mr
mr

🖋
Aleksandar
Aleksandar

🖋
Owl
Owl

🖋
Yedidya Schwartz
Yedidya Schwartz

🖋 💡
ari
ari

🖋
Thomas König
Thomas König

🖋
Kalle Lämsä
Kalle Lämsä

🖋
Wyatt
Wyatt

🖋
KHADIR Tayeb
KHADIR Tayeb

🖋
Shankar Regmi
Shankar Regmi

🖋
Shubham
Shubham

🖋
Lucas Alves
Lucas Alves

🖋
Benjamin
Benjamin

🖋
Yeoh Joer
Yeoh Joer

🖋
Miigon
Miigon

🖋
Rostislav Bogorad
Rostislav Bogorad

🖋
Flouse
Flouse

🖋
Tarantini Pereira
Tarantini Pereira

🖋
Kazuki Matsuo
Kazuki Matsuo

🖋
Adam Smith
Adam Smith

🖋
Dohyeon Ko
Dohyeon Ko

🖋
Vladislav Legkov
Vladislav Legkov

🖋
Kerollos Magdy
Kerollos Magdy

🖋
Erez Lieberman
Erez Lieberman

🖋
Breno Macedo
Breno Macedo

🖋
Fernando Flores
Fernando Flores

🌍
Rafael Brito
Rafael Brito

🌍
Emiliano Peralta
Emiliano Peralta

🌍
Shin, SJ
Shin, SJ

🖋
Benjamin Forster
Benjamin Forster

🖋
Daniele Fedeli
Daniele Fedeli

🖋
djob195
djob195

🖋
antspk
antspk

🖋
정진영
정진영

🖋
kkk-cashwalk
kkk-cashwalk

🖋
apainintheneck
apainintheneck

🖋
Fajar Budhi Iswanda
Fajar Budhi Iswanda

🖋
이주호
이주호

🖋
Singh
Singh

🖋
Alex Dumitru
Alex Dumitru

🖋
Anton Lykhatskyi
Anton Lykhatskyi

🖋
sangwonlee
sangwonlee

🖋
Eugenio Berretta
Eugenio Berretta

🖋
soranakk
soranakk

🖋
고준영
고준영

🖋 💻
Guilherme Portella
Guilherme Portella

🖋
André Esser
André Esser

🖋
Scc
Scc

🌍
Mauro Accornero
Mauro Accornero

🖋
no-yan
no-yan

🖋
diff --git a/README.brazilian-portuguese.md b/README.brazilian-portuguese.md index 09342e646..10c88e6f2 100644 --- a/README.brazilian-portuguese.md +++ b/README.brazilian-portuguese.md @@ -36,7 +36,7 @@ Leia em diferentes idiomas: [![CN](./assets/flags/CN.png)**CN**](./README.chines

-# Bem-vindo! 3 Coisas Que Você Precisa Saber: +# Bem-vindo! 3 Coisas Que Você Precisa Saber **1. Quando você lê aqui, na verdade você lê alguns dos melhores artigos de Node.js -** este é um resumo e curadoria dos mais bem ranqueados conteúdos sobre as melhores práticas do Node.js. @@ -48,13 +48,13 @@ Leia em diferentes idiomas: [![CN](./assets/flags/CN.png)**CN**](./README.chines ## Índice -1. [Práticas de Estrutura de Projeto (5)](#1-práticas-de-estrutura-de-projeto) -2. [Práticas de Tratamento de Erros (12) ](#2-práticas-de-tratamento-de-erros) -3. [Práticas de Estilo de Código (13) ](#3-práticas-de-estilo-de-código) -4. [Práticas de Testes e Qualidade Geral (13) ](#4-práticas-de-testes-e-qualidade-geral) -5. [Práticas de Produção (19) ](#5-boas-práticas-de-produção) -6. [Práticas de Segurança (25)](#6-boas-práticas-em-segurança) -7. [Práticas de Performance (1) (Em Progresso ✍️)](#7-boas-práticas-em-performance) +1. [Práticas de Estrutura de Projeto (5)](#1-práticas-de-estrutura-de-projeto) +2. [Práticas de Tratamento de Erros (12) ](#2-práticas-de-tratamento-de-erros) +3. [Práticas de Estilo de Código (13) ](#3-práticas-de-estilo-de-código) +4. [Práticas de Testes e Qualidade Geral (13) ](#4-práticas-de-testes-e-qualidade-geral) +5. [Práticas de Produção (19) ](#5-boas-práticas-de-produção) +6. [Práticas de Segurança (25)](#6-boas-práticas-em-segurança) +7. [Práticas de Performance (1) (Em Progresso ✍️)](#7-boas-práticas-em-performance)

@@ -62,7 +62,7 @@ Leia em diferentes idiomas: [![CN](./assets/flags/CN.png)**CN**](./README.chines ## ![✔] 1.1 Estruture sua solução por componentes -**TL;DR:** A pior armadilha das grandes aplicações é manter uma enorme base de código com centenas de dependências - tal qual as monolíticas, que diminuem a velocidade dos desenvolvedores conforme eles tentam incorporar novos recursos. Em vez disso, particione seu código em componentes, cada um com sua própria pasta ou uma base de código dedicada, e garanta cada unidade seja mantida pequena e simples. Veja o link ‘Leia Mais’ abaixo, para ver exemplos de estrutura correta de projeto. +**TL;DR:** A pior armadilha das grandes aplicações é manter uma enorme base de código com centenas de dependências - tal qual as monolíticas, que diminuem a velocidade dos desenvolvedores conforme eles tentam incorporar novos recursos. Em vez disso, particione seu código em componentes, cada um com sua própria pasta ou uma base de código dedicada, e garanta que cada unidade seja mantida pequena e simples. Veja o link ‘Leia Mais’ abaixo, para ver exemplos de estrutura correta de projeto. **Caso contrário:** Quando desenvolvendo novos recursos, desenvolvedores têm dificuldade para perceber o impacto de suas modificações e temem estragar outros componentes dependentes - deploys se tornam mais lentos e arriscados. Também é considerado mais difícil de escalar quando nenhuma unidade de negócio está separada. @@ -230,9 +230,9 @@ Leia em diferentes idiomas: [![CN](./assets/flags/CN.png)**CN**](./README.chines **Caso contrário:** Uma função que retorna uma `promise` sem o `await` não aparecerá na pilha de erro. A ausência dessas informações provavelmente complicariam a compreensão do fluxo que leva ao erro, -especialmente se a causa do comportamento anormal estiver dentro da função ausente +especialmente se a causa do comportamento anormal estiver dentro da função ausente - +🔗 [**Leia Mais: retornando promises**](./sections/errorhandling/returningpromises.md)


@@ -271,7 +271,8 @@ function someFunction() { } // Avoid -function someFunction() { +function someFunction() +{ // code block } ``` @@ -290,7 +291,7 @@ Não importa se você usa ponto-e-vírgula ou não para separar suas declaraçõ **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 +### Exemplo de código ```javascript // Faça @@ -340,7 +341,7 @@ const count = 2 // tenta executar 2(), mas 2 não é uma função **Caso contrário:** O JavaScript é a única linguagem no mundo que permite invocar um construtor (“Class”) diretamente sem instanciá-lo primeiro. Consequentemente, Classes e construtores de funções são diferenciados começando com UpperCamelCase -### Exemplo de Código +### 3.6 Exemplo de Código ```javascript // para classes nós usamos UpperCamelCase @@ -383,7 +384,7 @@ function doSomething() {} **Caso contrário:** Alterar a estrutura interna dos arquivos ou a assinatura pode quebrar a interface com clientes. -### Exemplo de Código +### 3.9 Exemplo de Código ```javascript // Do @@ -403,7 +404,7 @@ module.exports.SMSNumberResolver = require("./SMSNumberResolver/SMSNumberResolve **Caso contrário:** Variáveis diferentes podem retornar verdadeiro quando comparadas usando o operador `==`. -### Exemplo de Código +### 3.10 Exemplo de Código ```javascript "" == "0"; // false @@ -466,13 +467,13 @@ Todas as declarações acima false se feitas com `===`.

-## ![✔] 4.3 Estutura de testes padrão AAA +## ![✔] 4.3 Estutura de testes padrão AAA -**TL;DR:** Estruture seus testes com 3 seções bem separadas: Arrange, Act & Assert (AAA). A primeira parte inclui a configuração do teste, depois a execução do teste unitário, e finalmente, a fase de asserção. Seguir esta estrutura garante que o leitor não gaste nenhuma CPU cerebral para entender o plano de teste +**TL;DR:** Estruture seus testes com 3 seções bem separadas: Arrange, Act & Assert (AAA). A primeira parte inclui a configuração do teste, depois a execução do teste unitário, e finalmente, a fase de asserção. Seguir esta estrutura garante que o leitor não gaste nenhuma CPU cerebral para entender o plano de teste -**Caso contrário:** Você não somente passará várias horas do dia para entender o código principal, mas agora também gastará várias horas no que deveria ter sido uma simples parte do dia (testando) esticando seu cérebro. +**Caso contrário:** Você não somente passará várias horas do dia para entender o código principal, mas agora também gastará várias horas no que deveria ter sido uma simples parte do dia (testando) esticando seu cérebro. - +🔗 [**Leia Mais: Estutura de testes padrão AAA**](./sections/testingandquality/aaa.md)

@@ -554,13 +555,13 @@ Todas as declarações acima false se feitas com `===`.

-## ![✔] 4.13 Teste seus 'middlewares' isolatdamente +## ![✔] 4.13 Teste seus 'middlewares' isoladamente -**TL;DR:** quando um 'middleware' contém alguma lógica imensa que abrange muitas solicitações, vale a pena testá-lo isoladamente, sem ativar todo o framework. Isso pode ser facilmente alcançado por 'stubbing' e espionando os objetos {req, res, next} +**TL;DR:** quando um 'middleware' contém alguma lógica imensa que abrange muitas solicitações, vale a pena testá-lo isoladamente, sem ativar todo o framework. Isso pode ser facilmente alcançado por 'stubbing' e espionando os objetos {req, res, next} -**Caso contrário:** Um bug no 'middleware Express' === um bug em todas ou na maioria das solicitações +**Caso contrário:** Um bug no 'middleware Express' === um bug em todas ou na maioria das solicitações - +🔗 [**Read More: Test middlewares in isolation**](./sections/testingandquality/test-middlewares.md)


@@ -568,7 +569,7 @@ Todas as declarações acima false se feitas com `===`. # `5. Boas Práticas de Produção` -## ![✔] 5.1. Monitoramento! +## ![✔] 5.1. Monitoramento **TL;DR:** O monitoramento é um jogo de descobrir problemas antes que os clientes os encontrem - obviamente deve ser atribuída muita importância para isto. O mercado está sobrecarregado de ofertas, portanto, considere começar com a definição das métricas básicas que você deve seguir (sugestões minhas dentro), depois passe por recursos extras e escolha a solução que marca todas as caixas. Acesse o ‘Gist’ abaixo para uma visão geral das soluções. @@ -748,11 +749,11 @@ Todas as declarações acima false se feitas com `===`. ## ![✔] 5.19. Instale seus pacotes com `npm ci` -**TL;DR:** Você precisa ter certeza de que o código de produção usa a versão exata dos pacotes que você realizou os testes. Execute `npm ci` para fazer estritamente uma instalação limpa de suas dependências correspondentes do package.json e do package-lock.json. O uso desse comando é recomendado em ambientes automatizados, como pipelines de integração contínua. +**TL;DR:** Você precisa ter certeza de que o código de produção usa a versão exata dos pacotes que você realizou os testes. Execute `npm ci` para fazer estritamente uma instalação limpa de suas dependências correspondentes do package.json e do package-lock.json. O uso desse comando é recomendado em ambientes automatizados, como pipelines de integração contínua. **Caso contrário:** o QA testará completamente o código e aprovará uma versão que se comportará de maneira diferente em produção. Pior ainda, diferentes servidores no mesmo cluster de produção podem executar códigos diferentes. - +🔗 [**Read More: Use npm ci**](./sections/production/installpackageswithnpmci.md)


diff --git a/README.chinese.md b/README.chinese.md index fa9654d1f..44f39e18b 100644 --- a/README.chinese.md +++ b/README.chinese.md @@ -17,7 +17,8 @@ [![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) @@ -27,6 +28,7 @@


## [目录](#table-of-contents) + 1. [项目结构实践 (5) ](#1-project-structure-practices) 2. [异常处理实践 (11) ](#2-error-handling-practices) 3. [编码规范实践 (12) ](#3-code-style-practices) @@ -35,7 +37,6 @@ 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. 项目结构实践

@@ -81,7 +82,6 @@ ## ![✔] 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)。 **否则:** 不能满足任意的配置要求将会使开发,运维团队,或者两者,易于陷入泥潭。 @@ -108,7 +108,6 @@ **TL;DR:** 很多人抛出异常使用字符串类型或一些自定义类型 - 这会导致错误处理逻辑和模块间的调用复杂化。是否您reject一个promise,抛出异常或发出(emit)错误 - 使用内建的错误对象将会增加设计一致性,并防止信息的丢失。 - **否则:** 调用某些模块,将不确定哪种错误类型会返回 - 这将会使恰当的错误处理更加困难。更坏的情况是,使用特定的类型描述错误,会导致重要的错误信息缺失,比如stack trace! 🔗 [**更多: 使用内建错误对象**](./sections/errorhandling/useonlythebuiltinerror.chinese.md) @@ -141,7 +140,6 @@ **否则:** 任何API的客户端可能决定崩溃并重启,仅仅因为它收到一个不能处理的错误。注意:API的调用者可能是你(在微服务环境中非常典型)。 - 🔗 [**更多: 使用Swagger记录错误**](./sections/errorhandling/documentingusingswagger.chinese.md)

@@ -156,8 +154,6 @@

- - ## ![✔] 2.7 使用一个成熟的日志工具提高错误的可见性 **TL;DR:** 一系列成熟的日志工具,比如Winston,Bunyan和Log4J,会加速错误的发现和理解。忘记console.log吧。 @@ -166,17 +162,14 @@ 🔗 [**更多: 使用好用的日志工具**](./sections/errorhandling/usematurelogger.chinese.md) -

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

@@ -187,19 +180,16 @@ **否则:** 您花了很多的力气在测量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)

@@ -239,6 +229,7 @@ **TL;DR:** 代码块的第一个大括号应该和声明的起始保持在同一行中。 ### 代码示例 + ```javascript // 建议 function someFunction() { @@ -280,7 +271,8 @@ **否则:** JavaScript是世界上唯一一门不需要实例化,就可以直接调用构造函数("Class")的编码语言。因此,类和函数的构造函数由采用UpperCamelCase开始区分。 -### 代码示例 ### +### 3.6 代码示例 + ```javascript // 使用UpperCamelCase命名类名 class SomeClassExample () { @@ -326,7 +318,8 @@ **否则:** 更改文件内部结构或签名可能会破坏与客户端的接口。 -### 代码示例 +### 3.9 代码示例 + ```javascript // 建议 module.exports.SMSProvider = require('./SMSProvider'); @@ -339,14 +332,14 @@

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

@@ -383,12 +377,10 @@ null == undefined // true 🔗 [**更多: 这是拥抱箭头函数的时刻**](https://medium.com/javascript-scene/familiarity-bias-is-holding-you-back-its-time-to-embrace-arrow-functions-3d37e1a9bb75) -


⬆ 返回顶部

-

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

## ![✔] 4.1 至少,编写API(组件)测试 @@ -405,7 +397,6 @@ null == undefined // true **否则:** 您可能让一些反模式和易受攻击的代码传递到您的生产环境中。 -

## ![✔] 4.3 仔细挑选您的持续集成(CI)平台 @@ -440,8 +431,6 @@ null == undefined // true **否则:** 当你的大部分代码没有被测试覆盖时,就不会有任何自动化的度量指标告诉你了。 - -

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


⬆ 返回顶部

5. 上线实践

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

@@ -483,7 +469,6 @@ null == undefined // true **否则:** 您最终像是面对一个黑盒,不知道发生了什么事情,然后你开始重新写日志语句添加额外的信息。 - 🔗 [**更多: 使用智能日志增加透明度**](./sections/production/smartlogging.chinese.md)

@@ -494,7 +479,6 @@ null == undefined // true **否则:** 可怜的单线程Node将不幸地忙于处理网络任务,而不是处理应用程序核心,性能会相应降低。 - 🔗 [**更多: 委托可能的一切(例如:gzip,SSL)给反向代理**](./sections/production/delegatetoproxy.chinese.md)

@@ -505,7 +489,6 @@ null == undefined // true **否则:** QA测试通过的代码和批准的版本,在生产中表现不一致。更糟糕的是,同一生产集群中的不同服务器可能运行不同的代码。 - 🔗 [**更多: 锁住依赖**](./sections/production/lockdependencies.chinese.md)

@@ -516,10 +499,8 @@ null == undefined // true **否则:** 运行几十个实例没有明确的战略和太多的工具(集群管理,docker,PM2)可能导致一个DevOps混乱 - 🔗 [**更多: 使用正确的工具保护进程正常运行**](./sections/production/guardprocess.chinese.md) -

## ![✔] 5.6. 利用CPU多核 @@ -528,7 +509,6 @@ null == undefined // true **否则:** 您的应用可能只是使用了其可用资源中的25% (!),甚至更少。注意,一台典型的服务器有4个或更多的CPU,默认的Node.js部署仅仅用了一个CPU(甚至使用PaaS服务,比如AWS beanstalk,也一样)。 - 🔗 [**更多: 利用所有的CPU**](./sections/production/utilizecpu.chinese.md)

@@ -539,7 +519,6 @@ null == undefined // true **否则:** 您会发现,您正在执行许多“诊断部署” – 将代码发送到生产中,仅仅只为了诊断目的提取一些信息。 - 🔗 [**更多: 创建一个 '维护端点'**](./sections/production/createmaintenanceendpoint.chinese.md)

@@ -550,20 +529,16 @@ null == undefined // true **否则:** 你可能会花大力气测量API性能和停机时间,也许你永远不会知道,真实场景下哪个是你最慢的代码部分,这些怎么影响用户体验。 - 🔗 [**更多: 使用APM产品发现错误和宕机时间**](./sections/production/apmproducts.chinese.md) -

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

@@ -574,80 +549,76 @@ null == undefined // true **否则:** 您的内存可能一天泄漏一百兆,就像曾发生在沃尔玛的一样。 - 🔗 [**更多: 测量和保护内存使用**](./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工具,使他们成为简化部署的行业标准。 **否则:** 长时间部署 -> 线上宕机 & 和人相关的错误 -> 团队部署时不自信 -> 更少的部署和需求 +

+ +## ![✔] 5.17. 使用 Node.js 的 LTS 版本 + +**TL;DR:** 确保您是使用LTS版本的Node.js来获取关键的错误修复、安全更新和性能改进。 + +**否则:** 新发现的错误或漏洞可能会被用于生产环境中运行的应用程序,您的应用程序可能会变得难以维护且不受各种模块支持. + +🔗 [**更多: 使用node.js的LTS版本**](./sections/production/LTSrelease.chinese.md) +


⬆ 返回顶部

@@ -981,34 +952,36 @@ null == undefined // true

⬆ Return to top

-# `API 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. +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.

@@ -1017,4 +990,3 @@ Full Stack Developer based in New Zealand, interested in architecting and buildi We appreciate any contribution, from a single word fix to a new best practice. View our contributors and [contributing documentation here!](./README.md#contributors-)


- diff --git a/README.french.md b/README.french.md index d75cd56c1..ad402286f 100644 --- a/README.french.md +++ b/README.french.md @@ -849,7 +849,7 @@ Toutes les déclarations ci-dessus renverront false si elles sont utilisées ave -**TL;PL :** Les mots de passe ou les secrets (par exemple les clés API) doivent être stockés en utilisant une fonction de hachage sécurisée + un salt comme `bcrypt`,` scrypt`, ou dans le pire des cas `pbkdf2`. +**TL;PL :** Les mots de passe ou les secrets (par exemple les clés API) doivent être stockés en utilisant une fonction de hachage sécurisée + un salt comme `bcrypt`,`scrypt`, ou dans le pire des cas `pbkdf2`. **Autrement :** Les mots de passe et les secrets qui sont stockés sans utiliser de fonction sécurisée sont vulnérables au brute-force et aux attaques de dictionnaire qui mèneront à leur divulgation. @@ -1289,7 +1289,7 @@ Toutes les traductions sont fournies par la communauté. Nous serons heureux de ### Traductions en cours -- ![FR](./assets/flags/FR.png) [Français](https://github.com/goldbergyoni/nodebestpractices/blob/master/README.french.md) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/129)) +- ![FR](./assets/flags/FR.png) [Français](./README.french.md) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/129)) - ![HE](./assets/flags/HE.png) Hébreu ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/156)) - ![KR](./assets/flags/KR.png) [Coréen](README.korean.md) - Avec l'aimable autorisation de [Sangbeom Han](https://github.com/uronly14me) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/94)) - ![ES](./assets/flags/ES.png) [Espagnol](https://github.com/goldbergyoni/nodebestpractices/blob/spanish-translation/README.spanish.md) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/95)) @@ -1358,7 +1358,7 @@ Merci à tous nos collaborateurs ! 🙏 Nos collaborateurs sont des membres qui contribuent régulièrement au dépôt, en suggérant de nouvelles bonnes pratiques, en triant les issues, en examinant les pull request et bien d'autres choses encore. Si vous souhaitez nous aider à guider des milliers de personnes à créer de meilleures applications Node.js, veuillez lire nos [directives pour les contributeurs](./.operations/CONTRIBUTING.md) 🎉 -| | | Raz Luvaton | Josh Hemphill | +| | | Raz Luvaton | Josh Hemphill | | :--: | :--: | :--: | :--: | | [Ido Richter (Founder)](https://github.com/idori) | [Keith Holliday](https://github.com/TheHollidayInn) | [Raz Luvaton](https://github.com/rluvaton) | [Josh Hemphill](https://github.com/josh-hemphill) | @@ -1382,220 +1382,256 @@ Merci à ces merveilleuses personnes qui ont contribué à ce dépôt ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

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

📖

Forresst

🖋

Jonathan Svenheden

🖋

AustrisC

🖋

kyeongtae kim

🌍

007

🖋

Ane Diaz de Tuesta

🌍 🖋

YukiOta

🌍

Frazer Smith

🖋

Raz Luvaton

🖋

Yuta Azumi

🖋

andrewjbarbour

🖋

mr

🖋

Aleksandar

🖋

Owl

🖋

Yedidya Schwartz

🖋 💡

ari

🖋

Thomas König

🖋

Kalle Lämsä

🖋

Wyatt

🖋

KHADIR Tayeb

🖋

Shankar Regmi

🖋

Shubham

🖋

Lucas Alves

🖋

Benjamin

🖋

Yeoh Joer

🖋

Miigon

🖋

Rostislav Bogorad

🖋

Flouse

🖋

Tarantini Pereira

🖋

Kazuki Matsuo

🖋

Adam Smith

🖋

Dohyeon Ko

🖋

Vladislav Legkov

🖋

Kerollos Magdy

🖋

Erez Lieberman

🖋
Kevin Rambaud
Kevin Rambaud

🖋
Michael Fine
Michael Fine

🖋
Shreya Dahal
Shreya Dahal

🖋
Matheus Cruz Rocha
Matheus Cruz Rocha

🖋
Yog Mehta
Yog Mehta

🖋
Kudakwashe Paradzayi
Kudakwashe Paradzayi

🖋
t1st3
t1st3

🖋
mulijordan1976
mulijordan1976

🖋
Matan Kushner
Matan Kushner

🖋
Fabio Hiroki
Fabio Hiroki

🖋
James Sumners
James Sumners

🖋
Dan Gamble
Dan Gamble

🖋
PJ Trainor
PJ Trainor

🖋
Remek Ambroziak
Remek Ambroziak

🖋
Yoni Jah
Yoni Jah

🖋
Misha Khokhlov
Misha Khokhlov

🖋
Evgeny Orekhov
Evgeny Orekhov

🖋
-
-

🖋
Isaac Halvorson
Isaac Halvorson

🖋
Vedran Karačić
Vedran Karačić

🖋
lallenlowe
lallenlowe

🖋
Nathan Wells
Nathan Wells

🖋
Paulo Reis
Paulo Reis

🖋
syzer
syzer

🖋
David Sancho
David Sancho

🖋
Robert Manolea
Robert Manolea

🖋
Xavier Ho
Xavier Ho

🖋
Aaron
Aaron

🖋
Jan Charles Maghirang Adona
Jan Charles Maghirang Adona

🖋
Allen
Allen

🖋
Leonardo Villela
Leonardo Villela

🖋
Michał Załęcki
Michał Załęcki

🖋
Chris Nicola
Chris Nicola

🖋
Alejandro Corredor
Alejandro Corredor

🖋
cwar
cwar

🖋
Yuwei
Yuwei

🖋
Utkarsh Bhatt
Utkarsh Bhatt

🖋
Duarte Mendes
Duarte Mendes

🖋
Jason Kim
Jason Kim

🖋
Mitja O.
Mitja O.

🖋
Sandro Miguel Marques
Sandro Miguel Marques

🖋
Gabe
Gabe

🖋
Ron Gross
Ron Gross

🖋
Valeri Karpov
Valeri Karpov

🖋
Sergio Bernal
Sergio Bernal

🖋
Nikola Telkedzhiev
Nikola Telkedzhiev

🖋
Vitor Godoy
Vitor Godoy

🖋
Manish Saraan
Manish Saraan

🖋
Sangbeom Han
Sangbeom Han

🖋
blackmatch
blackmatch

🖋
Joe Reeve
Joe Reeve

🖋
Ryan Busby
Ryan Busby

🖋
Iman Mohamadi
Iman Mohamadi

🖋
Sergii Paryzhskyi
Sergii Paryzhskyi

🖋
Kapil Patel
Kapil Patel

🖋
迷渡
迷渡

🖋
Hozefa
Hozefa

🖋
Ethan
Ethan

🖋
Sam
Sam

🖋
Arlind
Arlind

🖋
Teddy Toussaint
Teddy Toussaint

🖋
Lewis
Lewis

🖋
Gabriel Lidenor
Gabriel Lidenor

🖋
Roman
Roman

🖋
Francozeira
Francozeira

🖋
Invvard
Invvard

🖋
Rômulo Garofalo
Rômulo Garofalo

🖋
Tho Q Luong
Tho Q Luong

🖋
Burak Shen
Burak Shen

🖋
Martin Muzatko
Martin Muzatko

🖋
Jared Collier
Jared Collier

🖋
Hilton Meyer
Hilton Meyer

🖋
ChangJoo Park(박창주)
ChangJoo Park(박창주)

🖋
Masahiro Sakaguchi
Masahiro Sakaguchi

🖋
Keith Holliday
Keith Holliday

🖋
coreyc
coreyc

🖋
Maximilian Berkmann
Maximilian Berkmann

🖋
Douglas Mariano Valero
Douglas Mariano Valero

🖋
Marcelo Melo
Marcelo Melo

🖋
Mehmet Perk
Mehmet Perk

🖋
ryan ouyang
ryan ouyang

🖋
Shabeer
Shabeer

🖋
Eduard Kyvenko
Eduard Kyvenko

🖋
Deyvison Rocha
Deyvison Rocha

🖋
George Mamer
George Mamer

🖋
Konstantinos Leimonis
Konstantinos Leimonis

🖋
Oliver Lluberes
Oliver Lluberes

🌍
Tien Do
Tien Do

🖋
Ranvir Singh
Ranvir Singh

🖋
Vadim Nicolaev
Vadim Nicolaev

🖋 🌍
German Gamboa Gonzalez
German Gamboa Gonzalez

🖋
Hafez
Hafez

🖋
Chandiran
Chandiran

🖋
VinayaSathyanarayana
VinayaSathyanarayana

🖋
Kim Kern
Kim Kern

🖋
Kenneth Freitas
Kenneth Freitas

🖋
songe
songe

🖋
Kirill Shekhovtsov
Kirill Shekhovtsov

🖋
Serge
Serge

🖋
keyrwinz
keyrwinz

🖋
Dmitry Nikitenko
Dmitry Nikitenko

🖋
bushuai
bushuai

👀 🖋
Benjamin Gruenbaum
Benjamin Gruenbaum

🖋
Ezequiel
Ezequiel

🌍
Juan José Rodríguez
Juan José Rodríguez

🌍
Or Bin
Or Bin

🖋
Andreo Vieira
Andreo Vieira

🖋
Michael Solomon
Michael Solomon

🖋
Jimmy Callin
Jimmy Callin

🖋
Siddharth
Siddharth

🖋
Ryan Smith
Ryan Smith

🖋
Tom Boettger
Tom Boettger

🖋
Joaquín Ormaechea
Joaquín Ormaechea

🌍
dfrzuz
dfrzuz

🌍
Victor Homyakov
Victor Homyakov

🖋
Josh
Josh

🖋 🛡️
Alec Francis
Alec Francis

🖋
arjun6610
arjun6610

🖋
Jan Osch
Jan Osch

🖋
Thiago Rotondo Sampaio
Thiago Rotondo Sampaio

🌍
Alexsey
Alexsey

🖋
Luis A. Acurero
Luis A. Acurero

🌍
Lucas Romano
Lucas Romano

🌍
Denise Case
Denise Case

🖋
Nick Ribal
Nick Ribal

🖋 👀
0xflotus
0xflotus

🖋
Jonathan Chen
Jonathan Chen

🖋
Dilan Srilal
Dilan Srilal

🖋
vladthelittleone
vladthelittleone

🌍
Nik Osvalds
Nik Osvalds

🖋
Daniel Kiss
Daniel Kiss

📖
Forresst
Forresst

🖋
Jonathan Svenheden
Jonathan Svenheden

🖋
AustrisC
AustrisC

🖋
kyeongtae kim
kyeongtae kim

🌍
007
007

🖋
Ane Diaz de Tuesta
Ane Diaz de Tuesta

🌍 🖋
YukiOta
YukiOta

🌍
Frazer Smith
Frazer Smith

🖋
Raz Luvaton
Raz Luvaton

🖋
Yuta Azumi
Yuta Azumi

🖋
andrewjbarbour
andrewjbarbour

🖋
mr
mr

🖋
Aleksandar
Aleksandar

🖋
Owl
Owl

🖋
Yedidya Schwartz
Yedidya Schwartz

🖋 💡
ari
ari

🖋
Thomas König
Thomas König

🖋
Kalle Lämsä
Kalle Lämsä

🖋
Wyatt
Wyatt

🖋
KHADIR Tayeb
KHADIR Tayeb

🖋
Shankar Regmi
Shankar Regmi

🖋
Shubham
Shubham

🖋
Lucas Alves
Lucas Alves

🖋
Benjamin
Benjamin

🖋
Yeoh Joer
Yeoh Joer

🖋
Miigon
Miigon

🖋
Rostislav Bogorad
Rostislav Bogorad

🖋
Flouse
Flouse

🖋
Tarantini Pereira
Tarantini Pereira

🖋
Kazuki Matsuo
Kazuki Matsuo

🖋
Adam Smith
Adam Smith

🖋
Dohyeon Ko
Dohyeon Ko

🖋
Vladislav Legkov
Vladislav Legkov

🖋
Kerollos Magdy
Kerollos Magdy

🖋
Erez Lieberman
Erez Lieberman

🖋
Breno Macedo
Breno Macedo

🖋
Fernando Flores
Fernando Flores

🌍
Rafael Brito
Rafael Brito

🌍
Emiliano Peralta
Emiliano Peralta

🌍
Shin, SJ
Shin, SJ

🖋
Benjamin Forster
Benjamin Forster

🖋
Daniele Fedeli
Daniele Fedeli

🖋
djob195
djob195

🖋
antspk
antspk

🖋
정진영
정진영

🖋
kkk-cashwalk
kkk-cashwalk

🖋
apainintheneck
apainintheneck

🖋
Fajar Budhi Iswanda
Fajar Budhi Iswanda

🖋
이주호
이주호

🖋
Singh
Singh

🖋
Alex Dumitru
Alex Dumitru

🖋
Anton Lykhatskyi
Anton Lykhatskyi

🖋
sangwonlee
sangwonlee

🖋
Eugenio Berretta
Eugenio Berretta

🖋
soranakk
soranakk

🖋
고준영
고준영

🖋 💻
Guilherme Portella
Guilherme Portella

🖋
André Esser
André Esser

🖋
Scc
Scc

🌍
Mauro Accornero
Mauro Accornero

🖋
no-yan
no-yan

🖋
diff --git a/README.hebrew.md b/README.hebrew.md new file mode 100644 index 000000000..22d5ce0ba --- /dev/null +++ b/README.hebrew.md @@ -0,0 +1,1927 @@ +[✔]: assets/images/checkbox-small-blue.png + +# שיטות עבודה מומלצות ב Node.js + +

+ Node.js Best Practices +

+ +
+ +
+ 102 items Last update: August 16, 2023 Updated for Node 14.0.0 +
+ +
+ +[](https://twitter.com/nodepractices/) **עיקבו אחרינו בטוויטר!** [**@nodepractices**](https://twitter.com/nodepractices/) +
+**:writing_hand: תורגם על ידי [הוד בואר](https://github.com/hodbauer)** +
+ +לקריאה בשפות נוספות: [![CN](./assets/flags/CN.png)**סינית**](./README.chinese.md), [![FR](./assets/flags/FR.png)**צרפתית**](./README.french.md), [![BR](./assets/flags/BR.png)**פורטוגזית**](./README.brazilian-portuguese.md), [![RU](./assets/flags/RU.png)**רוסית**](./README.russian.md), [![PL](./assets/flags/PL.png)**פולנית**](./README.polish.md), [![JA](./assets/flags/JA.png)**יפנית**](./README.japanese.md), [![EU](./assets/flags/EU.png)**באסקית**](./README.basque.md) [(![ES](./assets/flags/ES.png)**ספרדית**, ![HE](./assets/flags/HE.png)**עברית**, ![KR](./assets/flags/KR.png)**קוריאנית** ו ![TR](./assets/flags/TR.png)**טורקית** בתהליך! )](#translations) + +
+ +# Latest Best Practices and News + +- **🛰 2023 edition is released soon**: We're now writing the next edition, stay tuned? + +- **✨ 89,000 stars**: Blushing, surprised and proud! + +- **🔖 New menu and tags**: Our menu is collapsible now and includes `#tags`. New visitors can read `#strategic` items first. Returning visitors can focus on `#new` content. Seniors can filter for `#advanced` items. Courtesy of the one and only [Rubek Joshi](https://github.com/rubek-joshi) + +- **![FR](./assets/flags/FR.png) French translation!1! :** The latest translation that joins our international guide is French. Bienvenue + +

+ +# ברוכים הבאים! שלושה דברים שכדאי לדעת לפני שגוללים מטה + +**1. הנכם קוראים עשרות מאמרים של שיטות העבודה המומלצות ב Node.js -** המאגר הזה הוא סיכום לא יסולא בפז של שיטות העבודה המומלצות ב Node.js , כמו כן הוא נעשה על בשיתוף פעולה. + +**2. זהו האוסף הגדול ביותר, והוא ממשיך לגדול כל שבוע -** נכון לרגע זה, יש למעלה מ 100 שיטות עבודה מומלצות, המלצות ארכיטקטורה והמלצות סגנון כתיבה. נושאים חדשים ובקשות חדשות (PR's) מתווספים כל יום במטרה לשמור את התוכן מעודכן. אנחנו נשמח לראותכם תורמים לפה, בין אם לתקן שגיאות קוד, עזרה בתרגום, או להציע רעיונות מבריקים חדשים. ראו את [המדריך לכתיבת הנחיות](./.operations/writing-guidelines.md). + +**3. שיטות העבודה כוללות מידע נוסף -** רוב הנקודות כוללות קישור **🔗לקריאה נוספת** שמרחיב על ידי דוגמאות קוד, ציטוטים מבלוגים נבחרים ומידע נוסף. + +

+ +# מאת יוני גולדברג + +### לימדו איתי: כיועץ, אני נפגש עם קבוצות מכל העולם במגוון פעולות כמו סדנאות ומעבר על קוד. 🎉 לאחרונה פרסמתי את [הקורס המתקדם לכתיבת בדיקות](https://testjavascript.com/) + +

+## תוכן העניינים + +
+ + 1. מבנה הפרוייקט (6) + + +  [1.1 בנו את הפרוייקט לפי רכיבים עסקיים `#strategic` `#updated`](#-11-structure-your-solution-by-business-components)
+  [1.2 חלוקת הרכיבים ל3 שכבות, שמירה על שכבת הווב בגבולותיה `#strategic` `#updated`](#-12-layer-your-components-with-3-tiers-keep-the-web-layer-within-its-boundaries)
+  [1.3 עטפו כלים משותפים בחבילות, שקלו את הפצתם](#-13-wrap-common-utilities-as-packages-consider-publishing)
+  [1.4 השתמשו בקונפיגורציה עם משתני סביבה באופן מודע, מאובטח והיררכי `#updated`](#-14-use-environment-aware-secure-and-hierarchical-config)
+  [1.5 שקלו את כל ההשלכות בעת בחירת מסגרת `#new`](#-15-consider-all-the-consequences-when-choosing-the-main-framework)
+  [1.6 השתמשו ב-TypeScript במידתיות ובצורה מושכלת `#new`](#-16-use-typescript-sparingly-and-thoughtfully)
+ +
+ +
+ + 2. ניהול שגיאות (12) + + +  [2.1 השתמשו ב Async-Await או הבטחות לניהול שגיאות אסינכרוניות](#-21-use-async-await-or-promises-for-async-error-handling)
+  [2.2 הרחיבו את מבנה אוביקט השגיאה המובנה Error `#strategic` `#updated`](#-22-extend-the-built-in-error-object)
+  [2.3 הבחינו בין שגיאות קטסטרופליות לבין שגיאות תפעוליות `#strategic` `#updated`](#-23-distinguish-catastrophic-errors-from-operational-errors)
+  [2.4 נהלו את השגיאות במרוכז ולא באמצעות כלי ביניים `#strategic`](#-24-handle-errors-centrally-not-within-a-middleware)
+  [2.5 תעדו את שגיאות ה-API באמצעות OpenAPI או GraphQL](#-25-document-api-errors-using-openapi-or-graphql)
+  [2.6 הורידו את התהליך בצורה מסודרת כאשר זר בא לבקר `#strategic`](#-26-exit-the-process-gracefully-when-a-stranger-comes-to-town)
+  [2.7 השתמשו ב-Logger מוכר ואמין כדי להגדיל את הקְרִיאוּת של השגיאות `#updated`](#-27-use-a-mature-logger-to-increase-errors-visibility)
+  [2.8 בידקו את תגובת המערכת לשגיאות על ידי שימוש בכלי הבדיקות האהוב עליכם `#updated`](#-28-test-error-flows-using-your-favorite-test-framework)
+  [2.9 גלו שגיאות וזמני השבתה על ידי שימוש בכלי APM](#-29-discover-errors-and-downtime-using-apm-products)
+  [2.10 תפסו מקרים לא מטופלים של דחיות של הבטחות `#updated`](#-210-catch-unhandled-promise-rejections)
+  [2.11 היכשלו מהר, ודאו את משתני הקלט באמצעות ספריה יעודית](#-211-fail-fast-validate-arguments-using-a-dedicated-library)
+  [2.12 תמיד המתינו לתשובה מההבטחות לפני שאתם מעבירים את התשובה הלאה כדי להימנע ממעקב חלקי `#new`](#-212-always-await-promises-before-returning-to-avoid-a-partial-stacktrace)
+ +
+ +
+ + 3. תבניות קוד וסגנון עיצוב (13) + + +  [3.1 השתמשו ב-ESLint `#strategic`](#-31-use-eslint)
+  [3.2 השתמשו בתוספים של Node.js שמרחיבים את ESLint `#updated`](#-32-use-nodejs-eslint-extension-plugins)
+  [3.3 התחילו בלוק של קוד עם סוגריים מסולסלים באותה השורה](#-33-start-a-codeblocks-curly-braces-on-the-same-line)
+  [3.4 הפרידו בין ההצהרות השונות בצורה תקנית](#-34-separate-your-statements-properly)
+  [3.5 תנו לפונקציה שם](#-35-name-your-functions)
+  [3.6 השתמשו במוסכמות קבועות במתן שמות למשתנים, לקבועים, לפונקציות ולמחלקות](#-36-use-naming-conventions-for-variables-constants-functions-and-classes)
+  [3.7 העדיפו const על פני let. ניטשו את var](#-37-prefer-const-over-let-ditch-the-var)
+  [3.8 טענו מודולים בתחילה, ולא בקריאה לפונקציות](#-38-require-modules-first-not-inside-functions)
+  [3.9 הגדירו כניסה מסודרת לספריה שלכם `#updated`](#-39-set-an-explicit-entry-point-to-a-modulefolder)
+  [3.10 השתמשו באופרטור `===`](#-310-use-the--operator)
+  [3.11 השתמשו ב-Async Await, המנעו מ-callbacks `#strategic`](#-311-use-async-await-avoid-callbacks)
+  [3.12 השתמשו בפונקציות חץ (=>)](#-312-use-arrow-function-expressions-)
+  [3.13 הימנעו מהשפעות צדדיות מחוץ לפונקציות `#new`](#-313-avoid-effects-outside-of-functions)
+ +
+ +
+ + 4. בדיקות ובקרת איכות (13) + + +  [4.1 לפחות, כיתבו בדיקות API לרכיבים השונים `#strategic`](#-41-at-the-very-least-write-api-component-testing)
+  [4.2 סווגו 3 חלקים במתן שם לכל בדיקה `#new`](#-42-include-3-parts-in-each-test-name)
+  [4.3 חלקו את הבדיקות לפי תבנית ה-AAA `#strategic`](#-43-structure-tests-by-the-aaa-pattern)
+  [4.4 וודאו כי גרסת ה-Node אחידה `#new`](#-44-ensure-node-version-is-unified)
+  [4.5 הימנעו מאתחול מידע גרעיני משותף, הגדירו לפי צורך של בדיקה `#strategic`](#-45-avoid-global-test-fixtures-and-seeds-add-data-per-test)
+  [4.6 תייגו את הבדיקות `#advanced`](#-46-tag-your-tests)
+  [4.7 בידקו את רמת כיסוי הבדיקות שלכם, זה יעזור לזהות דפוסי בדיקות שגויים](#-47-check-your-test-coverage-it-helps-to-identify-wrong-test-patterns)
+  [4.8 Use production-like environment for e2e testing](#-48-use-production-like-environment-for-e2e-testing)
+  [4.9 שכתבו את הקוד באופן קבוע בעזרת כלי ניתוח סטטי](#-49-refactor-regularly-using-static-analysis-tools)
+  [4.10 הדמיית תשובות של שרתי HTTP חיצוניים `#new` `#advanced`](#-410-mock-responses-of-external-http-services)
+  [4.11 בדקו את פונקציות הביניים בנפרד](#-411-test-your-middlewares-in-isolation)
+  [4.12 קבעו את הפורט בייצור, הגדירו אקראי לבדיקות `#new`](#-412-specify-a-port-in-production-randomize-in-testing)
+  [4.13 בידקו את חמשת התוצאות האפשריות `#strategic` `#new`](#-413-test-the-five-possible-outcomes)
+ +
+ +
+ + 5. עלייה לאוויר (19) + + +  [5.1. ניטור `#strategic`](#-51-monitoring)
+  [5.2. הגדילו את יכולת הצפייה בעזרת לוגים איכותיים `#strategic`](#-52-increase-the-observability-using-smart-logging)
+  [5.3. האצילו כל מה שאפשר (לדוגמה gzip, SSL) לשירות נפרד `#strategic`](#-53-delegate-anything-possible-eg-gzip-ssl-to-a-reverse-proxy)
+  [5.4. קיבוע תלויות](#-54-lock-dependencies)
+  [5.5. הבטיחו את זמינות המערכת בעזרת הכלי המתאים](#-55-guard-process-uptime-using-the-right-tool)
+  [5.6. השתמשו בכל מעבדי ה-CPU](#-56-utilize-all-cpu-cores)
+  [5.7. תיצרו ‘maintenance endpoint’](#-57-create-a-maintenance-endpoint)
+  [5.8. גלו את הלא ידוע בעזרת מוצרי APM `#advanced` `#updated`](#-58-discover-the-unknowns-using-apm-products)
+  [5.9. כתבו את הקוד מותאם להתקנה](#-59-make-your-code-production-ready)
+  [5.10. מדדו ושימרו את ניצול הזיכרון `#advanced`](#-510-measure-and-guard-the-memory-usage)
+  [5.11. Get your frontend assets out of Node](#-511-get-your-frontend-assets-out-of-node)
+  [5.12. Strive to be stateless `#strategic`](#-512-strive-to-be-stateless)
+  [5.13. Use tools that automatically detect vulnerabilities](#-513-use-tools-that-automatically-detect-vulnerabilities)
+  [5.14. Assign a transaction id to each log statement `#advanced`](#-514-assign-a-transaction-id-to-each-log-statement)
+  [5.15. Set NODE_ENV=production](#-515-set-node_envproduction)
+  [5.16. Design automated, atomic and zero-downtime deployments `#advanced`](#-516-design-automated-atomic-and-zero-downtime-deployments)
+  [5.17. Use an LTS release of Node.js](#-517-use-an-lts-release-of-nodejs)
+  [5.18. Log to stdout, avoid specifying log destination within the app](#-518-log-to-stdout-avoid-specifying-log-destination-within-the-app)
+  [5.19. Install your packages with npm ci `#new`](#-519-install-your-packages-with-npm-ci)
+ +
+ +
+ + 6. אבטחה (27) + + +  [6.1. Embrace linter security rules](#-61-embrace-linter-security-rules)
+  [6.2. Limit concurrent requests using a middleware](#-62-limit-concurrent-requests-using-a-middleware)
+  [6.3 Extract secrets from config files or use packages to encrypt them `#strategic`](#-63-extract-secrets-from-config-files-or-use-packages-to-encrypt-them)
+  [6.4. Prevent query injection vulnerabilities with ORM/ODM libraries `#strategic`](#-64-prevent-query-injection-vulnerabilities-with-ormodm-libraries)
+  [6.5. Collection of generic security best practices](#-65-collection-of-generic-security-best-practices)
+  [6.6. Adjust the HTTP response headers for enhanced security](#-66-adjust-the-http-response-headers-for-enhanced-security)
+  [6.7. Constantly and automatically inspect for vulnerable dependencies `#strategic`](#-67-constantly-and-automatically-inspect-for-vulnerable-dependencies)
+  [6.8. Protect Users' Passwords/Secrets using bcrypt or scrypt `#strategic`](#-68-protect-users-passwordssecrets-using-bcrypt-or-scrypt)
+  [6.9. Escape HTML, JS and CSS output](#-69-escape-html-js-and-css-output)
+  [6.10. Validate incoming JSON schemas `#strategic`](#-610-validate-incoming-json-schemas)
+  [6.11. Support blocklisting JWTs](#-611-support-blocklisting-jwts)
+  [6.12. Prevent brute-force attacks against authorization `#advanced`](#-612-prevent-brute-force-attacks-against-authorization)
+  [6.13. Run Node.js as non-root user](#-613-run-nodejs-as-non-root-user)
+  [6.14. Limit payload size using a reverse-proxy or a middleware](#-614-limit-payload-size-using-a-reverse-proxy-or-a-middleware)
+  [6.15. Avoid JavaScript eval statements](#-615-avoid-javascript-eval-statements)
+  [6.16. Prevent evil RegEx from overloading your single thread execution](#-616-prevent-evil-regex-from-overloading-your-single-thread-execution)
+  [6.17. Avoid module loading using a variable](#-617-avoid-module-loading-using-a-variable)
+  [6.18. Run unsafe code in a sandbox](#-618-run-unsafe-code-in-a-sandbox)
+  [6.19. Take extra care when working with child processes `#advanced`](#-619-take-extra-care-when-working-with-child-processes)
+  [6.20. Hide error details from clients](#-620-hide-error-details-from-clients)
+  [6.21. Configure 2FA for npm or Yarn `#strategic`](#-621-configure-2fa-for-npm-or-yarn)
+  [6.22. Modify session middleware settings](#-622-modify-session-middleware-settings)
+  [6.23. Avoid DOS attacks by explicitly setting when a process should crash `#advanced`](#-623-avoid-dos-attacks-by-explicitly-setting-when-a-process-should-crash)
+  [6.24. Prevent unsafe redirects](#-624-prevent-unsafe-redirects)
+  [6.25. Avoid publishing secrets to the npm registry](#-625-avoid-publishing-secrets-to-the-npm-registry)
+  [6.26. 6.26 Inspect for outdated packages](#-626-inspect-for-outdated-packages)
+  [6.27. Import built-in modules using the 'node:' protocol `#new`](#-627-import-built-in-modules-using-the-node-protocol)
+ +
+ +
+ + 7. ביצועים (2) (בתהליך ✍️) + + +  [7.1. Don't block the event loop](#-71-dont-block-the-event-loop)
+  [7.2. Prefer native JS methods over user-land utils like Lodash](#-72-prefer-native-js-methods-over-user-land-utils-like-lodash)
+ +
+ +
+ + 8. דוקר (15) + + +  [8.1 Use multi-stage builds for leaner and more secure Docker images `#strategic`](#-81-use-multi-stage-builds-for-leaner-and-more-secure-docker-images)
+  [8.2. Bootstrap using node command, avoid npm start](#-82-bootstrap-using-node-command-avoid-npm-start)
+  [8.3. Let the Docker runtime handle replication and uptime `#strategic`](#-83-let-the-docker-runtime-handle-replication-and-uptime)
+  [8.4. Use .dockerignore to prevent leaking secrets](#-84-use-dockerignore-to-prevent-leaking-secrets)
+  [8.5. Clean-up dependencies before production](#-85-clean-up-dependencies-before-production)
+  [8.6. Shutdown smartly and gracefully `#advanced`](#-86-shutdown-smartly-and-gracefully)
+  [8.7. Set memory limits using both Docker and v8 `#advanced` `#strategic`](#-87-set-memory-limits-using-both-docker-and-v8)
+  [8.8. Plan for efficient caching](#-88-plan-for-efficient-caching)
+  [8.9. Use explicit image reference, avoid latest tag](#-89-use-explicit-image-reference-avoid-latest-tag)
+  [8.10. Prefer smaller Docker base images](#-810-prefer-smaller-docker-base-images)
+  [8.11. Clean-out build-time secrets, avoid secrets in args `#strategic #new`](#-811-clean-out-build-time-secrets-avoid-secrets-in-args)
+  [8.12. Scan images for multi layers of vulnerabilities `#advanced`](#-812-scan-images-for-multi-layers-of-vulnerabilities)
+  [8.13 Clean NODE_MODULE cache](#-813-clean-node_module-cache)
+  [8.14. Generic Docker practices](#-814-generic-docker-practices)
+  [8.15. Lint your Dockerfile `#new`](#-815-lint-your-dockerfile)
+ +
+ +

+ +# `1. מבנה הפרוייקט` + +## ![✔] 1.1 בנו את הפרוייקט לפי רכיבים עסקיים + +**אמ;לק:** בסיס המערכת צריך לכלול תיקיות או מאגרים שמייצג בצורה הגיונית את המידול העסקי. כל רכיב מייצג תחום מוצר (כלומר הקשר מוגבל), למשל 'משתמשים', 'הזמנות', וכולי... כל רכיב מכיל את ה API, לוגיקה ומסד הנתונים שלו. מה המטרה של זה? כאשר יש סביבה עצמאית כל שינוי משפיע אך ורק על החלק הרלוונטי - העומס הנפשי, סיבוכיות הפיתוח והחשש מפריסה חדשה של הרכיב הרבה יותר קטן. כתוצאה מכך, מתכנתים יכולים לפתח הרבה יותר מהר. זה לא דורש בהכרח הפרדה פיזית ויכול להיות מושג גם בMonorepo או multi-repo. + +```bash +my-system +├─ apps (components) +│ ├─ orders +│ ├─ users +│ ├─ payments +├─ libraries (generic cross-component functionality) +│ ├─ logger +│ ├─ authenticator +``` + +**אחרת:** כאשר מוצרים של מודולים או נושאים שונים מעורבבים יחד, ישנו סיכוי גבוה שתיווצר מערכת ספגטי בעלת צימוד גבוה. לדוגמה, בארכיטקטורה שבה 'מודול א`' קורא לשירות מ'מודול ב;', אין הפרדה ברורהבין המודולים השונים - כל שינוי בקוד עלול להשפיע על משהו אחר. עם הגישה הזאת , מתכנתים שצריכים להוסיף מוצר חדש למערכת יאבקו בה בהבנה על מה השינוי שלהם יכול להשפיע. כתוצאה מכך, הם חששו לשבור מודולים אחרים, וכל פריסה נהייתה איטית יותר ומסוכנת יותר. + +🔗 [**לקריאה נוספת: בנייה לפי רכיבים**](./sections/projectstructre/breakintcomponents.md) + +

+ +## ![✔] 1.2 חלוקת הרכיבים ל3 שכבות, שמירה על שכבת הווב בגבולותיה + +**אמ;לק:** כל רכיב צריך לכלול 'שכבות' - תיקייה יעודית עם אחריות משותפת: 'entry-point' איפה שחלקי השליטה נמצאים, 'domain' איפה שהלוגיקה נמצאת ו 'data-access'. העיקרון המנחה של הארכיטקטורות המובילות בשוק הוא להפריד את האחריות הטכנית (למשל: HTTP, DB ועוד) מהלוגיקה היעודית של המוצר כך שהמתכנתים יוכלו לקודד יותר תכולות בלי לדאוג לגבי ניהול תשתיות. השמה של כל שכבה בתיקייה יעודית, שידועה גם כ-[מודל 3 השכבות](https://he.wikipedia.org/wiki/%D7%90%D7%A8%D7%9B%D7%99%D7%98%D7%A7%D7%98%D7%95%D7%A8%D7%94_%D7%A8%D7%91-%D7%A9%D7%9B%D7%91%D7%AA%D7%99%D7%AA#%D7%90%D7%A8%D7%9B%D7%99%D7%98%D7%A7%D7%98%D7%95%D7%A8%D7%AA_%D7%A9%D7%9C%D7%95%D7%A9_%D7%A9%D7%9B%D7%91%D7%95%D7%AA) ([באנגלית](https://en.wikipedia.org/wiki/Multitier_architecture#Three-tier_architecture)) זאת הדרך _הפשוטה_ להשיג את המטרה. + +```bash +my-system +├─ apps (components) +│ ├─ component-a + │ ├─ entry-points + │ │ ├─ api # controller comes here + │ │ ├─ message-queue # message consumer comes here + │ ├─ domain # features and flows: DTO, services, logic + │ ├─ data-access # DB calls w/o ORM +``` + +**אחרת:** לעתים דחופות נתקלים בכך שהמתכנתים מעבירים אובייקטי תקשורת כדוגמת request/reqponse לפונקציות בשכבות של הלוגיקה או ניהול המידע - דבר זה פוגע בעיקרון ההפרדה וגורם לכך שבעתיד יהיה קשה יותר להנגיש את הלוגיקה לסוגי קלינטים אחרים כדוגמת: בדיקות יחידה, משימות מתוזמנות וmessage queues. + +🔗 [**לקריאה נוספת: חלק את המוצר לשכבות**](./sections/projectstructre/createlayers.md) + +

+ +## ![✔] 1.3 עטפו כלים משותפים בחבילות, שקלו את הפצתם + +**אמ;לק:** מקמו את כל הכלים שאפשר לשתף אותם בתיקייה ייעודית, למשל 'libraries' וכל כלי בתיקייה פנימית נפרדת, למשל '/libraries/logger'. הפכו את הכלי לחבילה בלתי תלויה עם קובץ ה package.json שלו וזאת כדי להגדיל את הכימוס (encapsulation), ואפשרו הפצה עתידית למאגר. כאשר הפרוייקט שלכם בנוי בתצורת monorepo, כלים אלו יכולים להיות מוגדרים על ידי שימוש ב 'npm linking' לכתובת הפיזית שלהם על ידי שימוש ב ts-paths או על ידי הפצה והתקנה על ידימנהל חבילות כדוגמת 'npm registry'. + +```bash +my-system +├─ apps (components) + │ ├─ component-a +├─ libraries (generic cross-component functionality) +│ ├─ logger +│ │ ├─ package.json +│ │ ├─ src +│ │ │ ├─ index.js + +``` + +**אחרת:** צרכנים של כלי יהיו צמודים לפונקציונליות הפנימית שלו. על ידי הגדרה של package.json בשורש הכלי מישהו יכול להגדיר קובץ package.json.main או package.json.exports כדי להצהיר במפורש אילו קבצים ופונקציולניות היא חלק מהחלקים הנגישים של הכלי. + +🔗 [**לקריאה נוספת: בנייה לפי תכונה**](./sections/projectstructre/wraputilities.md) + +

+ +## ![✔] 1.4 השתמשו בקונפיגורציה עם משתני סביבה באופן מודע, מאובטח והיררכי + +**אמ;לק:** הגדרת סביבה מושלמת צריכה להבטיח כי (א) שמות משתנים יכולים להיקרא מקבצים כמו גם ממשתני סביבה (ב) סודות נשמרים מחוץ לקוד ששייך למאגר (ג) הקונפיגורציה היא היררכית לצורך חיפוש קל יותר (ד) תמיכה בסוגים שונים של משתנים (ה) וידוא מוקדם של משתנים לא תקינים (ו) הגדרת ברירת מחדל לכל שדה. ישנן מספר ספריות שעונות על רוב הדרישות הללו כמו [convict](https://www.npmjs.com/package/convict), [env-var](env-var), [zod](https://github.com/colinhacks/zod), ועוד... + +**אחרת:** נניח וישנו משתנה סביבה הכרחי שלא הוגדר, המערכת תתחיל לרוץ בהצלחה, תענה לבקשות, חלק מהמידע יעודכן במסד הנתונים, ולפתע יהיה חסר לה שדה הכרחי להמשך התהליך ושבלעדיו היא לא יכולה לסיים את הפעולה, מה שייצור מערכת במצב "מלוכלך". + +🔗 [**לקריאה נוספת: שיטות עבודה של קונפיגורציה**](./sections/projectstructre/configguide.md) + +

+ +## ![✔] 1.5 שקלו את כל ההשלכות בעת בחירת מסגרת + +**אמ;לק:** כאשר בונים אפליקציות ו API-ים, שימוש בפריימוורק הוא חובה. קל להתעלם מהאפשרויות השונות שקיימות ומשיקולים חשובים ובסופו של דבר להשתמש באפשרות שפחות תואמת לדרישות של המוצר. נכון ל2023/2024 אנו מאמינים כי ארבעת הפריימוורקים הללו הם הכדאיים ביותר להשוואה: [Nest.js](https://nestjs.com/), [Fastify](https://www.fastify.io/), [express](https://expressjs.com/), ו [Koa](https://koajs.com/). לחצו על לקריאה נוספת בהמשך כדי לקרוא פרטים נוספים בעד ונגד כל אחת מהאפשרויות. באופן פשטני, אנו מאמינים כי Node.js זאת ההתאמה הכי טובה לצוותים שרוצים לעבוד בשיטת OOP או לבנות מוצרים שמיועדים לגדול בצורה ניכרת ואי אפשר לחלק אותם לרכיבים קטנים _ועצמאיים_. ההמלצה שלנו היא Fastify עבור מערכות בגודל סבירents (כמו Microservices) שמושתתים על עקרונות פשוטים של Node.js. + +**אחרת:** בשל הכמות העצומה של השיקולים, קל לקבל החלטה על בסיס מידע חלקי ולהשוות תפוחים לתפוזים. למשל, ישנה הנחה רווחת שFastify הוא web-server מינימלי שראוי להשוות לexpress בלבד. בפועל, זהו פריימוורק עשיר עם הרבה הרחבות רשמיות שמכסות הרבה צרכים. + +🔗 [**לקריאה נוספת: בחירת הפריימוורק הנכון**](./sections/projectstructre/choose-framework.md) + +## ![✔] 1.6 השתמשו ב-TypeScript במידתיות ובצורה מושכלת + +**אמ;לק:** קידוד ללא מקדמי בטיחות של סיווג משתנים הוא כבר לא אפשרות בת קיימא, TypeScript מהווה את האפשרות הפופולרית ביותר למשימה זו. משתמשים בה להגדרת סוגי משתנים וערכי החזרה של פונקציות. עם זאת, זוהי חרב פיפיות שיכולה בקלות ליצור מורכבות בשל בסביבות 50 מילות מפתח נוספות שיש לה ותכונות מתוחכמות שצריך לדעת להשתמש בהן. שימוש בה צריך להיעשות במידה, בעדיפות להגדרות פשוטות של משתנים, ושימוש ביכולות מתקדמות רק כאשר צורך הכרחי מופיע. + +**אחרת:** [מחקרים](https://earlbarr.com/publications/typestudy.pdf) מראים כי שימוש ב-TypeScript יכול לעזור בזיהוי כ20% מהבאגים בשלבים מוקדמים יותר. ללא TypeScript חווית הפיתוח ב IDE נהיית בלתי נסבלת. מהצד השני, 80% מהבאגים היא לא עוזרת לזהות. כתוצאה מכך, שימוש בTypeScript מוסיף ערך מוגבל. רק הוספה של בדיקות איכותיות יכולה לעזור לזהות את מגוון הבאגים הרחב, כולל כאלו שנגרמים מאפיון לא תקין של סוג המשתנה. שימוש לא טוב גם עלול להרוג את המטרה, תכונות מורכבות של קוד מעלות אתמורכבות הקוד מה שבאופן ישיר מעלה את מספר הבאגים וזמן התיקון של כל באג. + +🔗 [**לקריאה נוספת: שיקולים לשימוש ב-TypeScript**](./sections/projectstructre/typescript-considerations.md) + +


+ +

⬆ חזרה למעלה

+ +# `2. ניהול שגיאות` + +## ![✔] 2.1 השתמשו ב Async-Await או הבטחות לניהול שגיאות אסינכרוניות + +**אמ;לק:** ניהול שגיאות אסינכרוניות על ידי שימוש ב-callbacks זו הדרך המהירה לגהינום (הידועה בשם [פירמידת דום](https://en.wikipedia.org/wiki/Pyramid_of_doom_(programming))). המתנה הטובה ביותר שאפשר לתת לקוד הוא שימוש ב-promises בסגנון async-await דבר שמאפשר קוד הרבה יותר נקי ומסודר וסינטקס דומה ל try-catch. + +**אחרת:** סגנון הכתיבה `function(err, response)` הכולל שימוש ב-callbacks של Node.js, סולל דרך בטוחה לקוד שאי אפשר לתחזק בשל הערבוב בין ניהול שגיאות לניהול התהליך התקני של המערכת, עם קינון מוגזם וסגנון קוד מוזר. + +🔗 [**לקריאה נוספת: הימנעות מ-callbacks**](./sections/errorhandling/asyncerrorhandling.md) + +

+ +## ![✔] 2.2 הרחיבו את מבנה אוביקט השגיאה המובנה `Error` + +**אמ;לק:** ישנן ספריות שזורקות שגיאה כמחרוזת או כאובייקט פרי מחשבת כותבי הקוד של הספריה - דבר שיוצר מורכבות בניהול השגיאות וביצירת מכנה משותף בין מודולים שונים. במקום זאת, השקיעו ביצירת אובייקט או מחלקת (class) שגיאה שיורשת מאובייקט השגיאה המובנה של השפה והשתמשו בזה בכל פעם שצריך לדחות את המצב, לזרוק שגיאה או להפיץ שגיאה. השגיאה האפליקטיבית צריכה להוסיף שדות נוספים כדוגמת שם השגיאה ורמת החומרה שלה. על ידי כך, לכל השגיאות ישנו מבנה אחיד והן מאפשרות תמיכה טובה יותר בניהול שגיאות. ישנו כלל של `no-throw-literal` ESLint שבודק בצורה מיטבית את השימוש הזה (על אף שיש לזה קצת [מגבלות](https://eslint.org/docs/rules/no-throw-literal) שיכולות להסתדר על ידי שימוש ב-TypeScript והגדרת החוק `@typescript-eslint/no-throw-literal`) + +**אחרת:** כאשר מפעילים רכיב כלשהו, אם ישנה אי וודאות איזה סוג של שגיאה יגיע - זה גורם לכך שניהול השגיאות יהיה הרבה יותר מורכב. גרוע מכך, שימוש באובייקטים מומצאים לתיאור שגיאות עלול להוביל לאיבוד של שגיאות קריטיות בעלות מידע חשוב כמו מעקב אחר מקור השגיאה! + +🔗 [**לקריאה נוספת: שימוש באובייקט השגיאה המובנה**](./sections/errorhandling/useonlythebuiltinerror.md) + +

+ +## ![✔] 2.3 הבחינו בין שגיאות קטסטרופליות לבין שגיאות תפעוליות + +**אמ;לק:** שגיאות תפעוליות (למשל קלט לא תקין בפנייה ל-API) מתייחסות למקרים ידועים בהם ההשפעה של השגיאה מובנת לחלוטין ויכולה להיות מנוהלת בצורה מחושבת. מצד שני, שגיאות קטסטרופליות (ידועות גם כשגיאות תכנות) מתייחסות לשגיאות לא צפויות במערכת שדורשות אתחול בטוח שלה. + +**אחרת:** אתם עלולים לאתחל את המערכת בעקבות כל שגיאה. אבל למה לגרום לכ-5000 משתמשים לחוות התנתקות בגלל שגיאה תפעולית צפויה ושולית? ההיפך הוא גם לא אידיאלי - להשאיר את המערכת עובדת כאשר קטסטרופה לא צפויה קרתה בה והיא עלולה לגרור התנהגות בלתי צפויה. הבדלה בין שני המקרים מאפשרת התמודדות מושכלת ומאוזנת בהתאם להקשר. + +🔗 [**לקריאה נוספת: שגיאות תפעוליות מול שגיאות תכנות**](./sections/errorhandling/operationalvsprogrammererror.md) + +

+ +## ![✔] 2.4 נהלו את השגיאות במרוכז ולא באמצעות כלי ביניים + +**אמ;לק:** מימוש הניהול של השגיאות כמו למשל תעוד השגיאה, החלטה אם לקרוס ואילו מדדים לנטר צריך להיות מרוכז במקום אחד שכל הכניסות למערכת (למשל APIs, cron jobs, scheduled jobs) משתמשות בו כאשר חלה בהן שגיאה. + +**אחרת:** אם לא מנהלים את השגיאות במקום אחד אז במהרה יהיה שכפול קוד וכנראה ניהול לא תקין של חלק מהשגיאות. + +🔗 [**לקריאה נוספת: ניהול השגיאות במקום מרוכז**](./sections/errorhandling/centralizedhandling.md) + +

+ +## ![✔] 2.5 תעדו את שגיאות ה-API באמצעות OpenAPI או GraphQL + +**אמ;לק:** אפשרו למשתמשי ה-API שלכם לדעת אילו שגיאות עלולות להגיע כתשובה, כך שהם יוכלו להתמודד איתן בצורה מושכלת במקום לקרוס. ל-API מבוסס REST זה נעשה בדרך כלל באמצעות כלי תעוד כמו OpenAPI. אם אתם משתמשים ב-GraphQL, אתם יכולים להשתמש בסכמה ובהערות בשביל להשיג את המטרה. + +**אחרת:** מי שמשתמש ב-API שלנו עלול להחליט לגרום למערכת שלו לקרוס ולאתחל את עצמה רק בגלל שהוא קיבל שגיאה שהוא לא הצליח להבין. שימו לב: המשתמש של ה-API שלכם יכול להיות אתם (מה שקורה הרבה כשמשתמשים במיקרוסרוויסים). + +🔗 [**לקריאה נוספת: תיעוד שגיאות ה-API באמצעות OpenAPI או GraphQL**](./sections/errorhandling/documentingusingswagger.md) + +

+ +## ![✔] 2.6 הורידו את התהליך בצורה מסודרת כאשר זר בא לבקר + +**אמ;לק:** כאשר שגיאה לא ידועה חלה (שגיאה קטסטרופלית, ראו תובנה 2.3) - ישנה חוסר ודאות לגבי הבריאות והיציבות של המערכת. במקרה כזה, אין דרך לברוח מלגרום לשגיאה להיות ברת צפייה, סגירת חיבוריות לרכיבים נוספים והורדה של התהליך. כל סביבת ריצה מהימנה כדוגמת שירותי Docker או שירותי ענן שמספקים פתרונות ללא שרת (serverless) יוודאו שהתהליך יעלה מחדש עבורכם. + +**אחרת:** כאשר שגיאה לא צפויה קורית, רכיב כלשהו עלול להיות במצב לא תקין (למשל event emitter גלובאלי שמפסיק להפיץ אירועים בשל כשלון פנימי) והחל מעכשיו שאר הבקשות שמשתמשות ברכיב זה עלולות להיכשל או להתנהג באופן ממש לא צפוי. + +🔗 [**לקריאה נוספת: הורדת התהליך**](./sections/errorhandling/shuttingtheprocess.md) + +

+ +## ![✔] 2.7 השתמשו ב-Logger מוכר ואמין כדי להגדיל את הקְרִיאוּת של השגיאות + +**אמ;לק:** כלי לוגים איכותי כדוגמת [Pino](https://github.com/pinojs/pino) או [Winston](https://github.com/winstonjs/winston) מגדיל את הקריאות וההבנה של הלוגים על ידי שימוש ברמת חומרה, עימוד, עיצוב, צבעים ועוד. ל-`console.log` אין את היכולות הללו וראוי להימנע משימוש בו. העיפרון החד ביותר בתחום מאפשר הוספה של שדות שימושיים נוספים ללא תקורה גבוהה של ביצועים. מפתחים צריכים לכתוב את הלוגים ל-`stdout` ולתת לתשתית להעביר את המידע לכלי המתאים עבור כל מקרה. + +**אחרת:** רפרוף על שורות console.log או בצורה ידנית על קבצי טקסט עמוסים לעייפה ללא כלי חיפוש ותצוגה מותאמים עלולים להשאיר אתכם לעבוד עד השעות הקטנות של הלילה. + +🔗 [**לקריאה נוספת: שימוש ב-Logger אמין**](./sections/errorhandling/usematurelogger.md) + +

+ +## ![✔] 2.8 בידקו את תגובת המערכת לשגיאות על ידי שימוש בכלי הבדיקות האהוב עליכם + +**אמ;לק:** בין אם יש לכם כלי QA אוטומטי ומקצועי ובין אם אחד המפתחים מבצע את הבדיקות - ודאו כי לא רק המסלול הבטוח של הקוד מכוסה, אלא גם ניהול השגיאות ושחוזרות השגיאות שאמורות לחזור במקרה של תקלה. נוסף על כך, בידקו מקרים מורכבים יותר של שגיאות, כמו למשל שגיאות בלתי צפויות, כדי לוודא שהרכיב שמטפל בשגיאות מבצע זאת כראוי (ראו דוגמאות קוד בקישור "לקריאה נוספת") + +**אחרת:** ללא בדיקות כלל, לא ידניות ולא אוטומטיות, לא תוכלו לסמוך על הקוד שלכם שיחזיר את השגיאה הנכונה. ללא שגיאות משמעותיות לא תוכלו לטפל בשגיאות. + +🔗 [**לקריאה נוספת: בדיקת התנהגות בעת שגיאה**](./sections/errorhandling/testingerrorflows.md) + +

+ +## ![✔] 2.9 גלו שגיאות וזמני השבתה על ידי שימוש בכלי APM + +**אמ;לק:** כלי ניטור ובדיקת ביצועים (מוכרים כ-APM) מודדים באופן יזום את הקוד או ה-API כך שבאופן קסום הם מציגים שגיאות, התרסקויות וחלקים שעובדים לאט מהצפוי ואתם לא שמים לב אליהם. + +**אחרת:** אתם עלולים להתאמץ רבות במדידה של בעיות ביצועים וזמני השבתה של המערכת, כנראה שלעולם לא תהיו מודעים לאיזה חלקים במערכת הם האיטיים ביותר ואיך זה משפיע על חווית המשתמש. + +🔗 [**לקריאה נוספת: שימוש ב-APM**](./sections/errorhandling/apmproducts.md) + +

+ +## ![✔] 2.10 תפסו מקרים לא מטופלים של דחיות של הבטחות + +**אמ;לק:** כל שגיאה או דחייה שחוזרת מהבטחה תיבלע, אלא אם כן בשלב הפיתוח יטפלו בה כמו שצריך. אפילו אם יש בקוד האזנה ל `process.uncaughtException`! כדי להתגבר על זה צריך להאזין גם ל `process.unhandledRejection`. + +**אחרת:** השגיאות במערכת יבלעו ויעלמו ללא עקבות. לא משהו שצריך לדאוג ממנו... + +🔗 [**לקריאה נוספת: תפיסה של דחיות של הבטחות**](./sections/errorhandling/catchunhandledpromiserejection.md) + +

+ +## ![✔] 2.11 היכשלו מהר, ודאו את משתני הקלט באמצעות ספריה יעודית + +**אמ;לק:** הגדירו תבנית קלט קשיחה ל-API כדי להימנע מבאגים מלוכלכים שקשה הרבה יותר לעקוב אחריהם. כתיבת קוד האימות הוא תהליך מייגע, אלא אם כן תשתמשו באחת הספריות המוכרות כיום כמו [ajv](https://www.npmjs.com/package/ajv), [zod](https://github.com/colinhacks/zod), או [typebox](https://github.com/sinclairzx81/typebox). + +**אחרת:** חשבו על זה - הפונקציה שלכם מצפה לקבל כקלט משתנה `discount` מספרי שמי שקרה לפונקציה שכח להעביר. בהמשך, הקוד בודק אם `discount != 0` (כמות ההנחה שאפשר לקבל גדולה מאפס), ואם כן אז המשתמש יהנה מההנחה. וואו, זה באג מלוכלך, ראיתם??? + +🔗 [**לקריאה נוספת: כשלון מהיר**](./sections/errorhandling/failfast.md) + +

+ +## ![✔] 2.12 תמיד המתינו לתשובה מההבטחות לפני שאתם מעבירים את התשובה הלאה כדי להימנע ממעקב חלקי + +**אמ;לק:** תמיד כתבו `return await` כאשר מחזירים תוצאה של הבטחה וזאת כדי להשיג ערך מלא של מעקב אחר מקור השגיאה (stacktrace). אם פונקציה מחזירה הבטחה היא חייבת להיות מוגדרת כפונקציה אסינכרונית ובמפורש לחכות להבטחה שהיא מחזירה. + +```js +async function promisifyFunction() { + // some logic + return await new Promise(...); +} +``` + +**אחרת:** הפונקציה שמחזירה הבטחה ללא המתנה לא תופיע בנתיב המעקב אחרי השגיאה (stacktrace). חוסרים כאלו עלולים לסבך את ההבנה של זרימת המערכת שגרמה לשגיאה, במיוחד אם הגורם להתנהגות הלא צפויה קרה בפונקציה החסרה. + +🔗 [**לקריאה נוספת: החזרת הבטחות**](./sections/errorhandling/returningpromises.md) + +


+ +

⬆ חזרה למעלה

+ +# `3. תבניות קוד וסגנון עיצוב` + +## ![✔] 3.1 השתמשו ב-ESLint + +**אמ;לק:** [ESLint](https://eslint.org) הוא הסטנדרט דה-פקטו למציאת שגיאות בקוד ותיקון של סגנונות קוד, לא רק זיהוי של רווח סורר שעלול ליצור תקלה אלא גם זיהוי של קוד שלא עומד בסטנדרטים (anti-pattern) כמו זריקת שגיאות ללא סיווג. אמנם ESLint יכול לתקן באופן אוטומטי סגנונות קוד, אך כלים אחרים כדוגמת [prettier](https://www.npmjs.com/package/prettier) טובים יותר בעיצוב וסגנון הקוד ועובדים בשילוב עם ESLint. + +**אחרת:** מפתחים ישתעממו תוך כדי השקעת זמנם במציאת רווחים סוררים וידאגו לאורך השורה והזמן היקר שלהם יבוזבז על איך לשמור על סגנון הקוד של הפרוייקט. + +🔗 [**לקריאה נוספת: שימוש ב-ESLint ו-Prettier**](./sections/codestylepractices/eslint_prettier.md) + +

+ +## ![✔] 3.2 השתמשו בתוספים של Node.js שמרחיבים את ESLint + +**אמ;לק:** על גבי הסטנדרט של חוקי ESLint שמכסים את שפת JavaScript, הוסיפו את התוספים היעודיים של Node.js כמו [eslint-plugin-node](https://www.npmjs.com/package/eslint-plugin-node), [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha), [eslint-plugin-node-security](https://www.npmjs.com/package/eslint-plugin-security), [eslint-plugin-require](https://www.npmjs.com/package/eslint-plugin-require), [eslint-plugin-jest](https://www.npmjs.com/package/eslint-plugin-jest) ועוד תוספים שמממשים חוקים נוספים ומועילים. + +**אחרת:** הרבה תבניות קוד לא תקינות שבשימוש ב-Node.js נעלמות מתחת לרדאד. לדוגמה, מפתחים יכתבו `require(variableAsPath)` עם משתנה שמאפשר גישה לתיקיה בקוד, דבר שמאפשר לתוקפים להריץ כל קוד JS. אם תשתמשו בחוקי Node.js תוכלו לזהות את הטעות הזאת ולקבל עליה התראה מבעוד מועד. + +

+ +## ![✔] 3.3 התחילו בלוק של קוד עם סוגריים מסולסלים באותה השורה + +**אמ;לק:** מומלץ שהסוגריים המסולסלים הפותחים של בלוק של קוד יהיו באותה השורה יחד עם הקוד. + +### דוגמה + +```javascript +// Do +function someFunction() { + // code block +} + +// Avoid +function someFunction() +{ + // code block +} +``` + +**אחרת:** התעלמות משיטת עבודה זו עלולה להוביל לתוצאות לא צפויות, כמו שניתן לראות בשרשור בקישור מ StackOverflow: + +🔗 [**לקריאה נוספת:** "למה התוצאות משתנות בהתאם למיקום הסוגר המסולסל?" (StackOverflow)](https://stackoverflow.com/questions/3641519/why-does-a-results-vary-based-on-curly-brace-placement) + +

+ +## ![✔] 3.4 הפרידו בין ההצהרות השונות בצורה תקנית + +בין אם אתם משתמשים בנקודה-פסיק (;) בשביל להפריד בין ההצהרות על המשתנים ובין אם לא, עצם הידיעה על ההשלכות של ירידת שורה במקום הלא מתאים או של הוספה אוטומטית של נקודה-פסיק, יעזרו לכם לזהות שגיאות סינטקס רגילות. + +**אמ;לק:** שימוש ב-ESLint כדי להעלות את המודעות לגבי הסיכון הכרוך בזה. כלים כמו [Prettier](https://prettier.io/) או [Standardjs](https://standardjs.com/) יכולים באופן אוטומטי לפתור את הבעיות הללו. + +**אחרת:** כמו שראינו בסעיף הקודם, "המתורגמן" (interpreter) של JavaScript מוסיף אוטומטית נקודה-פסיק בסוף כל הצהרה במידה ואין, או שהוא מחליט כי ההצהרה מסתיימת במקום אחר מהמתוכנן על ידינו, דבר שעלול להוביל לתוצאות בלתי צפויות. אפשר להשתמש בהשמות ולהימנע מ [IIFE](https://developer.mozilla.org/en-US/docs/Glossary/IIFE) כדי להימנע מרוב ההתנהגויות הבלתי צפויות. + +### דוגמה + +```javascript +// Do +function doThing() { + // ... +} + +doThing() + +// Do + +const items = [1, 2, 3] +items.forEach(console.log) + +// Avoid — throws exception +const m = new Map() +const a = [1,2,3] +[...m.values()].forEach(console.log) +> [...m.values()].forEach(console.log) +> ^^^ +> SyntaxError: Unexpected token ... + +// Avoid — throws exception +const count = 2 // it tries to run 2(), but 2 is not a function +(function doSomething() { + // do something amazing +}()) +// put a semicolon before the immediate invoked function, after the const definition, save the return value of the anonymous function to a variable or avoid IIFEs altogether +``` + +🔗 [**לקריאה נוספת:** "Semi ESLint rule"](https://eslint.org/docs/rules/semi) +
+🔗 [**לקריאה נוספת:** "No unexpected multiline ESLint rule"](https://eslint.org/docs/rules/no-unexpected-multiline) + +

+ +## ![✔] 3.5 תנו לפונקציה שם + +**אמ;לק:** תנו שמות לכל הפונקציות, כולל closures ו-callbacks. הימנעו מפונקציות אנונימיות. זה מאוד שימושי כשבודקים אפליקציות Node.js. מתן שמות לכל הפונקציות יאפשר לכם להבין בקלות על מה אתם מסתכלים כשאתם צופים בתמונת מצב של הזיכרון של האפליקציה. + +**אחרת:** לדבג את גרסת היצור (production) על בסיס תמונת מצב של הזיכרון (core dump) עלול להיות מאתגר כשהבעיות של הזיכרון קורות בכל מיני פונקציות אנונימיות. + +

+ +## ![✔] 3.6 השתמשו במוסכמות קבועות במתן שמות למשתנים, לקבועים, לפונקציות ולמחלקות + +**אמ;לק:** השתמשו ב-**_lowerCamelCase_** כאשר אתם נותנים שמות לקבועים, משתנים ופונקציות, **_UpperCamelCase_** (גם האות הראשונה גדולה) כאשר אתם נותנים שמות למחלקות ו-**_UPPER_SNAKE_CASE_** כאשר אתם נותנים שמות למשתנים גלובליים או סטטיים. סדר זה יאפשר לכם להבחין בקלות בין משתנים רגילים ופונקציות לבין מחלקות שדורשות אתחול ולבין משתנים גלובליים. השתמשו בשמות שמתארים היטב את משמעות המשתנה, אך שיהיה קצר. + +**אחרת:** JavaScript היא השפה היחידה בעולם שתאפשר לכם לקרוא ל-constructor ("Class") ישירות ללא אתחול. לכן, חשוב מאוד להבדיל בין שמות מחלקות ושמות פונקציות על ידי שימוש ב-UpperCamelCase. + +### דוגמאות + +```javascript +// for global variables names we use the const/let keyword and UPPER_SNAKE_CASE +let MUTABLE_GLOBAL = "mutable value"; +const GLOBAL_CONSTANT = "immutable value"; +const CONFIG = { + key: "value", +}; + +// examples of UPPER_SNAKE_CASE convention in nodejs/javascript ecosystem +// in javascript Math.PI module +const PI = 3.141592653589793; + +// https://github.com/nodejs/node/blob/b9f36062d7b5c5039498e98d2f2c180dca2a7065/lib/internal/http2/core.js#L303 +// in nodejs http2 module +const HTTP_STATUS_OK = 200; +const HTTP_STATUS_CREATED = 201; + +// for class name we use UpperCamelCase +class SomeClassExample { + // for static class properties we use UPPER_SNAKE_CASE + static STATIC_PROPERTY = "value"; +} + +// for functions names we use lowerCamelCase +function doSomething() { + // for scoped variable names we use the const/let keyword and lowerCamelCase + const someConstExample = "immutable value"; + let someMutableExample = "mutable value"; +} +``` + +

+ +## ![✔] 3.7 העדיפו const על פני let. ניטשו את var + +**אמ;לק:** שימוש ב-`const` משמעותו היא שלאחר שהמשתנה מאותחל לראשונה הוא לא יכול להיות מאותחל שוב. העדפת שימוש ב-`const` תעזור לכם לא להתפתות ולהשתמש שוב באותו משתנה לצרכים שונים ותהפוך את הקוד שלכם לקריא יותר. אם משתנה צריך להיות מאותחל מחדש, למשל בתוך לולאת for, אז השתמשו ב-`let` לצורך כך. נקודה נוספת שחשוב לציין היא ששימוש ב-`let` אפשרית רק בתוך אותו הבלוק שהיא הוגדרה בו. `var` נצמד לscope של הפונקציה שהוא מוגדר בו ולא לבלוק ספציפי ולכן [צריך לא להשתמש בו ב-ES6](https://hackernoon.com/why-you-shouldnt-use-var-anymore-f109a58b9b70) כשאפשר להשתמש ב-`const` וב-`let`. + +**אחרת:** דיבוג הופך להיות מאוד מסורבל כאשר משתנה משתנה לעיתים דחופות. + +🔗 [**לקריאה נוספת: JavaScript ES6+: var, let, or const?** ](https://medium.com/javascript-scene/javascript-es6-var-let-or-const-ba58b8dcde75) + +

+ +## ![✔] 3.8 טענו מודולים בתחילה, ולא בקריאה לפונקציות + +**אמ;לק:** טענו את המודולים (require...) בתחילת כל קובץ, לפני כל הפונקציות. שיטת עבודה פשוטה זו לא רק שתעזור לכם בקלות ובמהירות לזהות את התלויות של קובץ מסוים, אלא גם תמנע מספר בעיות אפשריות. + +**אחרת:** טעינת מודולים היא תהליך סינכרוני ב-Node.js. אם הטעינה תתבצע מתוך פונקציה היא עלולה לחסום טיפול בבקשות אחרות בזמן קריטי. בנוסף לכך, אם מודול חיוני או מישהו שהוא תלוי בו יזרקו שגיאה ויפילו את השרת, מומלץ שזה יוודע כמה שיותר מוקדם, מה שלא בטוח יקרה במקרה שהמודול נטען מתוך פונקציה. + +

+ +## ![✔] 3.9 הגדירו כניסה מסודרת לספריה שלכם + +**אמ;לק:** בעת פיתוח מודול או ספריה, הגדירו קובץ בסיס שמייצא את הקוד המיועד לשימוש חיצוני. מנעו מהמשתמשים של הקוד שלכם את הצורך לייבא קבצים שיושבים עמוק אצלכם ואת הצורך שלהם להבין את מבנה הקבצים שלכם. כאשר עובדים בשיטת commonjs (require), זה יכול להיעשות על ידי שימוש בקובץ index.js שיושב בתיקיה הראשית או בהגדרת השדה main בקובץ package.json. כאשר עובדים בשיטת ESM (import), אם קובץ package.json קיים בתיקיה הראשית, אז השדה "exports" מאפשר את הגדרת הקובץ הראשי. אך אם אין קובץ package.json, אז שימוש בקובץ index.js בתיקיה הראשית ייצא את כל הפונקציונליות שמיועדת לשימוש חיצוני. + +**אחרת:** קיומו של קובץ ראשי רשמי משמש כממשק חיצוני שמסתיר את החלקים הפנימיים של הספריה, מקשר את המשתמש ישירות לקוד הזמין ומאפשר שינויים עתידיים ללא צורך לשבוראת החוזה. + +### דוגמה + +```javascript +// Avoid: client has deep familiarity with the internals + +// Client code +const SMSWithMedia = require("./SMSProvider/providers/media/media-provider.js"); + +// Better: explicitly export the public functions + +//index.js, module code +module.exports.SMSWithMedia = require("./SMSProvider/providers/media/media-provider.js"); + +// Client code +const { SMSWithMedia } = require("./SMSProvider"); +``` + +

+ +## ![✔] 3.10 השתמשו באופרטור `===` + +**אמ;לק:** העדיפו את ההשוואה הקפדנית באמצעות האופרטור `===` על פני ההשוואה החלשה יותר באמצעות האופרטור `==`. `==` משווה שני משתנים אחרי המרה של שניהם לסוג משתנה אחד. אין המרת סוגי משתנים באופרטור `===`, ושני המשתנים חייבים להיות מאותו סוג כדי שיוכלו להיות שווים. + +**אחרת:** משתנים בעלי ערכים שונים עלולים להחזיר `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, המנעו מ-callbacks + +**אמ;לק:** async-await זו הדרך הפשוטה ביותר לכתוב קוד אסינכרוני שירגיש כמו קוד סינכרוני. הקוד שיכתב בשיטת async-await הוא גם הרבה יותר פשוט ותומך במנגנון ה-try-catch. שיטה זו מחליפה את הצורך ב-callbacks ו-promises ברוב המקרים. שימוש בשיטה זו בקוד היא כנראה אחת המתנות הטובות יותר שאפשר לתת למי שיקרא את הקוד. + +**אחרת:** טיפול בשגיאות אסינכרוניות בשיטת callback היא כנראה הדרך המהירה לגהנום - מכיוון ששיטה זו מחייבת בדיקת שגיאות בכל שלב, יוצרת קינון מוזר בקוד ומקשה על הבנת תהליך הזרימה של הקוד. + +🔗[**לקריאה נוספת:** מדריך ל-async-await](https://github.com/yortus/asyncawait) + +

+ +## ![✔] 3.12 השתמשו בפונקציות חץ (=>) + +**אמ;לק:** אמנם מומלץ להשתמש ב async-await ולהימנע מהגדרת פרמטרים בפונקציות כאשר מתעסקים עם API ישן שתומך ב-callbacks או הבטחות - פונקציות חץ מאפשרות לארגן את הקוד קומפקטי יותר וכמובן ששומרות על הקונטקסט של פונקצית המעטפת (`this`). + +**אחרת:** קוד ארוך יותר (על בסיס פונקציות של ES5) חשוף ליותר באגים וקשה יותר לקריאה. + +🔗 [**לקריאה נוספת: הגיע הזמן לאמץ את פונקציות החץ**](https://medium.com/javascript-scene/familiarity-bias-is-holding-you-back-its-time-to-embrace-arrow-functions-3d37e1a9bb75) + +

+ +## ![✔] 3.13 הימנעו מהשפעות צדדיות מחוץ לפונקציות + +**אמ;לק:** הימנעו מכתיבת קוד עם השפעות צדדיות כמו פעולת רשת או פניה למסד נתונים מחוץ לפונקציה. אם כן תכתבו קוד כזה הוא ירוץ מיד כאשר קובץ אחר פונה לקובץ הזה. הקוד 'הצף' הזה עלול לרוץ כאשר התשתית אותה הוא מבקש עוד לא זמינה עבורו. זה גם פוגע בביצועים אפילו אם אין צורך בפונקציה שעבורה מתבצעת הפעולה בזמן הריצה. דבר אחרון, כתיבת כיסוי לפעולה זו בשביל בדיקות הרבה יותר מורכבת כשהיא לא נעשית בפונקציה. במקום זאת, שימו את הקוד הזה בפונקציה שצריכה להיקרא במפורש. אם הקוד הזה צריך להיקרא ישר בעת עליית המערכת, שיקלו שימוש ב-factory או בתבנית אחרת שמתאימה לדרישה כזאת. + +**אחרת:** תשתיות סטנדרטיות בעולם הווב מגדירות ניהול שגיאות, משתני סביבה וניטור תקלות. אם הפעולה תתבצע לפני שהתשתית מאותחלת אז לא יהיה ניטור של המקרה או שהפעולה תיכשל בשל חוסר בהגדרות שטרם נטענו. + +


+ +

⬆ חזרה למעלה

+ +# `4. בדיקות ובקרת איכות` + +> יש לנו מדריכים יעודיים לכתיבת בדיקות. רשימת שיטות העבודה המומלצות פה היא סיכום כללי של המדריכים הללו. +> +> א. [שיטות עבודה מומלצות בכתיבת בדיקות ל-JavaScript](https://github.com/goldbergyoni/javascript-testing-best-practices)
+> ב. [בדיקות ב-Node.js - מעבר ליסודות](https://github.com/testjavascript/nodejs-integration-tests-best-practices) + + +## ![✔] 4.1 לפחות, כיתבו בדיקות API לרכיבים השונים + +**אמ;לק:** ברוב הפרויקטים אין בדיקות אוטומטיות כלל בשל לוח זמנים קצר, או שהתחילו לנסות להוסיף בדיקות בפרויקט נוסף אך זה יצא משליטה וננטש עם הזמן. לכן, לתעדף ולהתחיל בדיקות API שזאת הדרך הקלה לכתוב בדיקות ולספק כיסוי (בדיקות) של הקוד מאשר בבדיקות יחידה של פונקציות בודדות (אפשר להשתמש בשביל זה גם בכלים חיצוניים ללא כתיבת קוד, למשל שימוש ב-[Postman](https://www.getpostman.com/)). לאחר מכן, אם יש לכם יותר משאבים וזמן תמשיכו עם בדיקות מתקדמות יותר כגון בדיקות יחידה, בדיקות מול מסדי הנתונים בדיקות ביצועים ועוד. + +**אחרת:** אתם עלולים לבזבז ימים שלמים על כתיבת בדיקות יחידה בלבד ולגלות בסופו של דבר שכיסיתם רק 20% מהמערכת. + +

+ +## ![✔] 4.2 סווגו 3 חלקים במתן שם לכל בדיקה + +**אמ;לק:** גירמו לבדיקה לתאר את שלב הדרישות כך שהיא תסביר את עצמה גם לQA או לאחרים (כולל אתכם בעתיד הלא רחוק) שלא בקיאים בחלקים הפנימיים של הקוד. ציינו בבדיקה (1) איזה חלק נבדק, (2) באילו תנאים (3) ומה התוצאה שמצפים שתחול. + +**אחרת:** ההתקנה בדיוק נכשלה, בדיקה בשם “Add product” נכשלה. האם זה מתאר מה בדיוק לא תיפקד? + +🔗 [**לקריאה נוספת: סווגו 3 חלקים במתן שם לכל בדיקה**](./sections/testingandquality/3-parts-in-name.md) + +

+ +## ![✔] 4.3 חלקו את הבדיקות לפי תבנית ה-AAA + +**אמ;לק:** חלקו את הבדיקות לשלושה חלקים נפרדים: Arrange (ארגן), Act (פעל) & Assert (ודא) (AAA). החלק הראשון כולל את ההכנה של הסביבה לבדיקה, החלק השני את ההרצה במצב בדיקות, ולבסוף החלק שמוודא שהתקבלה התוצאה הרצויה. שימוש במבנה זה בעקביות מבטיח שהקורא לא יבזבז זמן מחשבה של הבנת הבדיקה. + +**אחרת:** לא מספיק שיתבזבז זמן נרחב מהיום על הבנת הקוד, עכשיו גם החלק הקל ביום (הבנת הבדיקות) ישרוף את המוח. + +🔗 [**לקריאה נוספת: חלקו את הבדיקות לפי תבנית ה-AAA**](./sections/testingandquality/aaa.md) + +

+ +## ![✔] 4.4 וודאו כי גרסת ה-Node אחידה + +**אמ;לק:** השתמשו בכלים המעודדים או אוכפים שימוש באותה גרסת Node.js בסביבות השונות ועל ידי שאר המפתחים. כלים כמו [nvm](https://github.com/nvm-sh/nvm), ו-[Volta](https://volta.sh/) מאפשרים להגדיר במפורש את הגרסה הנדרשת בפרויקט בקובץ כך שכל חברי הצוות יכולים על ידי הרצת פקודה אחת ליישר קו עם גרסת הפרויקט. ישנה אפשרות שגרסה זו גם תשתקף לתהליך ה-CI וסביבת היצור/לקוחות (לדוגמה על ידי העתקת מספר הגרסה המבוקש ל-`.Dockerfile` ולקבצי ההגדרות של תהליך ה-CI). + +**אחרת:** מפתחת עלולה להיתקל או לפספס שגיאה מכיוון שהיא משתמשת בגרסת Node.js שונה משאר הצוות. או גרוע מכך, סביבת היצור רצה באמצעות גרסה שונה מזו שהורצו עליה הבדיקות. + +

+ +## ![✔] 4.5 הימנעו מאתחול מידע גרעיני משותף, הגדירו לפי צורך של בדיקה + +**אמ;לק:** כדי להימנע מצמידות ותלות בין בדיקות שונות וכדי שיהיה ברור יותר איך להסביר מה קורה בשלבים השונים של הבדיקה, ראוי שכל בדיקה תוסיף ותנהל את המידע העוטף שלה (למשל שורות בטבלה). במקרה ובדיקה צריכה לצרוך מידע מטבלה או להניח שהוא קיים שם - היא צריכה קודם לכן להוסיף את המידע במפורש ולהימנע משינוי מידע של בדיקה אחרת. + +**אחרת:** תארו לכם מקרה בו הפצת גרסה נכשלה בשל שגיאה בבדיקות, הצוות משנס מותניים לחקור את הסיבה ומגיע אם התובנה העצובה שהמערכת עובדת תקין אבל הבדיקות דורסות מידע אחת לשניה ולכן נכשלו ועצרו את תהליך ההפצה. + +🔗 [**לקריאה נוספת: הימנעו מאתחול מידע גרעיני משותף**](./sections/testingandquality/avoid-global-test-fixture.md) + +

+ +## ![✔] 4.6 תייגו את הבדיקות + +**אמ;לק:** בדיקות שונות צריכות לרוץ בתרחישים שונים: בדיקות שפיות (quick smoke/sanity), IO-less, בדיקות בעת שמירת קובץ או commit, בדיקות מלאות מקצה לקצה (e2e) כאשר נפתח PR וכולי... התרחישים השונים יכולים להיות מוגדרים בעזרת תיוג בדיקות שונות עם מילות מפתח כמו #cold #api #sanity דבר המאפשר להגדיר קבוצת בדיקות בהתאם לצורך ולהריץ רק אותה. למשל, זאת השיטה להריץ רק את קבוצת בדיקות השפיות באמצעות [Mocha](https://mochajs.org/): `mocha --grep 'sanity'`. + +**אחרת:** הרצה של כל הבדיקות כולל כאלו שמבצעות עשרות פניות למסד נתונים בכל פעם שמפתח עושה שינוי קטן יאט את קצב הפיתוח בצורה ניכרת ותמנע מצוות הפיתוח להריץ בדיקות. + +

+ +## ![✔] 4.7 בידקו את רמת כיסוי הבדיקות שלכם, זה יעזור לזהות דפוסי בדיקות שגויים + +**אמ;לק:** כלים לבדיקת כיסוי הקוד על ידי בדיקות כמו [Istanbul](https://github.com/istanbuljs/istanbuljs)/[NYC](https://github.com/istanbuljs/nyc) מצוינים בשל שלוש סיבות: הם בחינם (אין עלות לדו"חות שהם מספקים), הם עוזרים לזהות ירידה באחוזי הכיסוי, ואחרון חביב הם מדגישים מקרים של אי התאמה בבדיקות: על ידי צפייה בצבעים שהדוחות הללו מספקים אפשר לזהות למשל שיש קטעי קוד שלא נבדקים לעולם כמו הסתעפויות של `catch` (מה שאומר שיש בדיקות רק למסלול המצליח ולא למקרים של השגיאות). רצוי להגדיר את זה כך שזה יפיל את תהליכי יצירת הגרסאות במידה והכיסוי לא עובר סף מסוים. + +**אחרת:** לא יהיה שום אמצעי מדידה שידווח שקטעים נרחבים מהקוד לא נבדקים כלל. + +

+ +## ![✔] 4.8 Use production-like environment for e2e testing + +**אמ;לק:** End to end (e2e) testing which includes live data used to be the weakest link of the CI process as it depends on multiple heavy services like DB. Use an environment which is as close to your real production environment as possible like a-continue (Missed -continue here, needs content. Judging by the **Otherwise** clause, this should mention docker-compose) + +**אחרת:** Without docker-compose, teams must maintain a testing DB for each testing environment including developers' machines, keep all those DBs in sync so test results won't vary across environments + +

+ +## ![✔] 4.9 שכתבו את הקוד באופן קבוע בעזרת כלי ניתוח סטטי + +**אמ;לק:** שימוש בכלי ניתוח סטטי (static analysis tools) עוזר בכך שהוא נותן דרכים מתאימות לשפר את איכות הקוד ולשמור על הקוד מתוחזק. אפשר להוסיף כלים כאלו לשלבי הבנייה ב-CI כך שיפילו את התהליך במידה והם מזהים ניחוחות בקוד. אחד היתרונות העיקריים שלהם על פני כלים פשוטים יותר הוא היכולת לזהות פגמים באיכות הקוד על פני מספר קבצים (כמו כפל קוד), מורכבות גבוהה של קוד ומעקב אחרי ההיסטוריה וההתקדמות של הקוד. שני כלים מומלצים לשימוש הם [Sonarqube](https://www.sonarqube.org/) (7,900+ [stars](https://github.com/SonarSource/sonarqube)) ו [Code Climate](https://codeclimate.com/) (2,400+ [stars](https://github.com/codeclimate/codeclimate)). + +**אחרת:** אם הקוד באיכות נמוכה, תקלות ובעיות ביצועים תמיד יהוו אתגר שאף ספריה חדשה ונוצצת או פתרון טכנולוגי חדיש יוכלו לפתור. + +🔗 [**לקריאה נוספת: שכתוב!**](./sections/testingandquality/refactoring.md) + +

+ +## ![✔] 4.10 הדמיית תשובות של שרתי HTTP חיצוניים + +**אמ;לק:** השתמשו בכלי הדמיה של המידע שמגיע מהרשת עבור תשובות שמגיעות משירותים חיצוניים (כמו בקשות REST ו GraphQL). זה הכרחי לא רק כדי לבודד את הרכיב שנבדק אלא בעיקר כדי לבדוק מצבים לא צפויים. כלים כמו [nock](https://github.com/nock/nock) או [Mock-Server](https://www.mock-server.com/) מאפשרים להגדיר תשובה מסוימת לבקשה לשירות חיצוני בשורת קוד בודדה. חשוב לא לשכוח לדמות גם שגיאות, עיכובים, timeouts, וכל אירוע אחר שכנראה יקרה בסביבת הייצור. + +**אחרת:** לאפשר לרכיב לגשת למידע אמיתי משירותים חיצוניים בדרך כלל יסתיים בבדיקות פשוטות שמכסות בעיקר את המקרים שהכל טוב. בנוסף לכך הבדיקות לפעמים יכשלו ויהיו איטיות יותר. + +🔗 [**לקריאה נוספת: הדמיית שירותים חיצוניים**](./sections/testingandquality/mock-external-services.md) + +

+ +## ![✔] 4.11 בידקו את פונקציות הביניים בנפרד + +**אמ;לק:** כאשר פונקציית ביניים (middleware) אוחזת נתח משמעותי של לוגיקה שמשתרעת על פני מספר עצום של בקשות, כדאי לבדוק אותה בצורה מבודדת ללא צורך לטעון את כל תשתית הפריימוורק. אפשר להשיג את הפעולה הזאת בקלות על ידי עטיפה או הדמיה של `{req, res, next}`. + +**אחרת:** באג בפונקציות ביניים ב-`express` === באג ברוב הקריטי של הבקשות. + +🔗 [**לקריאה נוספת: לבדוק פונקציות ביניים בנפרד**](./sections/testingandquality/test-middlewares.md) + +

+ +## ![✔] 4.12 קבעו את הפורט בייצור, הגדירו אקראי לבדיקות + +**אמ;לק:** כאשר מבצעים בדיקות מול API, זה רצוי ואף נהוג לאתחל את השרת בתוך הבדיקות. תנו לשרת לבחור פורט באופן אקראי כאשר מריצים בדיקות כדי למנוע התנגשויות. אם אתם משתמשים בשרת HTTP של Node.js (בשימוש על ידי רוב ספריות התשתית), כדי להשיג את היכולת הזאת אין צורך לעשות כלום מלבד להעביר port=0 - זה כבר יגרום להקצאה דינאמית של פורט. + +**אחרת:** הגדרה של פורט ספציפי ימנע את האפשרות להריץ שני טסטים במקביל. רוב הכלים שמריצים כיום טסטים - מריצים במקביל כברירת מחדל. + +🔗 [**לקריאה נוספת: הגדירו פורט אקראי לבדיקות**](./sections/testingandquality/randomize-port.md) + +

+ +## ![✔] 4.13 בידקו את חמשת התוצאות האפשריות + +**אמ;לק:** בעת בדיקת מקרה, ודאו שאתם מכסים את חמשת הקטגוריות האפשריות. בכל פעם שפעולה חלה (למשל קריאת API), מתחילה תגובה, **תוצאה** משמעותית נוצרת ומתבצעת קריאה לבדיקה. ישנן חמש סוגי תוצאות לכל מקרה: תגובה, שינוי נראה לעין (כמו עדכון במסד הנתונים), שליחת קריאה ל- +API, הודעה חדשה נרשמת לתור, וקריאה לכלי צפיה במידע (כמו לוגר ואנליטיקות). [רשימת בדיקות בסיסיות](https://testjavascript.com/wp-content/uploads/2021/10/the-backend-checklist.pdf). כל סוג של תוצאה מגיע אם אתגרים יחודיים ושיטות להמתיק את האתגרים הללו - כתבנו מדריך יעודי על נושא זה [בדיקות ב-Node.js - מעבר ליסודות](https://github.com/testjavascript/nodejs-integration-tests-best-practices) + +**אחרת:** תארו לעצמכם מקרה של בדיקת הוספה של מוצר חדש למערכת. נפוץ לראות בדיקות שמכסות אך ורק את המקרים של תשובה תקינה. מה יקרה אם המוצר לא יתווסף על אף התשובה החיובית? מה צריך להיעשות במידה ובעת הוספת מוצר יש גם קריאה לשירות חיצוני או הוספת הודעה לתור - האם הבדיקה לא צריכה להתייחס גם לזה? קל להתעלם ממגוון מקרים, ובנקודה זאת [רשימת הבדיקות](https://testjavascript.com/wp-content/uploads/2021/10/the-backend-checklist.pdf) עוזרת. + +🔗 [**לקריאה נוספת: בדיקת חמשת התוצאות**](./sections/testingandquality/test-five-outcomes.md) + +


+ +

⬆ חזרה למעלה

+ +# `5. עלייה לאוויר` + +## ![✔] 5.1. ניטור + +**אמ;לק:** ניטור הוא משחק של מציאת בעיות לפני שהמשתמשים מוצאים אותן - מובן מאליו שזה צריך להיות בראש סדר העדיפויות. השוק מוצף בהצעות להגדרות מה הם המדדים הבסיסיים שחייבים לעקוב אחריהם (ההמלצות שלנו בהמשך), לאחר מכן לעבור על כל היכולות המעניינות שכל מוצר מציע ולבחור את הפתרון המיטבי עבור הדרישות שלכם. בכל מקרה, ארבעת השכבות הניתנות לצפייה חייבות להימדד: (1) Uptime - מציינת האם המערכת זמינה, (2) Metrics - מציינת מהי ההתנהגות המצטברת של המערכת (האם 99% מהבקשות נענות), (3) Logging - בודקת אם בקשה מסויימת מסתיימת בהצלחה, (4) Distributed tracing - בודקת האם המערכת יציבה בין הרכיבים המבוזרים שלה. + +**אחרת:** כשלון === לקוחות מאוכזבים. פשוט מאוד. + +🔗 [**לקריאה נוספת: ניטור!**](./sections/production/monitoring.md) + +

+ +## ![✔] 5.2. הגדילו את יכולת הצפייה בעזרת לוגים איכותיים + +**אמ;לק:** לוגים יכולים להיות פח הזבל של שלל מצבים שהמפתחים רצו לדבג או לחלופין מסך מהמם שמתאר את המצב של המוצר. תכננו את הלוגים שלכם מהיום הראשון: איך הם נאספים, איפה הם נשמרים ואיך הם מנותחים כדי להבטיח שהמידע ההכרחי (אחוז שגיאות, מעקב אחר פעולה בין מספר שירותים וכו') באמת נגיש ובר שימוש. + +**אחרת:** יש לכם קופסה שחורה שקשה להבין למה היא מגיעה למצב הנוכחי, ורק עכשיו אתם מתחילים לשכתב את כל הלוגים שלכם כדי שיהיה מידע רלוונטי. + +🔗 [**לקריאה נוספת: הגדלת השקיפות על ידי לוגים איכותיים**](./sections/production/smartlogging.md) + +

+ +## ![✔] 5.3. האצילו כל מה שאפשר (לדוגמה gzip, SSL) לשירות נפרד + +**אמ;לק:** Node.js גרוע בלבצע פעולות שדורשות עוצמת חישוב גבוהה מה-CPU, כמו למשל דחיסה, סיום תהליך SSL, וכו'... כדאי שתשתמשו בתשתיות כמו nginx, HAproxy או שירותי ענן אחרים לשם כך. + +**אחרת:** הת'רד הבודד והמסכן שלכם יישאר עסוק במשימות תשתיתיות במקום להתעסק בלב המערכת שלכם והביצועים יישחקו בהתאם. + +🔗 [**לקריאה נוספת: האצלת כל מה שאפשר (לדוגמה gzip, SSL) לשירות נפרד**](./sections/production/delegatetoproxy.md) + +

+ +## ![✔] 5.4. קיבוע תלויות + +**אמ;לק:** הקוד שלכם צריך להיות זהה בכל הסביבות, אך ללא קובץ יעודי npm יאפשר שימוש בתלויות שונות בכל סביבה. ודאו כי יש לכם `package-lock.json` כך שכל הסביבות יהיו זהות. + +**אחרת:** אנשי הבדיקות יאשרו גרסה שתתנהג אחרת בסביבת ייצור. גרוע מכך, שרתים שונים באותה סביבה יריצו קוד שונה. + +🔗 [**לקריאה נוספת: קיבוע תלויות**](./sections/production/lockdependencies.md) + +

+ +## ![✔] 5.5. הבטיחו את זמינות המערכת בעזרת הכלי המתאים + +**אמ;לק:** המערכת צריכה להמשיך לעבוד ולהתאתחל במידה וקרתה שגיאה קריטית. סביבות ריצה חדשות כמו למשל כאלו המבוססות דוקר (כמו קוברנטיס), או Serverless מטפלות בזה בצורה אוטומטית. כאשר המוצר מותקן על שרת אמיתי פיזי, יש צורך לנהל את משאבי המערכת בעזרת כלי כמו [systemd](https://systemd.io/). אך יש להימנע מלעשות זאת כאשר משתמשים בתשתיות שכבר מבצעות את הניטור מכיוון שזה יגרום לבליעת שגיאות. כאשר לתשתית אין מודעות לשגיאות, אין לה יכולת של ביצוע שלבי פיחות משאבים כמו העברת האינסטנס של המערכת למקום אחר ברשת. + +**אחרת:** הרצה של עשרות אינסטנסים ללא סיבה ברורה ויותר מידי כלי תשתית יחד (cluster management, docker, PM2) עלול לגרום לכאוס עבור ה-DevOps. + +🔗 [**לקריאה נוספת: הבטיחו את זמינות המערכת בעזרת הכלי המתאים**](./sections/production/guardprocess.md) + +

+ +## ![✔] 5.6. השתמשו בכל מעבדי ה-CPU + +**אמ;לק:** בתצורה הבסיסית שלה, מערכת מבוססת Node.js תרוץ על מעבד CPU אחד ושאר המעבדים ינוחו. מחובתכם לשכפל את התהליך ולנהל את המערכת ככה שתרוץ על כל המעבדים. רוב תשתיות הריצה החדשות (כמו קוברנטיס) מאפשרות לשכפל את התהליכים למספר מעבדים, אך הן לא מבטיחות להשתמש בכל המעבדים - זאת האחריות שלכם! אם המוצר מותקן על שרת פיזי, אז כחלק מאחריותכם אתם צריכים גם להשתמש בפתרונות שיבצעו את השכפול של התהליך (כמו systemd). + +**אחרת:** המוצר שלכם ינצל לכל היותר 25% מהמשאבים הזמינים(!). זכרו שלשרת רגיל יש 4 מעבדי CPU או יותר, והתקנה סטנדרטית של תהליך Node.js משתמשת רק במעבד אחד (גם שירותים בשיטת PaaS כמו AWS beanstalk!). + +🔗 [**לקריאה נוספת: השתמשו בכל מעבדי ה-CPU**](./sections/production/utilizecpu.md) + +

+ +## ![✔] 5.7. תיצרו ‘maintenance endpoint’ + +**אמ;לק:** חישפו מידע רלוונטי על המערכת, למשל מצב הזיכרון ו -[REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop), באמצעות API מאובטח. על אף שמומלץ להישען על כלים יעודיים לשם כך, את חלק מהמידע והפעולות יותר פשוט לבדוק באמצעות כתיבת קוד. + +**אחרת:** תגלו שאתם מבצעים הרבה “diagnostic deploys” – העלאת קוד לסביבת הייצור רק כדי להשיג עוד קצת מידע אבחנתי על המערכת. + +🔗 [**לקריאה נוספת: יצירת ‘maintenance endpoint’**](./sections/production/createmaintenanceendpoint.md) + +

+ +## ![✔] 5.8. גלו את הלא ידוע בעזרת מוצרי APM + +**אמ;לק:** שיקלו הוספת שכבה נוספת של בטיחות למוצר שלכם - [APM](https://en.wikipedia.org/wiki/Application_performance_management) (Application monitoring and performance products). אמנם רוב הסממנים והגורמים יכולים להימצא על ידי טכניקות ניטור סטנדרטיות, אך במערכות מבוזרות יש עוד רבדים סמויים מן העין. ניטור מערכות ובדיקת ביצועים (או בקיצור APM) יכולים באופן קסום להוסיף שכבה נוספת של חוויית פיתוח מעבר למה שמספקים הכלים הסטנדרטיים. לדוגמה, ישנם כלי APM שיכולים להדגיש טרנזקציה שטוענת לאט מידי את **צד הלקוח** ולהציע מה הסיבה לכך. כלים אלו גם מספקים יותר הקשר לצוות הפיתוח שמנסים לחקור שגיאה וזאת על ידי הצגה של העומסים שהיו בשרת בזמן שחלה השגיאה. + +**אחרת:** אתם משקיעים זמן ניכר במדידת ביצועי API ואי זמינות של המערכת, כנראה שלעולם לא תהיו מודעים לאילו חלקים בקוד הם האיטיים ביותר בזמן אמת ואיך זה משפיע על חווית המשתמש. + +🔗 [**לקריאה נוספת: גילוי שגיאות וזמני השבתה בעזרת מוצרי APM**](./sections/production/apmproducts.md) + +

+ +## ![✔] 5.9. כתבו את הקוד מותאם להתקנה + +**אמ;לק:** קודדו כאשר התוצאה הסופית במחשבותיכם, התכוננו להתקנה בסביבת יצור כבר מהיום הראשון. זה אמנם נשמע קצת מעורפל ולכן בקישור ישנן מספר המלצות הקשורות לתמיכה במוצר שכבר הותקן. + +**אחרת:** אלופי העולם של IT/DevOps לא ינסו להציל מערכת שכתובה גרוע. + +🔗 [**לקריאה נוספת: כתבו את הקוד מותאם להתקנה**](./sections/production/productioncode.md) + +

+ +## ![✔] 5.10. מדדו ושימרו את ניצול הזיכרון + +**אמ;לק:** ל-Node.js ישנה מערכת יחסים מורכבת עם ניהול הזיכרון: למנוע ה-v8 ישנם גבולות עדינים של צריכת זיכרון (1.4GB) וישנן דרכים ידועות איך לגרום לזליגת זיכרון בקוד של Node.js - ולכן מעקב אחר צריכת הזיכרון של תהליך Node.js הוא חובה. במוצרים קטנים, אפשר לאמוד את צריכת הזיכרון כל כמה זמן בעזרת פקודות shell, אבל במוצרים בינוניים-גדולים צריך לתעדף שימוש בכלים חזקים לניטור מצב הזיכרון. + +**אחרת:** זולגים לכם מאות MB כל יום מהתהליך כמו שקרה ב[וולמארט](https://www.joyent.com/blog/walmart-node-js-memory-leak) + +🔗 [**לקריאה נוספת: מדידה ושמירה על ניצול הזיכרון**](./sections/production/measurememory.md) + +

+ +## ![✔] 5.11. Get your frontend assets out of Node + +**אמ;לק:** Serve frontend content using a specialized infrastructure (nginx, S3, CDN) because Node performance gets hurt when dealing with many static files due to its single-threaded model. One exception to this guideline is when doing server-side rendering + +**אחרת:** Your single Node thread will be busy streaming hundreds of html/images/angular/react files instead of allocating all its resources for the task it was born for – serving dynamic content + +🔗 [**Read More: Get your frontend assets out of Node**](./sections/production/frontendout.md) + +

+ +## ![✔] 5.12. Strive to be stateless + +**אמ;לק:** Store any type of _data_ (e.g. user sessions, cache, uploaded files) within external data stores. When the app holds data in-process this adds additional layer of maintenance complexity like routing users to the same instance and higher cost of restarting a process. To enforce and encourage a stateless approach, most modern runtime platforms allows 'reapp-ing' instances periodically + +**אחרת:** Failure at a given server will result in application downtime instead of just killing a faulty machine. Moreover, scaling-out elasticity will get more challenging due to the reliance on a specific server + +🔗 [**Read More: Be stateless, kill your Servers almost every day**](./sections/production/bestateless.md) + +

+ +## ![✔] 5.13. Use tools that automatically detect vulnerabilities + +**אמ;לק:** Even the most reputable dependencies such as Express have known vulnerabilities (from time to time) that can put a system at risk. This can be easily be tamed using community and commercial tools that constantly check for vulnerabilities and warn (locally or at GitHub), some can even patch them immediately + +**אחרת:** Keeping your code clean from vulnerabilities without dedicated tools will require you to constantly follow online publications about new threats. Quite tedious + +🔗 [**Read More: Use tools that automatically detect vulnerabilities**](./sections/production/detectvulnerabilities.md) + +

+ +## ![✔] 5.14. Assign a transaction id to each log statement + +**אמ;לק:** Assign the same identifier, transaction-id: uuid(), to each log entry within a single request (also known as correlation-id/tracing-id/request-context). Then when inspecting errors in logs, easily conclude what happened before and after. Node has a built-in mechanism, [AsyncLocalStorage](https://nodejs.org/api/async_context.html), for keeping the same context across asynchronous calls. see code examples inside + +**אחרת:** Looking at a production error log without the context – what happened before – makes it much harder and slower to reason about the issue + +🔗 [**Read More: Assign ‘TransactionId’ to each log statement**](./sections/production/assigntransactionid.md) + +

+ +## ![✔] 5.15. Set `NODE_ENV=production` + +**אמ;לק:** Set the environment variable `NODE_ENV` to ‘production’ or ‘development’ to flag whether production optimizations should get activated – some npm packages determine the current environment and optimize their code for production + +**אחרת:** Omitting this simple property might greatly degrade performance when dealing with some specific libraries like Express server-side rendering + +🔗 [**Read More: Set NODE_ENV=production**](./sections/production/setnodeenv.md) + +

+ +## ![✔] 5.16. Design automated, atomic and zero-downtime deployments + +**אמ;לק:** Research shows that teams who perform many deployments lower the probability of severe production issues. Fast and automated deployments that don’t require risky manual steps and service downtime significantly improve the deployment process. You should probably achieve this using Docker combined with CI tools as they became the industry standard for streamlined deployment + +**אחרת:** Long deployments -> production downtime & human-related error -> team unconfident in making deployment -> fewer deployments and features + +

+ +## ![✔] 5.17. Use an LTS release of Node.js + +**אמ;לק:** Ensure you are using an LTS version of Node.js to receive critical bug fixes, security updates and performance improvements + +**אחרת:** Newly discovered bugs or vulnerabilities could be used to exploit an application running in production, and your application may become unsupported by various modules and harder to maintain + +🔗 [**Read More: Use an LTS release of Node.js**](./sections/production/LTSrelease.md) + +

+ +## ![✔] 5.18. Log to stdout, avoid specifying log destination within the app + +**אמ;לק:** Log destinations should not be hard-coded by developers within the application code, but instead should be defined by the execution environment the application runs in. Developers should write logs to `stdout` using a logger utility and then let the execution environment (container, server, etc.) pipe the `stdout` stream to the appropriate destination (i.e. Splunk, Graylog, ElasticSearch, etc.). + +**אחרת:** If developers set the log routing, less flexibility is left for the ops professional who wishes to customize it. Beyond this, if the app tries to log directly to a remote location (e.g., Elastic Search), in case of panic or crash - further logs that might explain the problem won't arrive + +🔗 [**Read More: Log Routing**](./sections/production/logrouting.md) + +

+ +## ![✔] 5.19. Install your packages with `npm ci` + +**אמ;לק:** Run `npm ci` to strictly do a clean install of your dependencies matching package.json and package-lock.json. Obviously production code must use the exact version of the packages that were used for testing. While package-lock.json file sets strict version for dependencies, in case of mismatch with the file package.json, the command 'npm install' will treat package.json as the source of truth. On the other hands, the command 'npm ci' will exit with error in case of mismatch between these files + +**אחרת:** QA will thoroughly test the code and approve a version that will behave differently in production. Even worse, different servers in the same production cluster might run different code. + +🔗 [**Read More: Use npm ci**](./sections/production/installpackageswithnpmci.md) + +


+ +

⬆ חזרה למעלה

+ +# `6. אבטחה` + +
+54 items +
+ +## ![✔] 6.1. Embrace linter security rules + + + +**אמ;לק:** Make use of security-related linter plugins such as [eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security) to catch security vulnerabilities and issues as early as possible, preferably while they're being coded. This can help catching security weaknesses like using eval, invoking a child process or importing a module with a string literal (e.g. user input). Click 'Read more' below to see code examples that will get caught by a security linter + +**אחרת:** What could have been a straightforward security weakness during development becomes a major issue in production. Also, the project may not follow consistent code security practices, leading to vulnerabilities being introduced, or sensitive secrets committed into remote repositories + +🔗 [**Read More: Lint rules**](./sections/security/lintrules.md) + +

+ +## ![✔] 6.2. Limit concurrent requests using a middleware + + + +**אמ;לק:** DOS attacks are very popular and relatively easy to conduct. Implement rate limiting using an external service such as cloud load balancers, cloud firewalls, nginx, [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible) package, or (for smaller and less critical apps) a rate-limiting middleware (e.g. [express-rate-limit](https://www.npmjs.com/package/express-rate-limit)) + +**אחרת:** An application could be subject to an attack resulting in a denial of service where real users receive a degraded or unavailable service. + +🔗 [**Read More: Implement rate limiting**](./sections/security/limitrequests.md) + +

+ +## ![✔] 6.3 Extract secrets from config files or use packages to encrypt them + + + +**אמ;לק:** Never store plain-text secrets in configuration files or source code. Instead, make use of secret-management systems like Vault products, Kubernetes/Docker Secrets, or using environment variables. As a last resort, secrets stored in source control must be encrypted and managed (rolling keys, expiring, auditing, etc). Make use of pre-commit/push hooks to prevent committing secrets accidentally + +**אחרת:** Source control, even for private repositories, can mistakenly be made public, at which point all secrets are exposed. Access to source control for an external party will inadvertently provide access to related systems (databases, apis, services, etc). + +🔗 [**Read More: Secret management**](./sections/security/secretmanagement.md) + +

+ +## ![✔] 6.4. Prevent query injection vulnerabilities with ORM/ODM libraries + + + +**אמ;לק:** To prevent SQL/NoSQL injection and other malicious attacks, always make use of an ORM/ODM or a database library that escapes data or supports named or indexed parameterized queries, and takes care of validating user input for expected types. Never just use JavaScript template strings or string concatenation to inject values into queries as this opens your application to a wide spectrum of vulnerabilities. All the reputable Node.js data access libraries (e.g. [Sequelize](https://github.com/sequelize/sequelize), [Knex](https://github.com/tgriesser/knex), [mongoose](https://github.com/Automattic/mongoose)) have built-in protection against injection attacks. + +**אחרת:** Unvalidated or unsanitized user input could lead to operator injection when working with MongoDB for NoSQL, and not using a proper sanitization system or ORM will easily allow SQL injection attacks, creating a giant vulnerability. + +🔗 [**Read More: Query injection prevention using ORM/ODM libraries**](./sections/security/ormodmusage.md) + +

+ +## ![✔] 6.5. Collection of generic security best practices + +**אמ;לק:** This is a collection of security advice that is not related directly to Node.js - the Node implementation is not much different than any other language. Click read more to skim through. + +🔗 [**Read More: Common security best practices**](./sections/security/commonsecuritybestpractices.md) + +

+ +## ![✔] 6.6. Adjust the HTTP response headers for enhanced security + + + +**אמ;לק:** Your application should be using secure headers to prevent attackers from using common attacks like cross-site scripting (XSS), clickjacking and other malicious attacks. These can be configured easily using modules like [helmet](https://www.npmjs.com/package/helmet). + +**אחרת:** Attackers could perform direct attacks on your application's users, leading to huge security vulnerabilities + +🔗 [**Read More: Using secure headers in your application**](./sections/security/secureheaders.md) + +

+ +## ![✔] 6.7. Constantly and automatically inspect for vulnerable dependencies + + + +**אמ;לק:** With the npm ecosystem it is common to have many dependencies for a project. Dependencies should always be kept in check as new vulnerabilities are found. Use tools like [npm audit](https://docs.npmjs.com/cli/audit) or [snyk](https://snyk.io/) to track, monitor and patch vulnerable dependencies. Integrate these tools with your CI setup so you catch a vulnerable dependency before it makes it to production. + +**אחרת:** An attacker could detect your web framework and attack all its known vulnerabilities. + +🔗 [**Read More: Dependency security**](./sections/security/dependencysecurity.md) + +

+ +## ![✔] 6.8. Protect Users' Passwords/Secrets using bcrypt or scrypt + + + +**אמ;לק:** Passwords or secrets (e.g. API keys) should be stored using a secure hash + salt function like `bcrypt`,`scrypt`, or worst case `pbkdf2`. + +**אחרת:** 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: User Passwords**](./sections/security/userpasswords.md) + +

+ +## ![✔] 6.9. Escape HTML, JS and CSS output + + + +**אמ;לק:** Untrusted data that is sent down to the browser might get executed instead of just being displayed, this is commonly referred as a cross-site-scripting (XSS) attack. Mitigate this by using dedicated libraries that explicitly mark the data as pure content that should never get executed (i.e. encoding, escaping) + +**אחרת:** An attacker might store malicious JavaScript code in your DB which will then be sent as-is to the poor clients + +🔗 [**Read More: Escape output**](./sections/security/escape-output.md) + +

+ +## ![✔] 6.10. Validate incoming JSON schemas + + + +**אמ;לק:** Validate the incoming requests' body payload and ensure it meets expectations, fail fast if it doesn't. To avoid tedious validation coding within each route you may use lightweight JSON-based validation schemas such as [jsonschema](https://www.npmjs.com/package/jsonschema) or [joi](https://www.npmjs.com/package/joi) + +**אחרת:** Your generosity and permissive approach greatly increases the attack surface and encourages the attacker to try out many inputs until they find some combination to crash the application + +🔗 [**Read More: Validate incoming JSON schemas**](./sections/security/validation.md) + +

+ +## ![✔] 6.11. Support blocklisting JWTs + + + +**אמ;לק:** 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. + +**אחרת:** 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: Blocklist JSON Web Tokens**](./sections/security/expirejwt.md) + +

+ +## ![✔] 6.12. Prevent brute-force attacks against authorization + + + +**אמ;לק:** A simple and powerful technique is to limit authorization attempts using two metrics: + +1. The first is number of consecutive failed attempts by the same user unique ID/name and IP address. +2. The second is number of failed attempts from an IP address over some long period of time. For example, block an IP address if it makes 100 failed attempts in one day. + +**אחרת:** An attacker can issue unlimited automated password attempts to gain access to privileged accounts on an application + +🔗 [**Read More: Login rate limiting**](./sections/security/login-rate-limit.md) + +

+ +## ![✔] 6.13. Run Node.js as non-root user + + + +**אמ;לק:** There is a common scenario where Node.js runs as a root user with unlimited permissions. For example, this is the default behaviour in Docker containers. It's recommended to create a non-root user and either bake it into the Docker image (examples given below) or run the process on this user's behalf by invoking the container with the flag "-u username" + +**אחרת:** An attacker who manages to run a script on the server gets unlimited power over the local machine (e.g. change iptable and re-route traffic to their server) + +🔗 [**Read More: Run Node.js as non-root user**](./sections/security/non-root-user.md) + +

+ +## ![✔] 6.14. Limit payload size using a reverse-proxy or a middleware + + + +**אמ;לק:** The bigger the body payload is, the harder your single thread works in processing it. This is an opportunity for attackers to bring servers to their knees without tremendous amount of requests (DOS/DDOS attacks). Mitigate this limiting the body size of incoming requests on the edge (e.g. firewall, ELB) or by configuring [express body parser](https://github.com/expressjs/body-parser) to accept only small-size payloads + +**אחרת:** Your application will have to deal with large requests, unable to process the other important work it has to accomplish, leading to performance implications and vulnerability towards DOS attacks + +🔗 [**Read More: Limit payload size**](./sections/security/requestpayloadsizelimit.md) + +

+ +## ![✔] 6.15. Avoid JavaScript eval statements + + + +**אמ;לק:** `eval` is evil as it allows executing custom JavaScript code during run time. This is not just a performance concern but also an important security concern due to malicious JavaScript code that may be sourced from user input. Another language feature that should be avoided is `new Function` constructor. `setTimeout` and `setInterval` should never be passed dynamic JavaScript code either. + +**אחרת:** Malicious JavaScript code finds a way into text passed into `eval` or other real-time evaluating JavaScript language functions, and will gain complete access to JavaScript permissions on the page. This vulnerability is often manifested as an XSS attack. + +🔗 [**Read More: Avoid JavaScript eval statements**](./sections/security/avoideval.md) + +

+ +## ![✔] 6.16. Prevent evil RegEx from overloading your single thread execution + + + +**אמ;לק:** Regular Expressions, while being handy, pose a real threat to JavaScript applications at large, and the Node.js platform in particular. A user input for text to match might require an outstanding amount of CPU cycles to process. RegEx processing might be inefficient to an extent that a single request that validates 10 words can block the entire event loop for 6 seconds and set the CPU on 🔥. For that reason, prefer third-party validation packages like [validator.js](https://github.com/chriso/validator.js) instead of writing your own Regex patterns, or make use of [safe-regex](https://github.com/substack/safe-regex) to detect vulnerable regex patterns + +**אחרת:** Poorly written regexes could be susceptible to Regular Expression DoS attacks that will block the event loop completely. For example, the popular `moment` package was found vulnerable with malicious RegEx usage in November of 2017 + +🔗 [**Read More: Prevent malicious RegEx**](./sections/security/regex.md) + +

+ +## ![✔] 6.17. Avoid module loading using a variable + + + +**אמ;לק:** Avoid requiring/importing another file with a path that was given as parameter due to the concern that it could have originated from user input. This rule can be extended for accessing files in general (i.e. `fs.readFile()`) or other sensitive resource access with dynamic variables originating from user input. [Eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security) linter can catch such patterns and warn early enough + +**אחרת:** Malicious user input could find its way to a parameter that is used to require tampered files, for example, a previously uploaded file on the file system, or access already existing system files. + +🔗 [**Read More: Safe module loading**](./sections/security/safemoduleloading.md) + +

+ +## ![✔] 6.18. Run unsafe code in a sandbox + + + +**אמ;לק:** When tasked to run external code that is given at run-time (e.g. plugin), use any sort of 'sandbox' execution environment that isolates and guards the main code against the plugin. This can be achieved using a dedicated process (e.g. `cluster.fork()`), serverless environment or dedicated npm packages that act as a sandbox + +**אחרת:** A plugin can attack through an endless variety of options like infinite loops, memory overloading, and access to sensitive process environment variables + +🔗 [**Read More: Run unsafe code in a sandbox**](./sections/security/sandbox.md) + +

+ +## ![✔] 6.19. Take extra care when working with child processes + + + +**אמ;לק:** Avoid using child processes when possible and validate and sanitize input to mitigate shell injection attacks if you still have to. Prefer using `child_process.execFile` which by definition will only execute a single command with a set of attributes and will not allow shell parameter expansion. + +**אחרת:** Naive use of child processes could result in remote command execution or shell injection attacks due to malicious user input passed to an unsanitized system command. + +🔗 [**Read More: Be cautious when working with child processes**](./sections/security/childprocesses.md) + +

+ +## ![✔] 6.20. Hide error details from clients + + + +**אמ;לק:** An integrated express error handler hides the error details by default. However, great are the chances that you implement your own error handling logic with custom Error objects (considered by many as a best practice). If you do so, ensure not to return the entire Error object to the client, which might contain some sensitive application details + +**אחרת:** Sensitive application details such as server file paths, third party modules in use, and other internal workflows of the application which could be exploited by an attacker, could be leaked from information found in a stack trace + +🔗 [**Read More: Hide error details from client**](./sections/security/hideerrors.md) + +

+ +## ![✔] 6.21. Configure 2FA for npm or Yarn + + + +**אמ;לק:** Any step in the development chain should be protected with MFA (multi-factor authentication), npm/Yarn are a sweet opportunity for attackers who can get their hands on some developer's password. Using developer credentials, attackers can inject malicious code into libraries that are widely installed across projects and services. Maybe even across the web if published in public. Enabling 2-factor-authentication in npm leaves almost zero chances for attackers to alter your package code. + +**אחרת:** [Have you heard about the eslint developer whose password was hijacked?](https://medium.com/@oprearocks/eslint-backdoor-what-it-is-and-how-to-fix-the-issue-221f58f1a8c8) + +

+ +## ![✔] 6.22. Modify session middleware settings + + + +**אמ;לק:** Each web framework and technology has its known weaknesses - telling an attacker which web framework we use is a great help for them. Using the default settings for session middlewares can expose your app to module- and framework-specific hijacking attacks in a similar way to the `X-Powered-By` header. Try hiding anything that identifies and reveals your tech stack (E.g. Node.js, express) + +**אחרת:** Cookies could be sent over insecure connections, and an attacker might use session identification to identify the underlying framework of the web application, as well as module-specific vulnerabilities + +🔗 [**Read More: Cookie and session security**](./sections/security/sessions.md) + +

+ +## ![✔] 6.23. Avoid DOS attacks by explicitly setting when a process should crash + + + +**אמ;לק:** The Node process will crash when errors are not handled. Many best practices even recommend to exit even though an error was caught and got handled. Express, for example, will crash on any asynchronous error - unless you wrap routes with a catch clause. This opens a very sweet attack spot for attackers who recognize what input makes the process crash and repeatedly send the same request. There's no instant remedy for this but a few techniques can mitigate the pain: Alert with critical severity anytime a process crashes due to an unhandled error, validate the input and avoid crashing the process due to invalid user input, wrap all routes with a catch and consider not to crash when an error originated within a request (as opposed to what happens globally) + +**אחרת:** This is just an educated guess: given many Node.js applications, if we try passing an empty JSON body to all POST requests - a handful of applications will crash. At that point, we can just repeat sending the same request to take down the applications with ease + +

+ +## ![✔] 6.24. Prevent unsafe redirects + + + +**אמ;לק:** Redirects that do not validate user input can enable attackers to launch phishing scams, steal user credentials, and perform other malicious actions. + +**אחרת:** If an attacker discovers that you are not validating external, user-supplied input, they may exploit this vulnerability by posting specially-crafted links on forums, social media, and other public places to get users to click it. + +🔗 [**Read More: Prevent unsafe redirects**](./sections/security/saferedirects.md) + +

+ +## ![✔] 6.25. Avoid publishing secrets to the npm registry + + + +**אמ;לק:** 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. + +**אחרת:** 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. + +🔗 [**Read More: Avoid publishing secrets**](./sections/security/avoid_publishing_secrets.md) + +

+ +## ![✔] 6.26 Inspect for outdated packages + +**אמ;לק:** 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 + +**אחרת:** Your production will run packages that have been explicitly tagged by their author as risky + +

+ +## ![✔] 6.27. Import built-in modules using the 'node:' protocol + + + +**אמ;לק:** Import or require built-in Node.js modules using the 'node protocol' syntax: + +```javascript +import { functionName } from "node:module"; // note that 'node:' prefix +``` + +For example: + +```javascript +import { createServer } from "node:http"; +``` + +This style ensures that there is no ambiguity with global npm packages and makes it clear for the reader that the code refers to a well-trusted official module. This style can be enforced with the eslint rule ['prefer-node-protocol'](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-node-protocol.md) + +**אחרת:** Using the import syntax without 'node:' prefix opens the door for [typosquatting attacks](https://en.wikipedia.org/wiki/Typosquatting) where one could mistakenly mistype a module name (e.g., 'event' instead of 'events) and get a malicious package that was built only to trick users into installing them + +


+ +

⬆ חזרה למעלה

+ +# `7. טיוטה: ביצועים` + +## Our contributors are working on this section. [Would you like to join?](https://github.com/goldbergyoni/nodebestpractices/issues/256) + +

+ +## ![✔] 7.1. Don't block the event loop + +**אמ;לק:** Avoid CPU intensive tasks as they will block the mostly single-threaded Event Loop and offload those to a dedicated thread, process or even a different technology based on the context. + +**אחרת:** As the Event Loop is blocked, Node.js will be unable to handle other request thus causing delays for concurrent users. **3000 users are waiting for a response, the content is ready to be served, but one single request blocks the server from dispatching the results back** + +🔗 [**Read More: Do not block the event loop**](./sections/performance/block-loop.md) + +


+ +## ![✔] 7.2. Prefer native JS methods over user-land utils like Lodash + +**אמ;לק:** It's often more penalising to use utility libraries like `lodash` and `underscore` over native methods as it leads to unneeded dependencies and slower performance. +Bear in mind that with the introduction of the new V8 engine alongside the new ES standards, native methods were improved in such a way that it's now about 50% more performant than utility libraries. + +**אחרת:** You'll have to maintain less performant projects where you could have simply used what was **already** available or dealt with a few more lines in exchange of a few more files. + +🔗 [**Read More: Native over user land utils**](./sections/performance/nativeoverutil.md) + +


+ +

⬆ חזרה למעלה

+ +# `8. דוקר` + +🏅 Many thanks to [Bret Fisher](https://github.com/BretFisher) from whom we learned many of the following practices + +

+ +## ![✔] 8.1 Use multi-stage builds for leaner and more secure Docker images + +**אמ;לק:** Use multi-stage build to copy only necessary production artifacts. A lot of build-time dependencies and files are not needed for running your application. With multi-stage builds these resources can be used during build while the runtime environment contains only what's necessary. Multi-stage builds are an easy way to get rid of overweight and security threats. + +**אחרת:** Larger images will take longer to build and ship, build-only tools might contain vulnerabilities and secrets only meant for the build phase might be leaked. + +### Example Dockerfile for multi-stage builds + +```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" ] +``` + +🔗 [**Read More: Use multi-stage builds**](./sections/docker/multi_stage_builds.md) + +


+ +## ![✔] 8.2. Bootstrap using `node` command, avoid `npm start` + +**אמ;לק:** Use `CMD ['node','server.js']` to start your app, avoid using npm scripts which don't pass OS signals to the code. This prevents problems with child-processes, signal handling, graceful shutdown and having zombie processes + +Update: [Starting from npm 7, npm claim](https://docs.npmjs.com/cli/v7/using-npm/changelog#706-2020-10-27) to pass signals. We follow and will update accordingly + +**אחרת:** When no signals are passed, your code will never be notified about shutdowns. Without this, it will lose its chance to close properly possibly losing current requests and/or data + +[**Read More: Bootstrap container using node command, avoid npm start**](./sections/docker/bootstrap-using-node.md) + +


+ +## ![✔] 8.3. Let the Docker runtime handle replication and uptime + +**אמ;לק:** When using a Docker run time orchestrator (e.g., Kubernetes), invoke the Node.js process directly without intermediate process managers or custom code that replicate the process (e.g. PM2, Cluster module). The runtime platform has the highest amount of data and visibility for making placement decision - It knows best how many processes are needed, how to spread them and what to do in case of crashes + +**אחרת:** Container keeps crashing due to lack of resources will get restarted indefinitely by the process manager. Should Kubernetes be aware of that, it could relocate it to a different roomy instance + +🔗 [**Read More: Let the Docker orchestrator restart and replicate processes**](./sections/docker/restart-and-replicate-processes.md) + +


+ +## ![✔] 8.4. Use .dockerignore to prevent leaking secrets + +**TL;DR**: Include a `.dockerignore` file that filters out common secret files and development artifacts. By doing so, you might prevent secrets from leaking into the image. As a bonus the build time will significantly decrease. Also, ensure not to copy all files recursively rather explicitly choose what should be copied to Docker + +**Otherwise**: Common personal secret files like `.env`, `.aws` and `.npmrc` will be shared with anybody with access to the image (e.g. Docker repository) + +🔗 [**Read More: Use .dockerignore**](./sections/docker/docker-ignore.md) + +


+ +## ![✔] 8.5. Clean-up dependencies before production + +**אמ;לק:** Although Dev-Dependencies are sometimes needed during the build and test life-cycle, eventually the image that is shipped to production should be minimal and clean from development dependencies. Doing so guarantees that only necessary code is shipped and the amount of potential attacks (i.e. attack surface) is minimized. When using multi-stage build (see dedicated bullet) this can be achieved by installing all dependencies first and finally running `npm ci --production` + +**אחרת:** Many of the infamous npm security breaches were found within development packages (e.g. [eslint-scope](https://eslint.org/blog/2018/07/postmortem-for-malicious-package-publishes)) + +🔗 Read More: [Remove development dependencies](./sections/docker/install-for-production.md) + +


+ +## ![✔] 8.6. Shutdown smartly and gracefully + +**אמ;לק:** Handle the process SIGTERM event and clean-up all existing connection and resources. This should be done while responding to ongoing requests. In Dockerized runtimes, shutting down containers is not a rare event, rather a frequent occurrence that happen as part of routine work. Achieving this demands some thoughtful code to orchestrate several moving parts: The load balancer, keep-alive connections, the HTTP server and other resources + +**אחרת:** Dying immediately means not responding to thousands of disappointed users + +🔗 [**Read More: Graceful shutdown**](./sections/docker/graceful-shutdown.md) + +


+ +## ![✔] 8.7. Set memory limits using both Docker and v8 + +**אמ;לק:** Always configure a memory limit using both Docker and the JavaScript runtime flags. The Docker limit is needed to make thoughtful container placement decision, the --v8's flag max-old-space is needed to kick off the GC on time and prevent under utilization of memory. Practically, set the v8's old space memory to be a just bit less than the container limit + +**אחרת:** The docker definition is needed to perform thoughtful scaling decision and prevent starving other citizens. Without also defining the v8's limits, it will under utilize the container resources - Without explicit instructions it crashes when utilizing ~50-60% of its host resources + +🔗 [**Read More: Set memory limits using Docker only**](./sections/docker/memory-limit.md) + +


+ +## ![✔] 8.8. Plan for efficient caching + +**אמ;לק:** Rebuilding a whole docker image from cache can be nearly instantaneous if done correctly. The less updated instructions should be at the top of your Dockerfile and the ones constantly changing (like app code) should be at the bottom. + +**אחרת:** Docker build will be very long and consume lot of resources even when making tiny changes + +🔗 [**Read More: Leverage caching to reduce build times**](./sections/docker/use-cache-for-shorter-build-time.md) + +


+ +## ![✔] 8.9. Use explicit image reference, avoid `latest` tag + +**אמ;לק:** Specify an explicit image digest or versioned label, never refer to `latest`. Developers are often led to believe that specifying the `latest` tag will provide them with the most recent image in the repository however this is not the case. Using a digest guarantees that every instance of the service is running exactly the same code. + +In addition, referring to an image tag means that the base image is subject to change, as image tags cannot be relied upon for a deterministic install. Instead, if a deterministic install is expected, a SHA256 digest can be used to reference an exact image. + +**אחרת:** A new version of a base image could be deployed into production with breaking changes, causing unintended application behaviour. + +🔗 [**Read More: Understand image tags and use the "latest" tag with caution**](./sections/docker/image-tags.md) + +


+ +## ![✔] 8.10. Prefer smaller Docker base images + +**אמ;לק:** Large images lead to higher exposure to vulnerabilities and increased resource consumption. Using leaner Docker images, such as Slim and Alpine Linux variants, mitigates this issue. + +**אחרת:** Building, pushing, and pulling images will take longer, unknown attack vectors can be used by malicious actors and more resources are consumed. + +🔗 [**Read More: Prefer smaller images**](./sections/docker/smaller_base_images.md) + +


+ +## ![✔] 8.11. Clean-out build-time secrets, avoid secrets in args + +**אמ;לק:** Avoid secrets leaking from the Docker build environment. A Docker image is typically shared in multiple environment like CI and a registry that are not as sanitized as production. A typical example is an npm token which is usually passed to a dockerfile as argument. This token stays within the image long after it is needed and allows the attacker indefinite access to a private npm registry. This can be avoided by coping a secret file like `.npmrc` and then removing it using multi-stage build (beware, build history should be deleted as well) or by using Docker build-kit secret feature which leaves zero traces + +**אחרת:** Everyone with access to the CI and docker registry will also get access to some precious organization secrets as a bonus + +🔗 [**Read More: Clean-out build-time secrets**](./sections/docker/avoid-build-time-secrets.md) + +


+ +## ![✔] 8.12. Scan images for multi layers of vulnerabilities + +**אמ;לק:** Besides checking code dependencies vulnerabilities also scan the final image that is shipped to production. Docker image scanners check the code dependencies but also the OS binaries. This E2E security scan covers more ground and verifies that no bad guy injected bad things during the build. Consequently, it is recommended running this as the last step before deployment. There are a handful of free and commercial scanners that also provide CI/CD plugins + +**אחרת:** Your code might be entirely free from vulnerabilities. However it might still get hacked due to vulnerable version of OS-level binaries (e.g. OpenSSL, TarBall) that are commonly being used by applications + +🔗 [**Read More: Scan the entire image before production**](./sections/docker/scan-images.md) + +


+ +## ![✔] 8.13 Clean NODE_MODULE cache + +**אמ;לק:** After installing dependencies in a container remove the local cache. It doesn't make any sense to duplicate the dependencies for faster future installs since there won't be any further installs - A Docker image is immutable. Using a single line of code tens of MB (typically 10-50% of the image size) are shaved off + +**אחרת:** The image that will get shipped to production will weigh 30% more due to files that will never get used + +🔗 [**Read More: Clean NODE_MODULE cache**](./sections/docker/clean-cache.md) + +


+ +## ![✔] 8.14. Generic Docker practices + +**אמ;לק:** This is a collection of Docker advice that is not related directly to Node.js - the Node implementation is not much different than any other language. Click read more to skim through. + +🔗 [**Read More: Generic Docker practices**](./sections/docker/generic-tips.md) + +


+ +## ![✔] 8.15. Lint your Dockerfile + +**אמ;לק:** 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. + +**אחרת:** 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) + +


+ +

⬆ חזרה למעלה

+ +# 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 + +
+ +## Translations + +All translations are contributed by the community. We will be happy to get any help with either completed, ongoing or new translations! + +### Completed translations + +- ![BR](./assets/flags/BR.png) [Brazilian Portuguese](./README.brazilian-portuguese.md) - Courtesy of [Marcelo Melo](https://github.com/marcelosdm) +- ![CN](./assets/flags/CN.png) [Chinese](./README.chinese.md) - Courtesy of [Matt Jin](https://github.com/mattjin) +- ![RU](./assets/flags/RU.png) [Russian](./README.russian.md) - Courtesy of [Alex Ivanov](https://github.com/contributorpw) +- ![PL](./assets/flags/PL.png) [Polish](./README.polish.md) - Courtesy of [Michal Biesiada](https://github.com/mbiesiad) +- ![JA](./assets/flags/JA.png) [Japanese](./README.japanese.md) - Courtesy of [Yuki Ota](https://github.com/YukiOta), [Yuta Azumi](https://github.com/YA21) +- ![EU](./assets/flags/EU.png) [Basque](README.basque.md) - Courtesy of [Ane Diaz de Tuesta](https://github.com/anediaz) & Joxefe Diaz de Tuesta + +### Translations in progress + +- ![FR](./assets/flags/FR.png) [French](./README.french.md) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/129)) +- ![HE](./assets/flags/HE.png) Hebrew ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/156)) +- ![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)) + +

+ +## Steering Committee + +Meet the steering committee members - the people who work together to provide guidance and future direction to the project. In addition, each member of the committee leads a project tracked under our [GitHub projects](https://github.com/goldbergyoni/nodebestpractices/projects). + + + +[Yoni Goldberg](https://github.com/goldbergyoni) + + + +Independent Node.js consultant who works with customers in the USA, Europe, and Israel on building large-scale Node.js applications. Many of the best practices above were first published at [goldbergyoni.com](https://goldbergyoni.com). Reach Yoni at [@goldbergyoni](https://github.com/goldbergyoni) or [me@goldbergyoni.com](mailto:me@goldbergyoni.com) + +
+ +Josh Hemphill + +[Josh Hemphill](https://github.com/josh-hemphill) + + + + +Full Stack Software Engineer / Developer specializing in Security, DevOps/DevSecOps, and ERP Integrations. + +
+ +Raz Luvaton + +[Raz Luvaton](https://github.com/rluvaton) + + + +Full Stack Developer who knows how to exit from Vim and loves Architecture, Virtualization and Security. + +
+ +## 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 ✨ + +Thanks goes to these wonderful people who have contributed to this repository! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Kevin Rambaud
Kevin Rambaud

🖋
Michael Fine
Michael Fine

🖋
Shreya Dahal
Shreya Dahal

🖋
Matheus Cruz Rocha
Matheus Cruz Rocha

🖋
Yog Mehta
Yog Mehta

🖋
Kudakwashe Paradzayi
Kudakwashe Paradzayi

🖋
t1st3
t1st3

🖋
mulijordan1976
mulijordan1976

🖋
Matan Kushner
Matan Kushner

🖋
Fabio Hiroki
Fabio Hiroki

🖋
James Sumners
James Sumners

🖋
Dan Gamble
Dan Gamble

🖋
PJ Trainor
PJ Trainor

🖋
Remek Ambroziak
Remek Ambroziak

🖋
Yoni Jah
Yoni Jah

🖋
Misha Khokhlov
Misha Khokhlov

🖋
Evgeny Orekhov
Evgeny Orekhov

🖋
-
-

🖋
Isaac Halvorson
Isaac Halvorson

🖋
Vedran Karačić
Vedran Karačić

🖋
lallenlowe
lallenlowe

🖋
Nathan Wells
Nathan Wells

🖋
Paulo Reis
Paulo Reis

🖋
syzer
syzer

🖋
David Sancho
David Sancho

🖋
Robert Manolea
Robert Manolea

🖋
Xavier Ho
Xavier Ho

🖋
Aaron
Aaron

🖋
Jan Charles Maghirang Adona
Jan Charles Maghirang Adona

🖋
Allen
Allen

🖋
Leonardo Villela
Leonardo Villela

🖋
Michał Załęcki
Michał Załęcki

🖋
Chris Nicola
Chris Nicola

🖋
Alejandro Corredor
Alejandro Corredor

🖋
cwar
cwar

🖋
Yuwei
Yuwei

🖋
Utkarsh Bhatt
Utkarsh Bhatt

🖋
Duarte Mendes
Duarte Mendes

🖋
Jason Kim
Jason Kim

🖋
Mitja O.
Mitja O.

🖋
Sandro Miguel Marques
Sandro Miguel Marques

🖋
Gabe
Gabe

🖋
Ron Gross
Ron Gross

🖋
Valeri Karpov
Valeri Karpov

🖋
Sergio Bernal
Sergio Bernal

🖋
Nikola Telkedzhiev
Nikola Telkedzhiev

🖋
Vitor Godoy
Vitor Godoy

🖋
Manish Saraan
Manish Saraan

🖋
Sangbeom Han
Sangbeom Han

🖋
blackmatch
blackmatch

🖋
Joe Reeve
Joe Reeve

🖋
Ryan Busby
Ryan Busby

🖋
Iman Mohamadi
Iman Mohamadi

🖋
Sergii Paryzhskyi
Sergii Paryzhskyi

🖋
Kapil Patel
Kapil Patel

🖋
迷渡
迷渡

🖋
Hozefa
Hozefa

🖋
Ethan
Ethan

🖋
Sam
Sam

🖋
Arlind
Arlind

🖋
Teddy Toussaint
Teddy Toussaint

🖋
Lewis
Lewis

🖋
Gabriel Lidenor
Gabriel Lidenor

🖋
Roman
Roman

🖋
Francozeira
Francozeira

🖋
Invvard
Invvard

🖋
Rômulo Garofalo
Rômulo Garofalo

🖋
Tho Q Luong
Tho Q Luong

🖋
Burak Shen
Burak Shen

🖋
Martin Muzatko
Martin Muzatko

🖋
Jared Collier
Jared Collier

🖋
Hilton Meyer
Hilton Meyer

🖋
ChangJoo Park(박창주)
ChangJoo Park(박창주)

🖋
Masahiro Sakaguchi
Masahiro Sakaguchi

🖋
Keith Holliday
Keith Holliday

🖋
coreyc
coreyc

🖋
Maximilian Berkmann
Maximilian Berkmann

🖋
Douglas Mariano Valero
Douglas Mariano Valero

🖋
Marcelo Melo
Marcelo Melo

🖋
Mehmet Perk
Mehmet Perk

🖋
ryan ouyang
ryan ouyang

🖋
Shabeer
Shabeer

🖋
Eduard Kyvenko
Eduard Kyvenko

🖋
Deyvison Rocha
Deyvison Rocha

🖋
George Mamer
George Mamer

🖋
Konstantinos Leimonis
Konstantinos Leimonis

🖋
Oliver Lluberes
Oliver Lluberes

🌍
Tien Do
Tien Do

🖋
Ranvir Singh
Ranvir Singh

🖋
Vadim Nicolaev
Vadim Nicolaev

🖋 🌍
German Gamboa Gonzalez
German Gamboa Gonzalez

🖋
Hafez
Hafez

🖋
Chandiran
Chandiran

🖋
VinayaSathyanarayana
VinayaSathyanarayana

🖋
Kim Kern
Kim Kern

🖋
Kenneth Freitas
Kenneth Freitas

🖋
songe
songe

🖋
Kirill Shekhovtsov
Kirill Shekhovtsov

🖋
Serge
Serge

🖋
keyrwinz
keyrwinz

🖋
Dmitry Nikitenko
Dmitry Nikitenko

🖋
bushuai
bushuai

👀 🖋
Benjamin Gruenbaum
Benjamin Gruenbaum

🖋
Ezequiel
Ezequiel

🌍
Juan José Rodríguez
Juan José Rodríguez

🌍
Or Bin
Or Bin

🖋
Andreo Vieira
Andreo Vieira

🖋
Michael Solomon
Michael Solomon

🖋
Jimmy Callin
Jimmy Callin

🖋
Siddharth
Siddharth

🖋
Ryan Smith
Ryan Smith

🖋
Tom Boettger
Tom Boettger

🖋
Joaquín Ormaechea
Joaquín Ormaechea

🌍
dfrzuz
dfrzuz

🌍
Victor Homyakov
Victor Homyakov

🖋
Josh
Josh

🖋 🛡️
Alec Francis
Alec Francis

🖋
arjun6610
arjun6610

🖋
Jan Osch
Jan Osch

🖋
Thiago Rotondo Sampaio
Thiago Rotondo Sampaio

🌍
Alexsey
Alexsey

🖋
Luis A. Acurero
Luis A. Acurero

🌍
Lucas Romano
Lucas Romano

🌍
Denise Case
Denise Case

🖋
Nick Ribal
Nick Ribal

🖋 👀
0xflotus
0xflotus

🖋
Jonathan Chen
Jonathan Chen

🖋
Dilan Srilal
Dilan Srilal

🖋
vladthelittleone
vladthelittleone

🌍
Nik Osvalds
Nik Osvalds

🖋
Daniel Kiss
Daniel Kiss

📖
Forresst
Forresst

🖋
Jonathan Svenheden
Jonathan Svenheden

🖋
AustrisC
AustrisC

🖋
kyeongtae kim
kyeongtae kim

🌍
007
007

🖋
Ane Diaz de Tuesta
Ane Diaz de Tuesta

🌍 🖋
YukiOta
YukiOta

🌍
Frazer Smith
Frazer Smith

🖋
Raz Luvaton
Raz Luvaton

🖋
Yuta Azumi
Yuta Azumi

🖋
andrewjbarbour
andrewjbarbour

🖋
mr
mr

🖋
Aleksandar
Aleksandar

🖋
Owl
Owl

🖋
Yedidya Schwartz
Yedidya Schwartz

🖋 💡
ari
ari

🖋
Thomas König
Thomas König

🖋
Kalle Lämsä
Kalle Lämsä

🖋
Wyatt
Wyatt

🖋
KHADIR Tayeb
KHADIR Tayeb

🖋
Shankar Regmi
Shankar Regmi

🖋
Shubham
Shubham

🖋
Lucas Alves
Lucas Alves

🖋
Benjamin
Benjamin

🖋
Yeoh Joer
Yeoh Joer

🖋
Miigon
Miigon

🖋
Rostislav Bogorad
Rostislav Bogorad

🖋
Flouse
Flouse

🖋
Tarantini Pereira
Tarantini Pereira

🖋
Kazuki Matsuo
Kazuki Matsuo

🖋
Adam Smith
Adam Smith

🖋
Dohyeon Ko
Dohyeon Ko

🖋
Vladislav Legkov
Vladislav Legkov

🖋
Kerollos Magdy
Kerollos Magdy

🖋
Erez Lieberman
Erez Lieberman

🖋
Breno Macedo
Breno Macedo

🖋
Fernando Flores
Fernando Flores

🌍
Rafael Brito
Rafael Brito

🌍
Emiliano Peralta
Emiliano Peralta

🌍
Shin, SJ
Shin, SJ

🖋
Benjamin Forster
Benjamin Forster

🖋
Daniele Fedeli
Daniele Fedeli

🖋
djob195
djob195

🖋
antspk
antspk

🖋
정진영
정진영

🖋
kkk-cashwalk
kkk-cashwalk

🖋
apainintheneck
apainintheneck

🖋
Fajar Budhi Iswanda
Fajar Budhi Iswanda

🖋
이주호
이주호

🖋
Singh
Singh

🖋
Alex Dumitru
Alex Dumitru

🖋
Anton Lykhatskyi
Anton Lykhatskyi

🖋
sangwonlee
sangwonlee

🖋
Eugenio Berretta
Eugenio Berretta

🖋
soranakk
soranakk

🖋
고준영
고준영

🖋 💻
Guilherme Portella
Guilherme Portella

🖋
André Esser
André Esser

🖋
Scc
Scc

🌍
Mauro Accornero
Mauro Accornero

🖋
no-yan
no-yan

🖋
+ + + + + + +### Steering Committee Emeriti + +[Bruno Scheufler](https://github.com/BrunoScheufler) + + +💻 full-stack web engineer, Node.js & GraphQL enthusiast + +
+ + + +[Kyle Martin](https://github.com/js-kyle) + + + +Full Stack Developer & Site Reliability Engineer based in New Zealand, interested in web application security, and architecting and building Node.js applications to perform at global scale. + +
+ + + +[Kevyn Bruyere](https://github.com/kevynb) + + +Independent full-stack developer with a taste for Ops and automation. + +
+ + + +[Sagir Khan](https://github.com/sagirk) + + + + +Deep specialist in JavaScript and its ecosystem — React, Node.js, TypeScript, GraphQL, MongoDB, pretty much anything that involves JS/JSON in any layer of the system — building products using the web platform for the world’s most recognized brands. Individual Member of the Node.js Foundation. diff --git a/README.indonesian.md b/README.indonesian.md index d248e8547..f4d2d2f71 100644 --- a/README.indonesian.md +++ b/README.indonesian.md @@ -444,7 +444,7 @@ Semua pernyataan di atas akan mengembalikan nilai _false_ jika menggunakan `===`

⬆ Kembali ke atas

-# `4. Praktik Pengujian dan Kualitas Secara Keseluruhan ` +# `4. Praktik Pengujian dan Kualitas Secara Keseluruhan` ## ![✔] 4.1 Paling tidak, buat pengujian API (komponen) @@ -1376,201 +1376,256 @@ Terima kasih kepada orang-orang hebat ini yang telah berkontribusi pada reposito - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

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

📖

Forresst

🖋

Jonathan Svenheden

🖋

AustrisC

🖋

kyeongtae kim

🌍

007

🖋

Ane Diaz de Tuesta

🌍 🖋

YukiOta

🌍

Frazer Smith

🖋

Raz Luvaton

🖋

Yuta Azumi

🖋

andrewjbarbour

🖋

mr

🖋

Aleksandar

🖋

Owl

🖋

Yedidya Schwartz

🖋 💡

ari

🖋

Thomas König

🖋

Kalle Lämsä

🖋

Wyatt

🖋

KHADIR Tayeb

🖋
Kevin Rambaud
Kevin Rambaud

🖋
Michael Fine
Michael Fine

🖋
Shreya Dahal
Shreya Dahal

🖋
Matheus Cruz Rocha
Matheus Cruz Rocha

🖋
Yog Mehta
Yog Mehta

🖋
Kudakwashe Paradzayi
Kudakwashe Paradzayi

🖋
t1st3
t1st3

🖋
mulijordan1976
mulijordan1976

🖋
Matan Kushner
Matan Kushner

🖋
Fabio Hiroki
Fabio Hiroki

🖋
James Sumners
James Sumners

🖋
Dan Gamble
Dan Gamble

🖋
PJ Trainor
PJ Trainor

🖋
Remek Ambroziak
Remek Ambroziak

🖋
Yoni Jah
Yoni Jah

🖋
Misha Khokhlov
Misha Khokhlov

🖋
Evgeny Orekhov
Evgeny Orekhov

🖋
-
-

🖋
Isaac Halvorson
Isaac Halvorson

🖋
Vedran Karačić
Vedran Karačić

🖋
lallenlowe
lallenlowe

🖋
Nathan Wells
Nathan Wells

🖋
Paulo Reis
Paulo Reis

🖋
syzer
syzer

🖋
David Sancho
David Sancho

🖋
Robert Manolea
Robert Manolea

🖋
Xavier Ho
Xavier Ho

🖋
Aaron
Aaron

🖋
Jan Charles Maghirang Adona
Jan Charles Maghirang Adona

🖋
Allen
Allen

🖋
Leonardo Villela
Leonardo Villela

🖋
Michał Załęcki
Michał Załęcki

🖋
Chris Nicola
Chris Nicola

🖋
Alejandro Corredor
Alejandro Corredor

🖋
cwar
cwar

🖋
Yuwei
Yuwei

🖋
Utkarsh Bhatt
Utkarsh Bhatt

🖋
Duarte Mendes
Duarte Mendes

🖋
Jason Kim
Jason Kim

🖋
Mitja O.
Mitja O.

🖋
Sandro Miguel Marques
Sandro Miguel Marques

🖋
Gabe
Gabe

🖋
Ron Gross
Ron Gross

🖋
Valeri Karpov
Valeri Karpov

🖋
Sergio Bernal
Sergio Bernal

🖋
Nikola Telkedzhiev
Nikola Telkedzhiev

🖋
Vitor Godoy
Vitor Godoy

🖋
Manish Saraan
Manish Saraan

🖋
Sangbeom Han
Sangbeom Han

🖋
blackmatch
blackmatch

🖋
Joe Reeve
Joe Reeve

🖋
Ryan Busby
Ryan Busby

🖋
Iman Mohamadi
Iman Mohamadi

🖋
Sergii Paryzhskyi
Sergii Paryzhskyi

🖋
Kapil Patel
Kapil Patel

🖋
迷渡
迷渡

🖋
Hozefa
Hozefa

🖋
Ethan
Ethan

🖋
Sam
Sam

🖋
Arlind
Arlind

🖋
Teddy Toussaint
Teddy Toussaint

🖋
Lewis
Lewis

🖋
Gabriel Lidenor
Gabriel Lidenor

🖋
Roman
Roman

🖋
Francozeira
Francozeira

🖋
Invvard
Invvard

🖋
Rômulo Garofalo
Rômulo Garofalo

🖋
Tho Q Luong
Tho Q Luong

🖋
Burak Shen
Burak Shen

🖋
Martin Muzatko
Martin Muzatko

🖋
Jared Collier
Jared Collier

🖋
Hilton Meyer
Hilton Meyer

🖋
ChangJoo Park(박창주)
ChangJoo Park(박창주)

🖋
Masahiro Sakaguchi
Masahiro Sakaguchi

🖋
Keith Holliday
Keith Holliday

🖋
coreyc
coreyc

🖋
Maximilian Berkmann
Maximilian Berkmann

🖋
Douglas Mariano Valero
Douglas Mariano Valero

🖋
Marcelo Melo
Marcelo Melo

🖋
Mehmet Perk
Mehmet Perk

🖋
ryan ouyang
ryan ouyang

🖋
Shabeer
Shabeer

🖋
Eduard Kyvenko
Eduard Kyvenko

🖋
Deyvison Rocha
Deyvison Rocha

🖋
George Mamer
George Mamer

🖋
Konstantinos Leimonis
Konstantinos Leimonis

🖋
Oliver Lluberes
Oliver Lluberes

🌍
Tien Do
Tien Do

🖋
Ranvir Singh
Ranvir Singh

🖋
Vadim Nicolaev
Vadim Nicolaev

🖋 🌍
German Gamboa Gonzalez
German Gamboa Gonzalez

🖋
Hafez
Hafez

🖋
Chandiran
Chandiran

🖋
VinayaSathyanarayana
VinayaSathyanarayana

🖋
Kim Kern
Kim Kern

🖋
Kenneth Freitas
Kenneth Freitas

🖋
songe
songe

🖋
Kirill Shekhovtsov
Kirill Shekhovtsov

🖋
Serge
Serge

🖋
keyrwinz
keyrwinz

🖋
Dmitry Nikitenko
Dmitry Nikitenko

🖋
bushuai
bushuai

👀 🖋
Benjamin Gruenbaum
Benjamin Gruenbaum

🖋
Ezequiel
Ezequiel

🌍
Juan José Rodríguez
Juan José Rodríguez

🌍
Or Bin
Or Bin

🖋
Andreo Vieira
Andreo Vieira

🖋
Michael Solomon
Michael Solomon

🖋
Jimmy Callin
Jimmy Callin

🖋
Siddharth
Siddharth

🖋
Ryan Smith
Ryan Smith

🖋
Tom Boettger
Tom Boettger

🖋
Joaquín Ormaechea
Joaquín Ormaechea

🌍
dfrzuz
dfrzuz

🌍
Victor Homyakov
Victor Homyakov

🖋
Josh
Josh

🖋 🛡️
Alec Francis
Alec Francis

🖋
arjun6610
arjun6610

🖋
Jan Osch
Jan Osch

🖋
Thiago Rotondo Sampaio
Thiago Rotondo Sampaio

🌍
Alexsey
Alexsey

🖋
Luis A. Acurero
Luis A. Acurero

🌍
Lucas Romano
Lucas Romano

🌍
Denise Case
Denise Case

🖋
Nick Ribal
Nick Ribal

🖋 👀
0xflotus
0xflotus

🖋
Jonathan Chen
Jonathan Chen

🖋
Dilan Srilal
Dilan Srilal

🖋
vladthelittleone
vladthelittleone

🌍
Nik Osvalds
Nik Osvalds

🖋
Daniel Kiss
Daniel Kiss

📖
Forresst
Forresst

🖋
Jonathan Svenheden
Jonathan Svenheden

🖋
AustrisC
AustrisC

🖋
kyeongtae kim
kyeongtae kim

🌍
007
007

🖋
Ane Diaz de Tuesta
Ane Diaz de Tuesta

🌍 🖋
YukiOta
YukiOta

🌍
Frazer Smith
Frazer Smith

🖋
Raz Luvaton
Raz Luvaton

🖋
Yuta Azumi
Yuta Azumi

🖋
andrewjbarbour
andrewjbarbour

🖋
mr
mr

🖋
Aleksandar
Aleksandar

🖋
Owl
Owl

🖋
Yedidya Schwartz
Yedidya Schwartz

🖋 💡
ari
ari

🖋
Thomas König
Thomas König

🖋
Kalle Lämsä
Kalle Lämsä

🖋
Wyatt
Wyatt

🖋
KHADIR Tayeb
KHADIR Tayeb

🖋
Shankar Regmi
Shankar Regmi

🖋
Shubham
Shubham

🖋
Lucas Alves
Lucas Alves

🖋
Benjamin
Benjamin

🖋
Yeoh Joer
Yeoh Joer

🖋
Miigon
Miigon

🖋
Rostislav Bogorad
Rostislav Bogorad

🖋
Flouse
Flouse

🖋
Tarantini Pereira
Tarantini Pereira

🖋
Kazuki Matsuo
Kazuki Matsuo

🖋
Adam Smith
Adam Smith

🖋
Dohyeon Ko
Dohyeon Ko

🖋
Vladislav Legkov
Vladislav Legkov

🖋
Kerollos Magdy
Kerollos Magdy

🖋
Erez Lieberman
Erez Lieberman

🖋
Breno Macedo
Breno Macedo

🖋
Fernando Flores
Fernando Flores

🌍
Rafael Brito
Rafael Brito

🌍
Emiliano Peralta
Emiliano Peralta

🌍
Shin, SJ
Shin, SJ

🖋
Benjamin Forster
Benjamin Forster

🖋
Daniele Fedeli
Daniele Fedeli

🖋
djob195
djob195

🖋
antspk
antspk

🖋
정진영
정진영

🖋
kkk-cashwalk
kkk-cashwalk

🖋
apainintheneck
apainintheneck

🖋
Fajar Budhi Iswanda
Fajar Budhi Iswanda

🖋
이주호
이주호

🖋
Singh
Singh

🖋
Alex Dumitru
Alex Dumitru

🖋
Anton Lykhatskyi
Anton Lykhatskyi

🖋
sangwonlee
sangwonlee

🖋
Eugenio Berretta
Eugenio Berretta

🖋
soranakk
soranakk

🖋
고준영
고준영

🖋 💻
Guilherme Portella
Guilherme Portella

🖋
André Esser
André Esser

🖋
Scc
Scc

🌍
Mauro Accornero
Mauro Accornero

🖋
no-yan
no-yan

🖋
diff --git a/README.japanese.md b/README.japanese.md index c4c3e2380..7ec6e9559 100644 --- a/README.japanese.md +++ b/README.japanese.md @@ -259,7 +259,7 @@ function someFunction() { } // Avoid -function someFunction() +function someFunction() { // code block } @@ -279,7 +279,7 @@ function someFunction() **さもないと:** 前のセクションで見たように、JavaScript のインタプリタは、セミコロンがない場合は自動的に文の最後にセミコロンを追加したり、ステートメントが本来あるべき場所で終わっていないとみなしたりすることで、望まない結果になってしまう可能性があります。代入を使用し、即時に呼び出された関数式の使用を避けることで、予期せぬエラーのほとんどを防ぐことができます。 -### コード例 +### 3.4 コード例 ```javascript // する @@ -347,7 +347,7 @@ function doSomething() {}

-## ![✔] 3.7 let よりも const を優先してください。var はいりません。 +## ![✔] 3.7 let よりも const を優先してください。var はいりません **TL;DR:** `const` を使うということは、一度代入された変数は再代入できないということを意味します。`const` を優先することで、同じ変数を異なる用途に使いたくなることを防ぎ、コードをより明確にすることができます。変数を再割り当てする必要がある場合、例えば for ループの中などでは、`let` を使って宣言します。もう一つの重要な点は、`let` を使って宣言された変数は、それが定義されたブロックスコープ内でのみ利用可能であるということです。`var` はブロックスコープではなく関数スコープであり、[ES6 では使うべきではない](https://hackernoon.com/why-you-shouldnt-use-var-anymore-f109a58b9b70) ので、`const` と `let` がある以上必要ありません。 @@ -1056,7 +1056,7 @@ null == undefined; // true **TL;DR:** CPU 集約的なタスクは、主にシングルスレッドのイベントループをブロックし、専用のスレッド、プロセス、またはコンテキストに基づいて別の技術にそれらをオフロードするため、避けてください。 -**さもないと:** イベントループがブロックされると、Node.js は他のリクエストを処理することができなくなり、同時接続ユーザーの遅延を引き起こします。**3000 人のユーザーがレスポンスを待っていて、コンテンツを提供する準備ができていたとしても、1 つのリクエストがサーバからの結果のディスパッチをブロックしていしまいます\*** +**さもないと:** イベントループがブロックされると、Node.js は他のリクエストを処理することができなくなり、同時接続ユーザーの遅延を引き起こします。**3000 人のユーザーがレスポンスを待っていて、コンテンツを提供する準備ができていたとしても、1 つのリクエストがサーバからの結果のディスパッチをブロックしていしまいます** 🔗 [**さらに読む: イベントループをブロックしない**](./sections/performance/block-loop.japanese.md) @@ -1367,204 +1367,259 @@ JavaScript とそのエコシステム(React、Node.js、TypeScript、GraphQL - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

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

📖

Forresst

🖋

Jonathan Svenheden

🖋

AustrisC

🖋

kyeongtae kim

🌍

007

🖋

Ane Diaz de Tuesta

🌍 🖋

YukiOta

🌍

Frazer Smith

🖋

Raz Luvaton

🖋

Yuta Azumi

🖋

andrewjbarbour

🖋

mr

🖋

Aleksandar

🖋

Owl

🖋

Yedidya Schwartz

🖋 💡

ari

🖋

Thomas König

🖋

Kalle Lämsä

🖋

Wyatt

🖋

KHADIR Tayeb

🖋
Kevin Rambaud
Kevin Rambaud

🖋
Michael Fine
Michael Fine

🖋
Shreya Dahal
Shreya Dahal

🖋
Matheus Cruz Rocha
Matheus Cruz Rocha

🖋
Yog Mehta
Yog Mehta

🖋
Kudakwashe Paradzayi
Kudakwashe Paradzayi

🖋
t1st3
t1st3

🖋
mulijordan1976
mulijordan1976

🖋
Matan Kushner
Matan Kushner

🖋
Fabio Hiroki
Fabio Hiroki

🖋
James Sumners
James Sumners

🖋
Dan Gamble
Dan Gamble

🖋
PJ Trainor
PJ Trainor

🖋
Remek Ambroziak
Remek Ambroziak

🖋
Yoni Jah
Yoni Jah

🖋
Misha Khokhlov
Misha Khokhlov

🖋
Evgeny Orekhov
Evgeny Orekhov

🖋
-
-

🖋
Isaac Halvorson
Isaac Halvorson

🖋
Vedran Karačić
Vedran Karačić

🖋
lallenlowe
lallenlowe

🖋
Nathan Wells
Nathan Wells

🖋
Paulo Reis
Paulo Reis

🖋
syzer
syzer

🖋
David Sancho
David Sancho

🖋
Robert Manolea
Robert Manolea

🖋
Xavier Ho
Xavier Ho

🖋
Aaron
Aaron

🖋
Jan Charles Maghirang Adona
Jan Charles Maghirang Adona

🖋
Allen
Allen

🖋
Leonardo Villela
Leonardo Villela

🖋
Michał Załęcki
Michał Załęcki

🖋
Chris Nicola
Chris Nicola

🖋
Alejandro Corredor
Alejandro Corredor

🖋
cwar
cwar

🖋
Yuwei
Yuwei

🖋
Utkarsh Bhatt
Utkarsh Bhatt

🖋
Duarte Mendes
Duarte Mendes

🖋
Jason Kim
Jason Kim

🖋
Mitja O.
Mitja O.

🖋
Sandro Miguel Marques
Sandro Miguel Marques

🖋
Gabe
Gabe

🖋
Ron Gross
Ron Gross

🖋
Valeri Karpov
Valeri Karpov

🖋
Sergio Bernal
Sergio Bernal

🖋
Nikola Telkedzhiev
Nikola Telkedzhiev

🖋
Vitor Godoy
Vitor Godoy

🖋
Manish Saraan
Manish Saraan

🖋
Sangbeom Han
Sangbeom Han

🖋
blackmatch
blackmatch

🖋
Joe Reeve
Joe Reeve

🖋
Ryan Busby
Ryan Busby

🖋
Iman Mohamadi
Iman Mohamadi

🖋
Sergii Paryzhskyi
Sergii Paryzhskyi

🖋
Kapil Patel
Kapil Patel

🖋
迷渡
迷渡

🖋
Hozefa
Hozefa

🖋
Ethan
Ethan

🖋
Sam
Sam

🖋
Arlind
Arlind

🖋
Teddy Toussaint
Teddy Toussaint

🖋
Lewis
Lewis

🖋
Gabriel Lidenor
Gabriel Lidenor

🖋
Roman
Roman

🖋
Francozeira
Francozeira

🖋
Invvard
Invvard

🖋
Rômulo Garofalo
Rômulo Garofalo

🖋
Tho Q Luong
Tho Q Luong

🖋
Burak Shen
Burak Shen

🖋
Martin Muzatko
Martin Muzatko

🖋
Jared Collier
Jared Collier

🖋
Hilton Meyer
Hilton Meyer

🖋
ChangJoo Park(박창주)
ChangJoo Park(박창주)

🖋
Masahiro Sakaguchi
Masahiro Sakaguchi

🖋
Keith Holliday
Keith Holliday

🖋
coreyc
coreyc

🖋
Maximilian Berkmann
Maximilian Berkmann

🖋
Douglas Mariano Valero
Douglas Mariano Valero

🖋
Marcelo Melo
Marcelo Melo

🖋
Mehmet Perk
Mehmet Perk

🖋
ryan ouyang
ryan ouyang

🖋
Shabeer
Shabeer

🖋
Eduard Kyvenko
Eduard Kyvenko

🖋
Deyvison Rocha
Deyvison Rocha

🖋
George Mamer
George Mamer

🖋
Konstantinos Leimonis
Konstantinos Leimonis

🖋
Oliver Lluberes
Oliver Lluberes

🌍
Tien Do
Tien Do

🖋
Ranvir Singh
Ranvir Singh

🖋
Vadim Nicolaev
Vadim Nicolaev

🖋 🌍
German Gamboa Gonzalez
German Gamboa Gonzalez

🖋
Hafez
Hafez

🖋
Chandiran
Chandiran

🖋
VinayaSathyanarayana
VinayaSathyanarayana

🖋
Kim Kern
Kim Kern

🖋
Kenneth Freitas
Kenneth Freitas

🖋
songe
songe

🖋
Kirill Shekhovtsov
Kirill Shekhovtsov

🖋
Serge
Serge

🖋
keyrwinz
keyrwinz

🖋
Dmitry Nikitenko
Dmitry Nikitenko

🖋
bushuai
bushuai

👀 🖋
Benjamin Gruenbaum
Benjamin Gruenbaum

🖋
Ezequiel
Ezequiel

🌍
Juan José Rodríguez
Juan José Rodríguez

🌍
Or Bin
Or Bin

🖋
Andreo Vieira
Andreo Vieira

🖋
Michael Solomon
Michael Solomon

🖋
Jimmy Callin
Jimmy Callin

🖋
Siddharth
Siddharth

🖋
Ryan Smith
Ryan Smith

🖋
Tom Boettger
Tom Boettger

🖋
Joaquín Ormaechea
Joaquín Ormaechea

🌍
dfrzuz
dfrzuz

🌍
Victor Homyakov
Victor Homyakov

🖋
Josh
Josh

🖋 🛡️
Alec Francis
Alec Francis

🖋
arjun6610
arjun6610

🖋
Jan Osch
Jan Osch

🖋
Thiago Rotondo Sampaio
Thiago Rotondo Sampaio

🌍
Alexsey
Alexsey

🖋
Luis A. Acurero
Luis A. Acurero

🌍
Lucas Romano
Lucas Romano

🌍
Denise Case
Denise Case

🖋
Nick Ribal
Nick Ribal

🖋 👀
0xflotus
0xflotus

🖋
Jonathan Chen
Jonathan Chen

🖋
Dilan Srilal
Dilan Srilal

🖋
vladthelittleone
vladthelittleone

🌍
Nik Osvalds
Nik Osvalds

🖋
Daniel Kiss
Daniel Kiss

📖
Forresst
Forresst

🖋
Jonathan Svenheden
Jonathan Svenheden

🖋
AustrisC
AustrisC

🖋
kyeongtae kim
kyeongtae kim

🌍
007
007

🖋
Ane Diaz de Tuesta
Ane Diaz de Tuesta

🌍 🖋
YukiOta
YukiOta

🌍
Frazer Smith
Frazer Smith

🖋
Raz Luvaton
Raz Luvaton

🖋
Yuta Azumi
Yuta Azumi

🖋
andrewjbarbour
andrewjbarbour

🖋
mr
mr

🖋
Aleksandar
Aleksandar

🖋
Owl
Owl

🖋
Yedidya Schwartz
Yedidya Schwartz

🖋 💡
ari
ari

🖋
Thomas König
Thomas König

🖋
Kalle Lämsä
Kalle Lämsä

🖋
Wyatt
Wyatt

🖋
KHADIR Tayeb
KHADIR Tayeb

🖋
Shankar Regmi
Shankar Regmi

🖋
Shubham
Shubham

🖋
Lucas Alves
Lucas Alves

🖋
Benjamin
Benjamin

🖋
Yeoh Joer
Yeoh Joer

🖋
Miigon
Miigon

🖋
Rostislav Bogorad
Rostislav Bogorad

🖋
Flouse
Flouse

🖋
Tarantini Pereira
Tarantini Pereira

🖋
Kazuki Matsuo
Kazuki Matsuo

🖋
Adam Smith
Adam Smith

🖋
Dohyeon Ko
Dohyeon Ko

🖋
Vladislav Legkov
Vladislav Legkov

🖋
Kerollos Magdy
Kerollos Magdy

🖋
Erez Lieberman
Erez Lieberman

🖋
Breno Macedo
Breno Macedo

🖋
Fernando Flores
Fernando Flores

🌍
Rafael Brito
Rafael Brito

🌍
Emiliano Peralta
Emiliano Peralta

🌍
Shin, SJ
Shin, SJ

🖋
Benjamin Forster
Benjamin Forster

🖋
Daniele Fedeli
Daniele Fedeli

🖋
djob195
djob195

🖋
antspk
antspk

🖋
정진영
정진영

🖋
kkk-cashwalk
kkk-cashwalk

🖋
apainintheneck
apainintheneck

🖋
Fajar Budhi Iswanda
Fajar Budhi Iswanda

🖋
이주호
이주호

🖋
Singh
Singh

🖋
Alex Dumitru
Alex Dumitru

🖋
Anton Lykhatskyi
Anton Lykhatskyi

🖋
sangwonlee
sangwonlee

🖋
Eugenio Berretta
Eugenio Berretta

🖋
soranakk
soranakk

🖋
고준영
고준영

🖋 💻
Guilherme Portella
Guilherme Portella

🖋
André Esser
André Esser

🖋
Scc
Scc

🌍
Mauro Accornero
Mauro Accornero

🖋
no-yan
no-yan

🖋
- + diff --git a/README.korean.md b/README.korean.md index c0d5716ba..a29f23351 100644 --- a/README.korean.md +++ b/README.korean.md @@ -30,15 +30,15 @@ # 최근 모범사례와 뉴스 -- **:tada: Node.js 모범사례가 4만 별에 도달했습니다**: 이 프로젝트가 지금 여기까지 올 수 있도록 도와주신 모든 협력자분들께 감사드립니다. 앞으로도 계속 늘어나는 Node.js 모범사례들을 추가하여 더욱더 확장시킬 계획입니다. +- **![FR](./assets/flags/FR.png) 프랑스어 번역!1! :** 우리의 국제 가이드에 합류한 최신 번역은 프랑스어입니다. Bienvenue(어서오세요.) -- **:rocket: 새로운 모범사례 둘 추가**: 그동안 열심히 만든 dependency state를 production 환경에서 미리 볼 수 있는 [npm ci 사용](https://github.com/goldbergyoni/nodebestpractices#-519-install-your-packages-with-npm-ci) 관련 부분과, [미들웨어 격리 테스트](https://github.com/goldbergyoni/nodebestpractices#-413-test-your-middlewares-in-isolation)에 관한 새로운 모범사례들을 두 개 추가했습니다. +- **🇯🇵 Japanese translation:** 우리 가이드는 이제 일본어로도 번역됩니다! 뛰어난 [YukiOta](https://github.com/YukiOta)와 [Yuta Azumi](https://github.com/YA21)의 제공입니다. -- **:whale: Node.js + Docker 모범사례**: dockerized 된 Node.js 애플리케이션 관련 모범사례 [아이디어 수집](https://github.com/goldbergyoni/nodebestpractices/issues/620)을 개시합니다. 그 외에 다른 모범사례가 있다면 주저말고 대화에 참여해주세요! +- **🎊 60,000 stars!**: 우리 리포지토리는 60,100명의 개발자에게 별을 받고 신뢰를 얻었습니다. 말문이 막힐 정도입니다.

-# 어서오세요! 먼저 이 3가지를 알아두세요: +# 어서오세요! 먼저 이 3가지를 알아두세요 **1. 이 문서를 읽는 것은 베스트 Node.js 문서 수십개를 읽는 것과 같습니다. -** 이 문서는 Node.js 의 가장 일반적인 Best Practice 모범사례들을 모은 요약집 및 큐레이션입니다. @@ -279,7 +279,7 @@ function someFunction() **그렇게 하지 않을 경우:** 이전 섹션에서 본것처럼 자바스크립트의 인터프리터는 세미콜론이 없으면 자동으로 문장의 끝에 세미콜론을 붙이거나, 문장이 끝났어야 함에도 끝났다고 인지하지 못하여 의도되지 않은 결과를 야기할 수 있다. 대부분의 의도하지 않은 에러들은 assignment를 사용하고 imediate invoked function expression을 사용하는 것을 피함으로써 예방할 수 있다. -### 코드 예제 +### 3.4 코드 예제 ```javascript // 좋은 예 @@ -371,7 +371,7 @@ function doSomething() {} **그렇게 하지 않을 경우:** 파일 내부의 구조 혹은 서명을 변경하면 클라이언트와의 인터페이스가 손상될 수 있다. -### 코드 예제 +### 3.9 코드 예제 ```javascript // 좋은 예 @@ -391,7 +391,7 @@ module.exports.SMSNumberResolver = require("./SMSNumberResolver/SMSNumberResolve **그렇게 하지 않을 경우:** `==`으로 비교하는 경우 같지 않은 변수가 true로 반환 될 수있다. -### 코드 예제 +### 3.10 코드 예제 ```javascript "" == "0"; // false @@ -1173,204 +1173,259 @@ null == undefined; // true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

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

📖

Forresst

🖋

Jonathan Svenheden

🖋

AustrisC

🖋

kyeongtae kim

🌍

007

🖋

Ane Diaz de Tuesta

🌍 🖋

YukiOta

🌍

Frazer Smith

🖋

Raz Luvaton

🖋

Yuta Azumi

🖋

andrewjbarbour

🖋

mr

🖋

Aleksandar

🖋

Owl

🖋

Yedidya Schwartz

🖋 💡

ari

🖋

Thomas König

🖋

Kalle Lämsä

🖋

Wyatt

🖋

KHADIR Tayeb

🖋
Kevin Rambaud
Kevin Rambaud

🖋
Michael Fine
Michael Fine

🖋
Shreya Dahal
Shreya Dahal

🖋
Matheus Cruz Rocha
Matheus Cruz Rocha

🖋
Yog Mehta
Yog Mehta

🖋
Kudakwashe Paradzayi
Kudakwashe Paradzayi

🖋
t1st3
t1st3

🖋
mulijordan1976
mulijordan1976

🖋
Matan Kushner
Matan Kushner

🖋
Fabio Hiroki
Fabio Hiroki

🖋
James Sumners
James Sumners

🖋
Dan Gamble
Dan Gamble

🖋
PJ Trainor
PJ Trainor

🖋
Remek Ambroziak
Remek Ambroziak

🖋
Yoni Jah
Yoni Jah

🖋
Misha Khokhlov
Misha Khokhlov

🖋
Evgeny Orekhov
Evgeny Orekhov

🖋
-
-

🖋
Isaac Halvorson
Isaac Halvorson

🖋
Vedran Karačić
Vedran Karačić

🖋
lallenlowe
lallenlowe

🖋
Nathan Wells
Nathan Wells

🖋
Paulo Reis
Paulo Reis

🖋
syzer
syzer

🖋
David Sancho
David Sancho

🖋
Robert Manolea
Robert Manolea

🖋
Xavier Ho
Xavier Ho

🖋
Aaron
Aaron

🖋
Jan Charles Maghirang Adona
Jan Charles Maghirang Adona

🖋
Allen
Allen

🖋
Leonardo Villela
Leonardo Villela

🖋
Michał Załęcki
Michał Załęcki

🖋
Chris Nicola
Chris Nicola

🖋
Alejandro Corredor
Alejandro Corredor

🖋
cwar
cwar

🖋
Yuwei
Yuwei

🖋
Utkarsh Bhatt
Utkarsh Bhatt

🖋
Duarte Mendes
Duarte Mendes

🖋
Jason Kim
Jason Kim

🖋
Mitja O.
Mitja O.

🖋
Sandro Miguel Marques
Sandro Miguel Marques

🖋
Gabe
Gabe

🖋
Ron Gross
Ron Gross

🖋
Valeri Karpov
Valeri Karpov

🖋
Sergio Bernal
Sergio Bernal

🖋
Nikola Telkedzhiev
Nikola Telkedzhiev

🖋
Vitor Godoy
Vitor Godoy

🖋
Manish Saraan
Manish Saraan

🖋
Sangbeom Han
Sangbeom Han

🖋
blackmatch
blackmatch

🖋
Joe Reeve
Joe Reeve

🖋
Ryan Busby
Ryan Busby

🖋
Iman Mohamadi
Iman Mohamadi

🖋
Sergii Paryzhskyi
Sergii Paryzhskyi

🖋
Kapil Patel
Kapil Patel

🖋
迷渡
迷渡

🖋
Hozefa
Hozefa

🖋
Ethan
Ethan

🖋
Sam
Sam

🖋
Arlind
Arlind

🖋
Teddy Toussaint
Teddy Toussaint

🖋
Lewis
Lewis

🖋
Gabriel Lidenor
Gabriel Lidenor

🖋
Roman
Roman

🖋
Francozeira
Francozeira

🖋
Invvard
Invvard

🖋
Rômulo Garofalo
Rômulo Garofalo

🖋
Tho Q Luong
Tho Q Luong

🖋
Burak Shen
Burak Shen

🖋
Martin Muzatko
Martin Muzatko

🖋
Jared Collier
Jared Collier

🖋
Hilton Meyer
Hilton Meyer

🖋
ChangJoo Park(박창주)
ChangJoo Park(박창주)

🖋
Masahiro Sakaguchi
Masahiro Sakaguchi

🖋
Keith Holliday
Keith Holliday

🖋
coreyc
coreyc

🖋
Maximilian Berkmann
Maximilian Berkmann

🖋
Douglas Mariano Valero
Douglas Mariano Valero

🖋
Marcelo Melo
Marcelo Melo

🖋
Mehmet Perk
Mehmet Perk

🖋
ryan ouyang
ryan ouyang

🖋
Shabeer
Shabeer

🖋
Eduard Kyvenko
Eduard Kyvenko

🖋
Deyvison Rocha
Deyvison Rocha

🖋
George Mamer
George Mamer

🖋
Konstantinos Leimonis
Konstantinos Leimonis

🖋
Oliver Lluberes
Oliver Lluberes

🌍
Tien Do
Tien Do

🖋
Ranvir Singh
Ranvir Singh

🖋
Vadim Nicolaev
Vadim Nicolaev

🖋 🌍
German Gamboa Gonzalez
German Gamboa Gonzalez

🖋
Hafez
Hafez

🖋
Chandiran
Chandiran

🖋
VinayaSathyanarayana
VinayaSathyanarayana

🖋
Kim Kern
Kim Kern

🖋
Kenneth Freitas
Kenneth Freitas

🖋
songe
songe

🖋
Kirill Shekhovtsov
Kirill Shekhovtsov

🖋
Serge
Serge

🖋
keyrwinz
keyrwinz

🖋
Dmitry Nikitenko
Dmitry Nikitenko

🖋
bushuai
bushuai

👀 🖋
Benjamin Gruenbaum
Benjamin Gruenbaum

🖋
Ezequiel
Ezequiel

🌍
Juan José Rodríguez
Juan José Rodríguez

🌍
Or Bin
Or Bin

🖋
Andreo Vieira
Andreo Vieira

🖋
Michael Solomon
Michael Solomon

🖋
Jimmy Callin
Jimmy Callin

🖋
Siddharth
Siddharth

🖋
Ryan Smith
Ryan Smith

🖋
Tom Boettger
Tom Boettger

🖋
Joaquín Ormaechea
Joaquín Ormaechea

🌍
dfrzuz
dfrzuz

🌍
Victor Homyakov
Victor Homyakov

🖋
Josh
Josh

🖋 🛡️
Alec Francis
Alec Francis

🖋
arjun6610
arjun6610

🖋
Jan Osch
Jan Osch

🖋
Thiago Rotondo Sampaio
Thiago Rotondo Sampaio

🌍
Alexsey
Alexsey

🖋
Luis A. Acurero
Luis A. Acurero

🌍
Lucas Romano
Lucas Romano

🌍
Denise Case
Denise Case

🖋
Nick Ribal
Nick Ribal

🖋 👀
0xflotus
0xflotus

🖋
Jonathan Chen
Jonathan Chen

🖋
Dilan Srilal
Dilan Srilal

🖋
vladthelittleone
vladthelittleone

🌍
Nik Osvalds
Nik Osvalds

🖋
Daniel Kiss
Daniel Kiss

📖
Forresst
Forresst

🖋
Jonathan Svenheden
Jonathan Svenheden

🖋
AustrisC
AustrisC

🖋
kyeongtae kim
kyeongtae kim

🌍
007
007

🖋
Ane Diaz de Tuesta
Ane Diaz de Tuesta

🌍 🖋
YukiOta
YukiOta

🌍
Frazer Smith
Frazer Smith

🖋
Raz Luvaton
Raz Luvaton

🖋
Yuta Azumi
Yuta Azumi

🖋
andrewjbarbour
andrewjbarbour

🖋
mr
mr

🖋
Aleksandar
Aleksandar

🖋
Owl
Owl

🖋
Yedidya Schwartz
Yedidya Schwartz

🖋 💡
ari
ari

🖋
Thomas König
Thomas König

🖋
Kalle Lämsä
Kalle Lämsä

🖋
Wyatt
Wyatt

🖋
KHADIR Tayeb
KHADIR Tayeb

🖋
Shankar Regmi
Shankar Regmi

🖋
Shubham
Shubham

🖋
Lucas Alves
Lucas Alves

🖋
Benjamin
Benjamin

🖋
Yeoh Joer
Yeoh Joer

🖋
Miigon
Miigon

🖋
Rostislav Bogorad
Rostislav Bogorad

🖋
Flouse
Flouse

🖋
Tarantini Pereira
Tarantini Pereira

🖋
Kazuki Matsuo
Kazuki Matsuo

🖋
Adam Smith
Adam Smith

🖋
Dohyeon Ko
Dohyeon Ko

🖋
Vladislav Legkov
Vladislav Legkov

🖋
Kerollos Magdy
Kerollos Magdy

🖋
Erez Lieberman
Erez Lieberman

🖋
Breno Macedo
Breno Macedo

🖋
Fernando Flores
Fernando Flores

🌍
Rafael Brito
Rafael Brito

🌍
Emiliano Peralta
Emiliano Peralta

🌍
Shin, SJ
Shin, SJ

🖋
Benjamin Forster
Benjamin Forster

🖋
Daniele Fedeli
Daniele Fedeli

🖋
djob195
djob195

🖋
antspk
antspk

🖋
정진영
정진영

🖋
kkk-cashwalk
kkk-cashwalk

🖋
apainintheneck
apainintheneck

🖋
Fajar Budhi Iswanda
Fajar Budhi Iswanda

🖋
이주호
이주호

🖋
Singh
Singh

🖋
Alex Dumitru
Alex Dumitru

🖋
Anton Lykhatskyi
Anton Lykhatskyi

🖋
sangwonlee
sangwonlee

🖋
Eugenio Berretta
Eugenio Berretta

🖋
soranakk
soranakk

🖋
고준영
고준영

🖋 💻
Guilherme Portella
Guilherme Portella

🖋
André Esser
André Esser

🖋
Scc
Scc

🌍
Mauro Accornero
Mauro Accornero

🖋
no-yan
no-yan

🖋
- + diff --git a/README.md b/README.md index 0201a997a..065d37585 100644 --- a/README.md +++ b/README.md @@ -9,12 +9,12 @@
- 102 items Last update: July 14, 2021 Updated for Node 14.0.0 + 102 items Last update: January 3rd, 2024 Updated for Node 22.0.0

-[![nodepractices](./assets/images/twitter-s.png)](https://twitter.com/nodepractices/) **Follow us on Twitter!** [**@nodepractices**](https://twitter.com/nodepractices/) +[](https://twitter.com/nodepractices/) **Follow us on Twitter!** [**@nodepractices**](https://twitter.com/nodepractices/)
@@ -22,15 +22,13 @@ Read in a different language: [![CN](./assets/flags/CN.png)**CN**](./README.chin
-###### Built and maintained by our [Steering Committee](#steering-committee) and [Collaborators](#collaborators) +# 🎊 2024 edition is here! -# Latest Best Practices and News +- **🛰 Modernized to 2024**: Tons of text edits, new recommended libraries, and some new best practices -- **![FR](./assets/flags/FR.png) French translation!1! :** The latest translation that joins our international guide is French. Bienvenue +- **✨ Easily focus on new content**: Already visited before? Search for `#new` or `#updated` tags for new content only -- **🇯🇵 Japanese translation:** Our guide is now also translated to Japanese! Courtesy of the amazing [YukiOta](https://github.com/YukiOta) and [Yuta Azumi](https://github.com/YA21) - -- **🎊 60,000 stars!**: Our repo was starred and trusted by 60,100 developers. We're speechless +- **🔖 Curious to see examples? We have a starter**: Visit [Practica.js](https://github.com/practicajs/practica), our application example and boilerplate (beta) to see some practices in action

@@ -44,68 +42,289 @@ Read in a different language: [![CN](./assets/flags/CN.png)**CN**](./README.chin

-## Table of Contents +# By Yoni Goldberg -1. [Project Structure Practices (5)](#1-project-structure-practices) -2. [Error Handling Practices (12) ](#2-error-handling-practices) -3. [Code Style Practices (12) ](#3-code-style-practices) -4. [Testing And Overall Quality Practices (13) ](#4-testing-and-overall-quality-practices) -5. [Going To Production Practices (19) ](#5-going-to-production-practices) -6. [Security Practices (25)](#6-security-best-practices) -7. [Performance Practices (2) (Work In Progress️ ✍️)](#7-draft-performance-best-practices) -8. [Docker Practices (15)](#8-docker-best-practices) +### Learn with me: As a consultant, I engage with worldwide teams on various activities like workshops and code reviews. 🎉AND... Hold on, I've just launched my [beyond-the-basics testing course, which is on a 🎁 limited-time sale](https://testjavascript.com/) until August 7th

-# `1. Project Structure Practices` - -## ![✔] 1.1 Structure your solution by components +## Table of Contents -**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 +
+ + 1. Project Architecture Practices (6) + + +  [1.1 Structure your solution by components `#strategic` `#updated`](#-11-structure-your-solution-by-business-components)
+  [1.2 Layer your components, keep the web layer within its boundaries `#strategic` `#updated`](#-12-layer-your-components-with-3-tiers-keep-the-web-layer-within-its-boundaries)
+  [1.3 Wrap common utilities as packages, consider publishing](#-13-wrap-common-utilities-as-packages-consider-publishing)
+  [1.4 Use environment aware, secure and hierarchical config `#updated`](#-14-use-environment-aware-secure-and-hierarchical-config)
+  [1.5 Consider all the consequences when choosing the main framework `#new`](#-15-consider-all-the-consequences-when-choosing-the-main-framework)
+  [1.6 Use TypeScript sparingly and thoughtfully `#new`](#-16-use-typescript-sparingly-and-thoughtfully)
+ +
+ +
+ + 2. Error Handling Practices (12) + + +  [2.1 Use Async-Await or promises for async error handling](#-21-use-async-await-or-promises-for-async-error-handling)
+  [2.2 Extend the built-in Error object `#strategic` `#updated`](#-22-extend-the-built-in-error-object)
+  [2.3 Distinguish operational vs programmer errors `#strategic` `#updated`](#-23-distinguish-catastrophic-errors-from-operational-errors)
+  [2.4 Handle errors centrally, not within a middleware `#strategic`](#-24-handle-errors-centrally-not-within-a-middleware)
+  [2.5 Document API errors using OpenAPI or GraphQL](#-25-document-api-errors-using-openapi-or-graphql)
+  [2.6 Exit the process gracefully when a stranger comes to town `#strategic`](#-26-exit-the-process-gracefully-when-a-stranger-comes-to-town)
+  [2.7 Use a mature logger to increase errors visibility `#updated`](#-27-use-a-mature-logger-to-increase-errors-visibility)
+  [2.8 Test error flows using your favorite test framework `#updated`](#-28-test-error-flows-using-your-favorite-test-framework)
+  [2.9 Discover errors and downtime using APM products](#-29-discover-errors-and-downtime-using-apm-products)
+  [2.10 Catch unhandled promise rejections `#updated`](#-210-catch-unhandled-promise-rejections)
+  [2.11 Fail fast, validate arguments using a dedicated library](#-211-fail-fast-validate-arguments-using-a-dedicated-library)
+  [2.12 Always await promises before returning to avoid a partial stacktrace `#new`](#-212-always-await-promises-before-returning-to-avoid-a-partial-stacktrace)
+  [2.13 Subscribe to event emitters 'error' event `#new`](#-213-subscribe-to-event-emitters-and-streams-error-event)
+ +
+ +
+ + 3. Code Style Practices (12) + + +  [3.1 Use ESLint `#strategic`](#-31-use-eslint)
+  [3.2 Use Node.js eslint extension plugins `#updated`](#-32-use-nodejs-eslint-extension-plugins)
+  [3.3 Start a Codeblock's Curly Braces on the Same Line](#-33-start-a-codeblocks-curly-braces-on-the-same-line)
+  [3.4 Separate your statements properly](#-34-separate-your-statements-properly)
+  [3.5 Name your functions](#-35-name-your-functions)
+  [3.6 Use naming conventions for variables, constants, functions and classes](#-36-use-naming-conventions-for-variables-constants-functions-and-classes)
+  [3.7 Prefer const over let. Ditch the var](#-37-prefer-const-over-let-ditch-the-var)
+  [3.8 Require modules first, not inside functions](#-38-require-modules-first-not-inside-functions)
+  [3.9 Set an explicit entry point to a module/folder `#updated`](#-39-set-an-explicit-entry-point-to-a-modulefolder)
+  [3.10 Use the === operator](#-310-use-the--operator)
+  [3.11 Use Async Await, avoid callbacks `#strategic`](#-311-use-async-await-avoid-callbacks)
+  [3.12 Use arrow function expressions (=>)](#-312-use-arrow-function-expressions-)
+  [3.13 Avoid effects outside of functions `#new`](#-313-avoid-effects-outside-of-functions)
+ +
+ +
+ + 4. Testing And Overall Quality Practices (13) + + +  [4.1 At the very least, write API (component) testing `#strategic`](#-41-at-the-very-least-write-api-component-testing)
+  [4.2 Include 3 parts in each test name `#new`](#-42-include-3-parts-in-each-test-name)
+  [4.3 Structure tests by the AAA pattern `#strategic`](#-43-structure-tests-by-the-aaa-pattern)
+  [4.4 Ensure Node version is unified `#new`](#-44-ensure-node-version-is-unified)
+  [4.5 Avoid global test fixtures and seeds, add data per-test `#strategic`](#-45-avoid-global-test-fixtures-and-seeds-add-data-per-test)
+  [4.6 Tag your tests `#advanced`](#-46-tag-your-tests)
+  [4.7 Check your test coverage, it helps to identify wrong test patterns](#-47-check-your-test-coverage-it-helps-to-identify-wrong-test-patterns)
+  [4.8 Use production-like environment for e2e testing](#-48-use-production-like-environment-for-e2e-testing)
+  [4.9 Refactor regularly using static analysis tools](#-49-refactor-regularly-using-static-analysis-tools)
+  [4.10 Mock responses of external HTTP services #advanced `#new` `#advanced`](#-410-mock-responses-of-external-http-services)
+  [4.11 Test your middlewares in isolation](#-411-test-your-middlewares-in-isolation)
+  [4.12 Specify a port in production, randomize in testing `#new`](#-412-specify-a-port-in-production-randomize-in-testing)
+  [4.13 Test the five possible outcomes #strategic `#new`](#-413-test-the-five-possible-outcomes)
+ +
+ +
+ + 5. Going To Production Practices (19) + + +  [5.1. Monitoring `#strategic`](#-51-monitoring)
+  [5.2. Increase the observability using smart logging `#strategic`](#-52-increase-the-observability-using-smart-logging)
+  [5.3. Delegate anything possible (e.g. gzip, SSL) to a reverse proxy `#strategic`](#-53-delegate-anything-possible-eg-gzip-ssl-to-a-reverse-proxy)
+  [5.4. Lock dependencies](#-54-lock-dependencies)
+  [5.5. Guard process uptime using the right tool](#-55-guard-process-uptime-using-the-right-tool)
+  [5.6. Utilize all CPU cores](#-56-utilize-all-cpu-cores)
+  [5.7. Create a ‘maintenance endpoint’](#-57-create-a-maintenance-endpoint)
+  [5.8. Discover the unknowns using APM products `#advanced` `#updated`](#-58-discover-the-unknowns-using-apm-products)
+  [5.9. Make your code production-ready](#-59-make-your-code-production-ready)
+  [5.10. Measure and guard the memory usage `#advanced`](#-510-measure-and-guard-the-memory-usage)
+  [5.11. Get your frontend assets out of Node](#-511-get-your-frontend-assets-out-of-node)
+  [5.12. Strive to be stateless `#strategic`](#-512-strive-to-be-stateless)
+  [5.13. Use tools that automatically detect vulnerabilities](#-513-use-tools-that-automatically-detect-vulnerabilities)
+  [5.14. Assign a transaction id to each log statement `#advanced`](#-514-assign-a-transaction-id-to-each-log-statement)
+  [5.15. Set NODE_ENV=production](#-515-set-node_envproduction)
+  [5.16. Design automated, atomic and zero-downtime deployments `#advanced`](#-516-design-automated-atomic-and-zero-downtime-deployments)
+  [5.17. Use an LTS release of Node.js](#-517-use-an-lts-release-of-nodejs)
+  [5.18. Log to stdout, avoid specifying log destination within the app `#updated`](#-518-log-to-stdout-avoid-specifying-log-destination-within-the-app)
+  [5.19. Install your packages with npm ci `#new`](#-519-install-your-packages-with-npm-ci)
+ +
+ +
+ + 6. Security Practices (25) + + +  [6.1. Embrace linter security rules](#-61-embrace-linter-security-rules)
+  [6.2. Limit concurrent requests using a middleware](#-62-limit-concurrent-requests-using-a-middleware)
+  [6.3 Extract secrets from config files or use packages to encrypt them `#strategic`](#-63-extract-secrets-from-config-files-or-use-packages-to-encrypt-them)
+  [6.4. Prevent query injection vulnerabilities with ORM/ODM libraries `#strategic`](#-64-prevent-query-injection-vulnerabilities-with-ormodm-libraries)
+  [6.5. Collection of generic security best practices](#-65-collection-of-generic-security-best-practices)
+  [6.6. Adjust the HTTP response headers for enhanced security](#-66-adjust-the-http-response-headers-for-enhanced-security)
+  [6.7. Constantly and automatically inspect for vulnerable dependencies `#strategic`](#-67-constantly-and-automatically-inspect-for-vulnerable-dependencies)
+  [6.8. Protect Users' Passwords/Secrets using bcrypt or scrypt `#strategic`](#-68-protect-users-passwordssecrets-using-bcrypt-or-scrypt)
+  [6.9. Escape HTML, JS and CSS output](#-69-escape-html-js-and-css-output)
+  [6.10. Validate incoming JSON schemas `#strategic`](#-610-validate-incoming-json-schemas)
+  [6.11. Support blocklisting JWTs](#-611-support-blocklisting-jwts)
+  [6.12. Prevent brute-force attacks against authorization `#advanced`](#-612-prevent-brute-force-attacks-against-authorization)
+  [6.13. Run Node.js as non-root user](#-613-run-nodejs-as-non-root-user)
+  [6.14. Limit payload size using a reverse-proxy or a middleware](#-614-limit-payload-size-using-a-reverse-proxy-or-a-middleware)
+  [6.15. Avoid JavaScript eval statements](#-615-avoid-javascript-eval-statements)
+  [6.16. Prevent evil RegEx from overloading your single thread execution](#-616-prevent-evil-regex-from-overloading-your-single-thread-execution)
+  [6.17. Avoid module loading using a variable](#-617-avoid-module-loading-using-a-variable)
+  [6.18. Run unsafe code in a sandbox](#-618-run-unsafe-code-in-a-sandbox)
+  [6.19. Take extra care when working with child processes `#advanced`](#-619-take-extra-care-when-working-with-child-processes)
+  [6.20. Hide error details from clients](#-620-hide-error-details-from-clients)
+  [6.21. Configure 2FA for npm or Yarn `#strategic`](#-621-configure-2fa-for-npm-or-yarn)
+  [6.22. Modify session middleware settings](#-622-modify-session-middleware-settings)
+  [6.23. Avoid DOS attacks by explicitly setting when a process should crash `#advanced`](#-623-avoid-dos-attacks-by-explicitly-setting-when-a-process-should-crash)
+  [6.24. Prevent unsafe redirects](#-624-prevent-unsafe-redirects)
+  [6.25. Avoid publishing secrets to the npm registry](#-625-avoid-publishing-secrets-to-the-npm-registry)
+  [6.26. 6.26 Inspect for outdated packages](#-626-inspect-for-outdated-packages)
+  [6.27. Import built-in modules using the 'node:' protocol `#new`](#-627-import-built-in-modules-using-the-node-protocol)
+ +
+ +
+ + 7. Performance Practices (2) (Work In Progress️ ✍️) + + +  [7.1. Don't block the event loop](#-71-dont-block-the-event-loop)
+  [7.2. Prefer native JS methods over user-land utils like Lodash](#-72-prefer-native-js-methods-over-user-land-utils-like-lodash)
+ +
+ +
+ + 8. Docker Practices (15) + + +  [8.1 Use multi-stage builds for leaner and more secure Docker images `#strategic`](#-81-use-multi-stage-builds-for-leaner-and-more-secure-docker-images)
+  [8.2. Bootstrap using node command, avoid npm start](#-82-bootstrap-using-node-command-avoid-npm-start)
+  [8.3. Let the Docker runtime handle replication and uptime `#strategic`](#-83-let-the-docker-runtime-handle-replication-and-uptime)
+  [8.4. Use .dockerignore to prevent leaking secrets](#-84-use-dockerignore-to-prevent-leaking-secrets)
+  [8.5. Clean-up dependencies before production](#-85-clean-up-dependencies-before-production)
+  [8.6. Shutdown smartly and gracefully `#advanced`](#-86-shutdown-smartly-and-gracefully)
+  [8.7. Set memory limits using both Docker and v8 `#advanced` `#strategic`](#-87-set-memory-limits-using-both-docker-and-v8)
+  [8.8. Plan for efficient caching](#-88-plan-for-efficient-caching)
+  [8.9. Use explicit image reference, avoid latest tag](#-89-use-explicit-image-reference-avoid-latest-tag)
+  [8.10. Prefer smaller Docker base images](#-810-prefer-smaller-docker-base-images)
+  [8.11. Clean-out build-time secrets, avoid secrets in args `#strategic #new`](#-811-clean-out-build-time-secrets-avoid-secrets-in-args)
+  [8.12. Scan images for multi layers of vulnerabilities `#advanced`](#-812-scan-images-for-multi-layers-of-vulnerabilities)
+  [8.13 Clean NODE_MODULE cache](#-813-clean-node_module-cache)
+  [8.14. Generic Docker practices](#-814-generic-docker-practices)
+  [8.15. Lint your Dockerfile `#new`](#-815-lint-your-dockerfile)
+ +
+ +

+ +# `1. Project Architecture Practices` + +## ![✔] 1.1 Structure your solution by business components + +### `📝 #updated` + +**TL;DR:** The root of a system should contain folders or repositories that represent reasonably sized business modules. Each component represents a product domain (i.e., bounded context), like 'user-component', 'order-component', etc. Each component has its own API, logic, and logical database. What is the significant merit? With an autonomous component, every change is performed over a granular and smaller scope - the mental overload, development friction, and deployment fear are much smaller and better. As a result, developers can move much faster. This does not necessarily demand physical separation and can be achieved using a Monorepo or with a multi-repo + +```bash +my-system +├─ apps (components) +│ ├─ orders +│ ├─ users +│ ├─ payments +├─ libraries (generic cross-component functionality) +│ ├─ logger +│ ├─ authenticator +``` -**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 +**Otherwise:** when artifacts from various modules/topics are mixed together, there are great chances of a tightly-coupled 'spaghetti' system. For example, in an architecture where 'module-a controller' might call 'module-b service', there are no clear modularity borders - every code change might affect anything else. With this approach, developers who code new features struggle to realize the scope and impact of their change. Consequently, they fear breaking other modules, and each deployment becomes slower and riskier 🔗 [**Read More: structure by components**](./sections/projectstructre/breakintcomponents.md)

-## ![✔] 1.2 Layer your components, keep the web layer within its boundaries +## ![✔] 1.2 Layer your components with 3-tiers, keep the web layer within its boundaries -**TL;DR:** Each component should contain 'layers' - a dedicated object for the web, logic, and data access code. This not only draws a clean separation of concerns but also significantly eases mocking and testing the system. Though this is a very common pattern, API developers tend to mix layers by passing the web layer objects (e.g. Express req, res) to business logic and data layers - this makes your application dependent on and accessible only by specific web frameworks +### `📝 #updated` -**Otherwise:** App that mixes web objects with other layers cannot be accessed by testing code, CRON jobs, triggers from message queues, etc +**TL;DR:** Each component should contain 'layers' - a dedicated folder for common concerns: 'entry-point' where controller lives, 'domain' where the logic lives, and 'data-access'. The primary principle of the most popular architectures is to separate the technical concerns (e.g., HTTP, DB, etc) from the pure logic of the app so a developer can code more features without worrying about infrastructural concerns. Putting each concern in a dedicated folder, also known as the [3-Tier pattern](https://en.wikipedia.org/wiki/Multitier_architecture), is the _simplest_ way to meet this goal + +```bash +my-system +├─ apps (components) +│ ├─ component-a + │ ├─ entry-points + │ │ ├─ api # controller comes here + │ │ ├─ message-queue # message consumer comes here + │ ├─ domain # features and flows: DTO, services, logic + │ ├─ data-access # DB calls w/o ORM +``` + +**Otherwise:** It's often seen that developer pass web objects like request/response to functions in the domain/logic layer - this violates the separation principle and makes it harder to access later the logic code by other clients like testing code, scheduled jobs, message queues, etc 🔗 [**Read More: layer your app**](./sections/projectstructre/createlayers.md)

-## ![✔] 1.3 Wrap common utilities as npm packages +## ![✔] 1.3 Wrap common utilities as packages, consider publishing + +**TL;DR:** Place all reusable modules in a dedicated folder, e.g., "libraries", and underneath each module in its own folder, e.g., "/libraries/logger". Make the module an independent package with its own package.json file to increase the module encapsulation, and allows future publishing to a repository. In a Monorepo setup, modules can be consumed by 'npm linking' to their physical paths, using ts-paths or by publishing and installing from a package manager repository like the npm registry -**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 +```bash +my-system +├─ apps (components) + │ ├─ component-a +├─ libraries (generic cross-component functionality) +│ ├─ logger +│ │ ├─ package.json +│ │ ├─ src +│ │ │ ├─ index.js + +``` -**Otherwise:** You'll have to invent your deployment and the dependency wheel +**Otherwise:** Clients of a module might import and get coupled to internal functionality of a module. With a package.json at the root, one can set a package.json.main or package.json.exports to explicitly tell which files and functions are part of the public interface 🔗 [**Read More: Structure by feature**](./sections/projectstructre/wraputilities.md)

-## ![✔] 1.4 Separate Express 'app' and 'server' +## ![✔] 1.4 Use environment aware, secure and hierarchical config -**TL;DR:** Avoid the nasty habit of defining the entire [Express](https://expressjs.com/) app in a single huge file - separate your 'Express' definition to at least two files: the API declaration (app.js) and the networking concerns (WWW). For even better structure, locate your API declaration within components +### `📝 #updated` -**Otherwise:** Your API will be accessible for testing via HTTP calls only (slower and much harder to generate coverage reports). It probably won't be a big pleasure to maintain hundreds of lines of code in a single file +**TL;DR:** A 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 (d) typing support (e) validation for failing fast (f) Specify default for each key. There are a few packages that can help tick most of those boxes like [convict](https://www.npmjs.com/package/convict), [env-var](https://github.com/evanshortiss/env-var), [zod](https://github.com/colinhacks/zod), and others -🔗 [**Read More: separate Express 'app' and 'server'**](./sections/projectstructre/separateexpress.md) +**Otherwise:** Consider a mandatory environment variable that wasn't provided. The app starts successfully and serve requests, some information is already persisted to DB. Then, it's realized that without this mandatory key the request can't complete, leaving the app in a dirty state + +🔗 [**Read More: configuration best practices**](./sections/projectstructre/configguide.md)

-## ![✔] 1.5 Use environment aware, secure and hierarchical config +## ![✔] 1.5 Consider all the consequences when choosing the main framework -**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). +### `🌟 #new` -**Otherwise:** Failing to satisfy any of the config requirements will simply bog down the development or DevOps team. Probably both +**TL;DR:** When building apps and APIs, using a framework is mandatory. It's easy to overlook alternative frameworks or important considerations and then finally land on a sub optimal option. As of 2023/2024, we believe that these four frameworks are worth considering: [Nest.js](https://nestjs.com/), [Fastify](https://www.fastify.io/), [express](https://expressjs.com/), and [Koa](https://koajs.com/). Click read more below for a detailed pros/cons of each framework. Simplistically, we believe that Nest.js is the best match for teams who wish to go OOP and/or build large-scale apps that can't get partitioned into smaller _autonomous_ components. Fastify is our recommendation for apps with reasonably-sized components (e.g., Microservices) that are built around simple Node.js mechanics. Read our [full considerations guide here](./sections/projectstructre/choose-framework.md) -🔗 [**Read More: configuration best practices**](./sections/projectstructre/configguide.md) +**Otherwise:** Due to the overwhelming amount of considerations, it's easy to make decisions based on partial information and compare apples with oranges. For example, it's believed that Fastify is a minimal web-server that should get compared with express only. In reality, it's a rich framework with many official plugins that cover many concerns + +🔗 [**Read More: Choosing the right framework**](./sections/projectstructre/choose-framework.md) + +## ![✔] 1.6 Use TypeScript sparingly and thoughtfully + +### `🌟 #new` + +**TL;DR:** Coding without type safety is no longer an option, TypeScript is the most popular option for this mission. Use it to define variables and functions return types. With that, it is also a double edge sword that can greatly _encourage_ complexity with its additional ~ 50 keywords and sophisticated features. Consider using it sparingly, mostly with simple types, and utilize advanced features only when a real need arises + +**Otherwise:** [Researches](https://earlbarr.com/publications/typestudy.pdf) show that using TypeScript can help in detecting ~20% bugs earlier. Without it, also the developer experience in the IDE is intolerable. On the flip side, 80% of other bugs were not discovered using types. Consequently, typed syntax is valuable but limited. Only efficient tests can discover the whole spectrum of bugs, including type-related bugs. It might also defeat its purpose: sophisticated code features are likely to increase the code complexity, which by itself increases both the amount of bugs and the average bug fix time + +🔗 [**Read More: TypeScript considerations**](./sections/projectstructre/typescript-considerations.md)


@@ -115,7 +334,7 @@ Read in a different language: [![CN](./assets/flags/CN.png)**CN**](./README.chin ## ![✔] 2.1 Use Async-Await or promises for async error handling -**TL;DR:** Handling async errors in callback style is probably the fastest way to hell (a.k.a the pyramid of doom). The best gift you can give to your code is using a reputable promise library or async-await instead which enables a much more compact and familiar code syntax like try-catch +**TL;DR:** Handling async errors in callback style is probably the fastest way to hell (a.k.a the pyramid of doom). The best gift you can give to your code is using Promises with async-await which enables a much more compact and familiar code syntax like try-catch **Otherwise:** Node.js callback style, function(err, response), is a promising way to un-maintainable code due to the mix of error handling with casual code, excessive nesting, and awkward coding patterns @@ -123,9 +342,11 @@ Read in a different language: [![CN](./assets/flags/CN.png)**CN**](./README.chin

-## ![✔] 2.2 Use only the built-in Error object +## ![✔] 2.2 Extend the built-in Error object + +### `📝 #updated` -**TL;DR:** Many throw errors as a string or as some custom type – this complicates the error handling logic and the interoperability between modules. Whether you reject a promise, throw an exception or emit an error – using only the built-in Error object (or an object that extends the built-in Error object) will increase uniformity and prevent loss of information. There is `no-throw-literal` ESLint rule that strictly checks that (although it have some [limitations](https://eslint.org/docs/rules/no-throw-literal) which can be solved when using TypeScript and setting the `@typescript-eslint/no-throw-literal` rule) +**TL;DR:** Some libraries throw errors as a string or as some custom type – this complicates the error handling logic and the interoperability between modules. Instead, create app error object/class that extends the built-in Error object and use it whenever rejecting, throwing or emitting an error. The app error should add useful imperative properties like the error name/code and isCatastrophic. By doing so, all errors have a unified structure and support better error handling. There is `no-throw-literal` ESLint rule that strictly checks that (although it has some [limitations](https://eslint.org/docs/rules/no-throw-literal) which can be solved when using TypeScript and setting the `@typescript-eslint/no-throw-literal` rule) **Otherwise:** When invoking some component, being uncertain which type of errors come in return – it makes proper error handling much harder. Even worse, using custom types to describe errors might lead to loss of critical error information like the stack trace! @@ -133,11 +354,13 @@ Read in a different language: [![CN](./assets/flags/CN.png)**CN**](./README.chin

-## ![✔] 2.3 Distinguish operational vs programmer errors +## ![✔] 2.3 Distinguish catastrophic errors from operational 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 an undefined variable) refers to unknown code failures that dictate to gracefully restart the application +### `📝 #updated` -**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 +**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, catastrophic error (also known as programmer errors) refers to unusual 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 catastrophic 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 🔗 [**Read More: operational vs programmer error**](./sections/errorhandling/operationalvsprogrammererror.md) @@ -145,7 +368,7 @@ Read in a different language: [![CN](./assets/flags/CN.png)**CN**](./README.chin ## ![✔] 2.4 Handle errors centrally, not within a middleware -**TL;DR:** Error handling logic such as mail to admin and logging should be encapsulated in a dedicated and centralized object that all endpoints (e.g. Express middleware, cron jobs, unit-testing) call when an error comes in +**TL;DR:** Error handling logic such as logging, deciding whether to crash and monitoring metrics should be encapsulated in a dedicated and centralized object that all entry-points (e.g. APIs, cron jobs, scheduled jobs) call when an error comes in **Otherwise:** Not handling errors within a single place will lead to code duplication and probably to improperly handled errors @@ -153,9 +376,9 @@ Read in a different language: [![CN](./assets/flags/CN.png)**CN**](./README.chin

-## ![✔] 2.5 Document API errors using Swagger or GraphQL +## ![✔] 2.5 Document API errors using OpenAPI or GraphQL -**TL;DR:** Let your API callers know which errors might come in return so they can handle these thoughtfully without crashing. For RESTful APIs, this is usually done with documentation frameworks like Swagger. If you're using GraphQL, you can utilize your schema and comments as well. +**TL;DR:** Let your API callers know which errors might come in return so they can handle these thoughtfully without crashing. For RESTful APIs, this is usually done with documentation frameworks like OpenAPI. If you're using GraphQL, you can utilize your schema and comments as well **Otherwise:** An API client might decide to crash and restart only because it received back an error it couldn’t understand. Note: the caller of your API might be you (very typical in a microservice environment) @@ -165,7 +388,7 @@ Read in a different language: [![CN](./assets/flags/CN.png)**CN**](./README.chin ## ![✔] 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. 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 (catastrophic error, see best practice 2.3) - there is uncertainty about the application healthiness. In this case, there is no escape from making the error observable, shutting off connections and exiting the process. Any reputable runtime framework like Dockerized services or cloud serverless solutions will take care to restart **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 @@ -173,9 +396,11 @@ Read in a different language: [![CN](./assets/flags/CN.png)**CN**](./README.chin

-## ![✔] 2.7 Use a mature logger to increase error visibility +## ![✔] 2.7 Use a mature logger to increase errors visibility + +### `📝 #updated` -**TL;DR:** A set of mature logging tools like [Pino](https://github.com/pinojs/pino) or [Log4js](https://www.npmjs.com/package/log4js), will speed-up error discovery and understanding. So forget about console.log +**TL;DR:** A robust logging tools like [Pino](https://github.com/pinojs/pino) or [Winston](https://github.com/winstonjs/winston) increases the errors visibility using features like log-levels, pretty print coloring and more. Console.log lacks these imperative features and should be avoided. The best in class logger allows attaching custom useful properties to log entries with minimized serialization performance penalty. Developers should write logs to `stdout` and let the infrastructure pipe the stream to the appropriate log aggregator **Otherwise:** Skimming through console.logs or manually through messy text file without querying tools or a decent log viewer might keep you busy at work until late @@ -185,7 +410,9 @@ Read in a different language: [![CN](./assets/flags/CN.png)**CN**](./README.chin ## ![✔] 2.8 Test error flows using your favorite test framework -**TL;DR:** Whether professional automated QA or plain manual developer testing – Ensure that your code not only satisfies positive scenarios but also handles and returns the right errors. Testing frameworks like Mocha & Chai can handle this easily (see code examples within the "Gist popup") +### `📝 #updated` + +**TL;DR:** Whether professional automated QA or plain manual developer testing – Ensure that your code not only satisfies positive scenarios but also handles and returns the right errors. On top of this, simulate deeper error flows like uncaught exceptions and ensure that the error handler treat these properly (see code examples within the "read more" section) **Otherwise:** Without testing, whether automatically or manually, you can’t rely on your code to return the right errors. Without meaningful errors – there’s no error handling @@ -205,6 +432,8 @@ Read in a different language: [![CN](./assets/flags/CN.png)**CN**](./README.chin ## ![✔] 2.10 Catch unhandled promise rejections +### `📝 #updated` + **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 @@ -215,7 +444,7 @@ Read in a different language: [![CN](./assets/flags/CN.png)**CN**](./README.chin ## ![✔] 2.11 Fail fast, validate arguments using a dedicated library -**TL;DR:** Assert API input to avoid nasty bugs that are much harder to track later. The validation code is usually tedious unless you are using a very cool helper library like [ajv](https://www.npmjs.com/package/ajv) and [Joi](https://www.npmjs.com/package/joi) +**TL;DR:** Assert API input to avoid nasty bugs that are much harder to track later. The validation code is usually tedious unless you are using a modern validation library like [ajv](https://www.npmjs.com/package/ajv), [zod](https://github.com/colinhacks/zod), or [typebox](https://github.com/sinclairzx81/typebox) **Otherwise:** Consider this – your function expects a numeric argument “Discount” which the caller forgets to pass, later on, your code checks if Discount!=0 (amount of allowed discount is greater than zero), then it will allow the user to enjoy a discount. OMG, what a nasty bug. Can you see it? @@ -225,6 +454,8 @@ Read in a different language: [![CN](./assets/flags/CN.png)**CN**](./README.chin ## ![✔] 2.12 Always await promises before returning to avoid a partial stacktrace +### `🌟 #new` + **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 @@ -235,15 +466,25 @@ especially if the cause of the abnormal behavior is inside of the missing functi 🔗 [**Read More: returning promises**](./sections/errorhandling/returningpromises.md) +

+ +## ![✔] 2.13 Subscribe to event emitters and streams 'error' event + +### `🌟 #new` + +**TL;DR:** Unlike typical functions, a try-catch clause won't get errors that originate from Event Emitters and anything inherited from it (e.g., streams). Instead of try-catch, subscribe to an event emitter's 'error' event so your code can handle the error in context. When dealing with [EventTargets](https://nodejs.org/api/events.html#eventtarget-and-event-api) (the web standard version of Event Emitters) there are no 'error' event and all errors end in the process.on('error) global event - in this case, at least ensure that the process crash or not based on the desired context. Also, mind that error originating from _asynchronous_ event handlers are not get caught unless the event emitter is initialized with {captureRejections: true} + +**Otherwise:** Event emitters are commonly used for global and key application functionality such as DB or message queue connection. When this kind of crucial objects throw an error, at best the process will crash due to unhandled exception. Even worst, it will stay alive as a zombie while a key functionality is turned off +


⬆ Return to top

-# `3. Code Style Practices` +# `3. Code Patterns And Style Practices` ## ![✔] 3.1 Use ESLint -**TL;DR:** [ESLint](https://eslint.org) is the de-facto standard for checking possible code errors and fixing code style, not only to identify nitty-gritty spacing issues but also to detect serious code anti-patterns like developers throwing errors without classification. Though ESLint can automatically fix code styles, other tools like [prettier](https://www.npmjs.com/package/prettier) and [beautify](https://www.npmjs.com/package/js-beautify) are more powerful in formatting the fix and work in conjunction with ESLint +**TL;DR:** [ESLint](https://eslint.org) is the de-facto standard for checking possible code errors and fixing code style, not only to identify nitty-gritty spacing issues but also to detect serious code anti-patterns like developers throwing errors without classification. Though ESLint can automatically fix code styles, other tools like [prettier](https://www.npmjs.com/package/prettier) are more powerful in formatting the fix and work in conjunction with ESLint **Otherwise:** Developers will focus on tedious spacing and line-width concerns and time might be wasted overthinking the project's code style @@ -251,9 +492,11 @@ especially if the cause of the abnormal behavior is inside of the missing functi

-## ![✔] 3.2 Node.js specific plugins +## ![✔] 3.2 Use Node.js eslint extension plugins + +### `📝 #updated` -**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) +**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), [eslint-plugin-require](https://www.npmjs.com/package/eslint-plugin-require), [/eslint-plugin-jest](https://www.npmjs.com/package/eslint-plugin-jest) and other useful rules **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 @@ -338,24 +581,41 @@ const count = 2 // it tries to run 2(), but 2 is not a function ## ![✔] 3.6 Use naming conventions for variables, constants, functions and classes -**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 +**TL;DR:** Use **_lowerCamelCase_** when naming constants, variables and functions, **_UpperCamelCase_** (capital first letter as well) when naming classes and **_UPPER_SNAKE_CASE_** when naming global or static variables. This will help you to easily distinguish between plain variables, functions, classes that require instantiation and variables declared at global module scope. Use descriptive names, but try to keep them short **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 ```javascript -// for class name we use UpperCamelCase -class SomeClassExample {} - -// for const names we use the const keyword and lowerCamelCase -const config = { +// for global variables names we use the const/let keyword and UPPER_SNAKE_CASE +let MUTABLE_GLOBAL = "mutable value"; +const GLOBAL_CONSTANT = "immutable value"; +const CONFIG = { key: "value", }; -// for variables and functions names we use lowerCamelCase -let someVariableExample = "value"; -function doSomething() {} +// examples of UPPER_SNAKE_CASE convention in nodejs/javascript ecosystem +// in javascript Math.PI module +const PI = 3.141592653589793; + +// https://github.com/nodejs/node/blob/b9f36062d7b5c5039498e98d2f2c180dca2a7065/lib/internal/http2/core.js#L303 +// in nodejs http2 module +const HTTP_STATUS_OK = 200; +const HTTP_STATUS_CREATED = 201; + +// for class name we use UpperCamelCase +class SomeClassExample { + // for static class properties we use UPPER_SNAKE_CASE + static STATIC_PROPERTY = "value"; +} + +// for functions names we use lowerCamelCase +function doSomething() { + // for scoped variable names we use the const/let keyword and lowerCamelCase + const someConstExample = "immutable value"; + let someMutableExample = "mutable value"; +} ```

@@ -378,22 +638,29 @@ function doSomething() {}

-## ![✔] 3.9 Require modules by folders, as opposed to the files directly +## ![✔] 3.9 Set an explicit entry point to a module/folder -**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 +### `📝 #updated` -**Otherwise:** Changing the internal structure of files or the signature may break the interface with clients +**TL;DR:** When developing a module/library, set an explicit root file that exports the public and interesting code. Discourage the client code from importing deep files and becoming familiar with the internal structure. With commonjs (require), this can be done with an index.js file at the folder's root or the package.json.main field. With ESM (import), if a package.json exists on the root, the field "exports" allow specifying the module's root file. If no package.json exists, you may put an index.js file on the root which re-exports all the public functionality -### 3.9 Code example +**Otherwise:** Having an explicit root file acts like a public 'interface' that encapsulates the internal, directs the caller to the public code and facilitates future changes without breaking the contract + +### 3.9 Code example - avoid coupling the client to the module structure ```javascript -// Do -module.exports.SMSProvider = require("./SMSProvider"); -module.exports.SMSNumberResolver = require("./SMSNumberResolver"); +// Avoid: client has deep familiarity with the internals -// Avoid -module.exports.SMSProvider = require("./SMSProvider/SMSProvider.js"); -module.exports.SMSNumberResolver = require("./SMSNumberResolver/SMSNumberResolver.js"); +// Client code +const SMSWithMedia = require("./SMSProvider/providers/media/media-provider.js"); + +// Better: explicitly export the public functions + +//index.js, module code +module.exports.SMSWithMedia = require("./SMSProvider/providers/media/media-provider.js"); + +// Client code +const { SMSWithMedia } = require("./SMSProvider"); ```

@@ -427,7 +694,7 @@ All statements above will return false if used with `===` ## ![✔] 3.11 Use Async Await, avoid callbacks -**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 +**TL;DR:** Async-await is the simplest way to express an asynchronous flow as it makes asynchronous code look synchronous. Async-await will also result in much more compact code and support for try-catch. This technique now supersedes callbacks and promises in _most_ cases. Using it in your code is probably the best gift one can give to the code reader **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 @@ -443,15 +710,31 @@ All statements above will return false if used with `===` 🔗 [**Read more: It’s Time to Embrace Arrow Functions**](https://medium.com/javascript-scene/familiarity-bias-is-holding-you-back-its-time-to-embrace-arrow-functions-3d37e1a9bb75) +

+ +## ![✔] 3.13 Avoid effects outside of functions + +### `🌟 #new` + +**TL;DR:** Avoid putting code with effects like network or DB calls outside of functions. Such a code will be executed immediately when another file requires the file. This 'floating' code might get executed when the underlying system is not ready yet. It also comes with a performance penalty even when this module's functions will finally not be used in runtime. Last, mocking these DB/network calls for testing is harder outside of functions. Instead, put this code inside functions that should get called explicitly. If some DB/network code must get executed right when the module loads, consider using the factory or revealing module patterns + +**Otherwise:** A typical web framework sets error handler, environment variables and monitoring. When DB/network calls are made before the web framework is initialized, they won't be monitored or fail due to a lack of configuration data +


⬆ Return to top

# `4. Testing And Overall Quality Practices` +\_We have dedicated guides for testing, see below. The best practices list here is a brief summary of these guides + +a. [JavaScript testing best practices](https://github.com/goldbergyoni/javascript-testing-best-practices) +b. [Node.js testing - beyond the basics](https://github.com/testjavascript/nodejs-integration-tests-best-practices) +\_ + ## ![✔] 4.1 At the very least, write API (component) testing -**TL;DR:** Most projects just don't have any automated testing due to short timetables or often the 'testing project' ran out of control and was abandoned. For that reason, prioritize and start with API testing which is the easiest way to write and provides more coverage than unit testing (you may even craft API tests without code using tools like [Postman](https://www.getpostman.com/)). Afterward, should you have more resources and time, continue with advanced test types like unit testing, DB testing, performance testing, etc +**TL;DR:** Most projects just don't have any automated testing due to short timetables or often the 'testing project' ran out of control and was abandoned. For that reason, prioritize and start with API testing which is the easiest way to write and provides more coverage than unit testing (you may even craft API tests without code using tools like [Postman](https://www.getpostman.com/)). Afterwards, should you have more resources and time, continue with advanced test types like unit testing, DB testing, performance testing, etc **Otherwise:** You may spend long days on writing unit tests to find out that you got only 20% system coverage @@ -459,6 +742,8 @@ All statements above will return false if used with `===` ## ![✔] 4.2 Include 3 parts in each test name +### `🌟 #new` + **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? @@ -469,6 +754,8 @@ All statements above will return false if used with `===` ## ![✔] 4.3 Structure tests by the AAA pattern +### `🌟 #new` + **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, but now also what should have been the simple part of the day (testing) stretches your brain @@ -477,11 +764,13 @@ All statements above will return false if used with `===`

-## ![✔] 4.4 Detect code issues with a linter +## ![✔] 4.4 Ensure Node version is unified -**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 +### `🌟 #new` -**Otherwise:** You may let pass some anti-pattern and possible vulnerable code to your production environment. +**TL;DR:** Use tools that encourage or enforce the same Node.js version across different environments and developers. Tools like [nvm](https://github.com/nvm-sh/nvm), and [Volta](https://volta.sh/) allow specifying the project's version in a file so each team member can run a single command to conform with the project's version. Optionally, this definition can be replicated to CI and the production runtime (e.g., copy the specified value to .Dockerfile build and to the CI declaration file) + +**Otherwise:** A developer might face or miss an error because she uses a different Node.js version than her teammates. Even worse - the production runtime might be different than the environment where tests were executed

@@ -495,15 +784,7 @@ All statements above will return false if used with `===`

-## ![✔] 4.6 Constantly inspect for vulnerable dependencies - -**TL;DR:** Even the most reputable dependencies such as Express have known vulnerabilities. This can get easily tamed using community and commercial tools such as 🔗 [npm audit](https://docs.npmjs.com/cli/audit) and 🔗 [snyk.io](https://snyk.io) that can be invoked from your CI on every build - -**Otherwise:** Keeping your code clean from vulnerabilities without dedicated tools will require to constantly follow online publications about new threats. Quite tedious - -

- -## ![✔] 4.7 Tag your tests +## ![✔] 4.6 Tag your tests **TL;DR:** Different tests must run on different scenarios: quick smoke, IO-less, tests should run when a developer saves or commits a file, full end-to-end tests usually run when a new pull request is submitted, etc. This can be achieved by tagging tests with keywords like #cold #api #sanity so you can grep with your testing harness and invoke the desired subset. For example, this is how you would invoke only the sanity test group with [Mocha](https://mochajs.org/): mocha --grep 'sanity' @@ -511,7 +792,7 @@ All statements above will return false if used with `===`

-## ![✔] 4.8 Check your test coverage, it helps to identify wrong test patterns +## ![✔] 4.7 Check your test coverage, it helps to identify wrong test patterns **TL;DR:** Code coverage tools like [Istanbul](https://github.com/istanbuljs/istanbuljs)/[NYC](https://github.com/istanbuljs/nyc) are great for 3 reasons: it comes for free (no effort is required to benefit this reports), it helps to identify a decrease in testing coverage, and last but not least it highlights testing mismatches: by looking at colored code coverage reports you may notice, for example, code areas that are never tested like catch clauses (meaning that tests only invoke the happy paths and not how the app behaves on errors). Set it to fail builds if the coverage falls under a certain threshold @@ -519,15 +800,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 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 - -

- -## ![✔] 4.10 Use production-like environment for e2e testing +## ![✔] 4.8 Use production-like environment for e2e testing **TL;DR:** End to end (e2e) testing which includes live data used to be the weakest link of the CI process as it depends on multiple heavy services like DB. Use an environment which is as close to your real production environment as possible like a-continue (Missed -continue here, needs content. Judging by the **Otherwise** clause, this should mention docker-compose) @@ -535,7 +808,7 @@ All statements above will return false if used with `===`

-## ![✔] 4.11 Refactor regularly using static analysis tools +## ![✔] 4.9 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)). @@ -545,15 +818,17 @@ 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) +## ![✔] 4.10 Mock responses of external HTTP services -**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 +### `🌟 #new` -**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 +**TL;DR:** Use network mocking tools to simulate responses of external collaborators' services that are approached over the network (e.g., REST, Graph). This is imperative not only to isolate the component under test but mostly to simulate non-happy path flows. Tools like [nock](https://github.com/nock/nock) (in-process) or [Mock-Server](https://www.mock-server.com/) allow defining a specific response of external service in a single line of code. Remember to simulate also errors, delays, timeouts, and any other event that is likely to happen in production -🔗 [**Read More: Choosing CI platform**](./sections/testingandquality/citools.md) +**Otherwise:** Allowing your component to reach real external services instances will likely result in naive tests that mostly cover happy paths. The tests might also be flaky and slow -## ![✔] 4.13 Test your middlewares in isolation +🔗 [**Read More: Mock external services**](./sections/testingandquality/mock-external-services.md) + +## ![✔] 4.11 Test your middlewares in isolation **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 @@ -561,6 +836,26 @@ All statements above will return false if used with `===` 🔗 [**Read More: Test middlewares in isolation**](./sections/testingandquality/test-middlewares.md) +## ![✔] 4.12 Specify a port in production, randomize in testing + +### `🌟 #new` + +**TL;DR:** When testing against the API, it's common and desirable to initialize the web server inside the tests. Let the server randomize the web server port in testing to prevent collisions. If you're using Node.js http server (used by most frameworks), doing so demands nothing but passing a port number zero - this will randomize an available port + +**Otherwise:** Specifying a fixed port will prevent two testing processes from running at the same time. Most of the modern test runners run with multiple processes by default + +🔗 [**Read More: Randomize a port for testing**](./sections/testingandquality/randomize-port.md) + +## ![✔] 4.13 Test the five possible outcomes + +### `🌟 #new` + +**TL;DR:** When testing a flow, ensure to cover five potential categories. Any time some action is triggered (e.g., API call), a reaction occurs, a meaningful **outcome** is produced and calls for testing. There are five possible outcome types for every flow: a response, a visible state change (e.g., DB), an outgoing API call, a new message in a queue, and an observability call (e.g., logging, metric). See a [checklist here](https://testjavascript.com/wp-content/uploads/2021/10/the-backend-checklist.pdf). Each type of outcome comes with unique challenges and techniques to mitigate those challenges - we have a dedicated guide about this topic: [Node.js testing - beyond the basics](https://github.com/testjavascript/nodejs-integration-tests-best-practices) + +**Otherwise:** Consider a case when testing the addition of a new product to the system. It's common to see tests that assert on a valid response only. What if the product was failed to persist regardless of the positive response? what if when adding a new product demands calling some external service, or putting a message in the queue - shouldn't the test assert these outcomes as well? It's easy to overlook various paths, this is where a [checklist comes handy](https://testjavascript.com/wp-content/uploads/2021/10/the-backend-checklist.pdf) + +🔗 [**Read More: Test five outcomes**](./sections/testingandquality/test-five-outcomes.md) +


⬆ Return to top

@@ -569,7 +864,7 @@ All statements above will return false if used with `===` ## ![✔] 5.1. Monitoring -**TL;DR:** Monitoring is a game of finding out issues before customers do – obviously this should be assigned unprecedented importance. The market is overwhelmed with offers thus consider starting with defining the basic metrics you must follow (my suggestions inside), then go over additional fancy features and choose the solution that ticks all boxes. Click ‘The Gist’ below for an overview of the solutions +**TL;DR:** Monitoring is a game of finding out issues before customers do – obviously this should be assigned unprecedented importance. The market is overwhelmed with offers thus consider starting with defining the basic metrics you must follow (my suggestions inside), then go over additional fancy features and choose the solution that ticks all boxes. In any case, the 4 layers of observability must be covered: uptime, metrics with focus on user-facing symptoms and Node.js technical metrics like event loop lag, distributed flows measurement with Open Telemetry and logging. Click ‘Read More’ below for an overview of the solutions **Otherwise:** Failure === disappointed customers. Simple @@ -577,7 +872,7 @@ All statements above will return false if used with `===`

-## ![✔] 5.2. Increase transparency using smart logging +## ![✔] 5.2. Increase the observability using smart logging **TL;DR:** Logs can be a dumb warehouse of debug statements or the enabler of a beautiful dashboard that tells the story of your app. Plan your logging platform from day 1: how logs are collected, stored and analyzed to ensure that the desired information (e.g. error rate, following an entire transaction through services and servers, etc) can really be extracted @@ -589,7 +884,7 @@ All statements above will return false if used with `===` ## ![✔] 5.3. Delegate anything possible (e.g. gzip, SSL) to a reverse proxy -**TL;DR:** Node is awfully bad at doing CPU intensive tasks like gzipping, SSL termination, etc. You should use ‘real’ middleware services like nginx, HAproxy or cloud vendor services instead +**TL;DR:** Node is quite bad at doing CPU intensive tasks like gzipping, SSL termination, etc. You should use specialized infrastructure like nginx, HAproxy or cloud vendor services instead **Otherwise:** Your poor single thread will stay busy doing infrastructural tasks instead of dealing with your application core and performance will degrade accordingly @@ -599,7 +894,7 @@ All statements above will return false if used with `===` ## ![✔] 5.4. Lock dependencies -**TL;DR:** Your code must be identical across all environments, but amazingly npm lets dependencies drift across environments by default – when you install packages at various environments it tries to fetch packages’ latest patch version. Overcome this by using npm config files, .npmrc, that tell each environment to save the exact (not the latest) version of each package. Alternatively, for finer grained control use `npm shrinkwrap`. \*Update: as of NPM5, dependencies are locked by default. The new package manager in town, Yarn, also got us covered by default +**TL;DR:** Your code must be identical across all environments, but without a special lockfile npm lets dependencies drift across environments. Ensure to commit your package-lock.json so all the environments will be identical **Otherwise:** QA will thoroughly test the code and approve a version that will behave differently in production. Even worse, different servers in the same production cluster might run different code @@ -609,7 +904,7 @@ All statements above will return false if used with `===` ## ![✔] 5.5. Guard process uptime using the right tool -**TL;DR:** The process must go on and get restarted upon failures. For simple scenarios, process management tools like PM2 might be enough but in today's ‘dockerized’ world, cluster management tools should be considered as well +**TL;DR:** The process must go on and get restarted upon failures. Modern runtime platforms like Docker-ized platforms (e.g. Kubernetes), and Serverless take care for this automatically. When the app is hosted on a bare metal server, one must take care for a process management tools like [systemd](https://systemd.io/). Avoid including a custom process management tool in a modern platform that monitors an app instance (e.g., Kubernetes) - doing so will hide failures from the infrastructure. When the underlying infrastructure is not aware of errors, it can't perform useful mitigation steps like re-placing the instance in a different location **Otherwise:** Running dozens of instances without a clear strategy and too many tools together (cluster management, docker, PM2) might lead to DevOps chaos @@ -619,7 +914,7 @@ All statements above will return false if used with `===` ## ![✔] 5.6. Utilize all CPU cores -**TL;DR:** At its basic form, a Node app runs on a single CPU core while all others are left idling. It’s your duty to replicate the Node process and utilize all CPUs – For small-medium apps you may use Node Cluster or PM2. For a larger app consider replicating the process using some Docker cluster (e.g. K8S, ECS) or deployment scripts that are based on Linux init system (e.g. systemd) +**TL;DR:** At its basic form, a Node app runs on a single CPU core while all others are left idling. It’s your duty to replicate the Node process and utilize all CPUs. Most of the modern run-times platform (e.g., Kubernetes) allow replicating instances of the app but they won't verify that all cores are utilized - this is your duty. If the app is hosted on a bare server, it's also your duty to use some process replication solution (e.g. systemd) **Otherwise:** Your app will likely utilize only 25% of its available resources(!) or even less. Note that a typical server has 4 CPU cores or more, naive deployment of Node.js utilizes only 1 (even using PaaS services like AWS beanstalk!) @@ -637,9 +932,11 @@ All statements above will return false if used with `===`

-## ![✔] 5.8. Discover errors and downtime using APM products +## ![✔] 5.8. Discover the unknowns using APM products + +### `📝 #updated` -**TL;DR:** Application monitoring and performance products (a.k.a. APM) proactively gauge codebase and API so they can auto-magically go beyond traditional monitoring and measure the overall user-experience across services and tiers. For example, some APM products can highlight a transaction that loads too slow on the end-user's side while suggesting the root cause +**TL;DR:** Consider adding another safety layer to the production stack - APM. While the majority of symptoms and causes can be detected using traditional monitoring techniques, in a distributed system there is more than meets the eye. Application monitoring and performance products (a.k.a. APM) can auto-magically go beyond traditional monitoring and provide additional layer of discovery and developer-experience. For example, some APM products can highlight a transaction that loads too slow on the **end-user's side** while suggesting the root cause. APMs also provide more context for developers who try to troubleshoot a log error by showing what was the server busy with when the error occurred. To name a few example **Otherwise:** You might spend great effort on measuring API performance and downtimes, probably you’ll never be aware which is your slowest code parts under real-world scenario and how these affect the UX @@ -649,7 +946,7 @@ All statements above will return false if used with `===` ## ![✔] 5.9. Make your code production-ready -**TL;DR:** Code with the end in mind, plan for production from day 1. This sounds a bit vague so I’ve compiled a few development tips that are closely related to production maintenance (click Gist below) +**TL;DR:** Code with the end in mind, plan for production from day 1. This sounds a bit vague so I’ve compiled a few development tips that are closely related to production maintenance (click 'Read More') **Otherwise:** A world champion IT/DevOps guy won’t save a system that is badly written @@ -669,7 +966,7 @@ All statements above will return false if used with `===` ## ![✔] 5.11. Get your frontend assets out of Node -**TL;DR:** Serve frontend content using dedicated middleware (nginx, S3, CDN) because Node performance really gets hurt when dealing with many static files due to its single-threaded model +**TL;DR:** Serve frontend content using a specialized infrastructure (nginx, S3, CDN) because Node performance gets hurt when dealing with many static files due to its single-threaded model. One exception to this guideline is when doing server-side rendering **Otherwise:** Your single Node thread will be busy streaming hundreds of html/images/angular/react files instead of allocating all its resources for the task it was born for – serving dynamic content @@ -677,9 +974,9 @@ All statements above will return false if used with `===`

-## ![✔] 5.12. Be stateless, kill your servers almost every day +## ![✔] 5.12. Strive to be stateless -**TL;DR:** Store any type of data (e.g. user sessions, cache, uploaded files) within external data stores. Consider ‘killing’ your servers periodically or use ‘serverless’ platform (e.g. AWS Lambda) that explicitly enforces a stateless behavior +**TL;DR:** Store any type of _data_ (e.g. user sessions, cache, uploaded files) within external data stores. When the app holds data in-process this adds additional layer of maintenance complexity like routing users to the same instance and higher cost of restarting a process. To enforce and encourage a stateless approach, most modern runtime platforms allows 'reapp-ing' instances periodically **Otherwise:** Failure at a given server will result in application downtime instead of just killing a faulty machine. Moreover, scaling-out elasticity will get more challenging due to the reliance on a specific server @@ -699,9 +996,7 @@ All statements above will return false if used with `===` ## ![✔] 5.14. Assign a transaction id to each log statement -Also known as correlation id / transit id / tracing id / request id / request context / etc. - -**TL;DR:** Assign the same identifier, transaction-id: {some value}, to each log entry within a single request. Then when inspecting errors in logs, easily conclude what happened before and after. Until version 14 of Node, this was not easy to achieve due to Node's async nature, but since AsyncLocalStorage came to town, this became possible and easy than ever. see code examples inside +**TL;DR:** Assign the same identifier, transaction-id: uuid(), to each log entry within a single request (also known as correlation-id/tracing-id/request-context). Then when inspecting errors in logs, easily conclude what happened before and after. Node has a built-in mechanism, [AsyncLocalStorage](https://nodejs.org/api/async_context.html), for keeping the same context across asynchronous calls. see code examples inside **Otherwise:** Looking at a production error log without the context – what happened before – makes it much harder and slower to reason about the issue @@ -711,9 +1006,9 @@ Also known as correlation id / transit id / tracing id / request id / request co ## ![✔] 5.15. Set `NODE_ENV=production` -**TL;DR:** Set the environment variable `NODE_ENV` to ‘production’ or ‘development’ to flag whether production optimizations should get activated – many npm packages determine the current environment and optimize their code for production +**TL;DR:** Set the environment variable `NODE_ENV` to ‘production’ or ‘development’ to flag whether production optimizations should get activated – some npm packages determine the current environment and optimize their code for production -**Otherwise:** Omitting this simple property might greatly degrade performance. For example, when using Express for server-side rendering omitting `NODE_ENV` makes it slower by a factor of three! +**Otherwise:** Omitting this simple property might greatly degrade performance when dealing with some specific libraries like Express server-side rendering 🔗 [**Read More: Set NODE_ENV=production**](./sections/production/setnodeenv.md) @@ -737,11 +1032,13 @@ Also known as correlation id / transit id / tracing id / request id / request co

-## ![✔] 5.18. Don't route logs within the app +## ![✔] 5.18. Log to stdout, avoid specifying log destination within the app + +### `📝 #updated` **TL;DR:** Log destinations should not be hard-coded by developers within the application code, but instead should be defined by the execution environment the application runs in. Developers should write logs to `stdout` using a logger utility and then let the execution environment (container, server, etc.) pipe the `stdout` stream to the appropriate destination (i.e. Splunk, Graylog, ElasticSearch, etc.). -**Otherwise:** Application handling log routing === hard to scale, loss of logs, poor separation of concerns +**Otherwise:** If developers set the log routing, less flexibility is left for the ops professional who wishes to customize it. Beyond this, if the app tries to log directly to a remote location (e.g., Elastic Search), in case of panic or crash - further logs that might explain the problem won't arrive 🔗 [**Read More: Log Routing**](./sections/production/logrouting.md) @@ -749,7 +1046,7 @@ Also known as correlation id / transit id / tracing id / request id / request co ## ![✔] 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. +**TL;DR:** Run `npm ci` to strictly do a clean install of your dependencies matching package.json and package-lock.json. Obviously production code must use the exact version of the packages that were used for testing. While package-lock.json file sets strict version for dependencies, in case of mismatch with the file package.json, the command 'npm install' will treat package.json as the source of truth. On the other hand, the command 'npm ci' will exit with error in case of mismatch between these files **Otherwise:** QA will thoroughly test the code and approve a version that will behave differently in production. Even worse, different servers in the same production cluster might run different code. @@ -914,7 +1211,7 @@ Also known as correlation id / transit id / tracing id / request id / request co **TL;DR:** There is a common scenario where Node.js runs as a root user with unlimited permissions. For example, this is the default behaviour in Docker containers. It's recommended to create a non-root user and either bake it into the Docker image (examples given below) or run the process on this user's behalf by invoking the container with the flag "-u username" -**Otherwise:** An attacker who manages to run a script on the server gets unlimited power over the local machine (e.g. change iptable and re-route traffic to his server) +**Otherwise:** An attacker who manages to run a script on the server gets unlimited power over the local machine (e.g. change iptable and re-route traffic to their server) 🔗 [**Read More: Run Node.js as non-root user**](./sections/security/non-root-user.md) @@ -1057,6 +1354,39 @@ Also known as correlation id / transit id / tracing id / request id / request co **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. 🔗 [**Read More: Avoid publishing secrets**](./sections/security/avoid_publishing_secrets.md) + +

+ +## ![✔] 6.26 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 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 + +

+ +## ![✔] 6.27. Import built-in modules using the 'node:' protocol + +### `🌟 #new` + + + +**TL;DR:** Import or require built-in Node.js modules using the 'node protocol' syntax: + +```javascript +import { functionName } from "node:module"; // note that 'node:' prefix +``` + +For example: + +```javascript +import { createServer } from "node:http"; +``` + +This style ensures that there is no ambiguity with global npm packages and makes it clear for the reader that the code refers to a well-trusted official module. This style can be enforced with the eslint rule ['prefer-node-protocol'](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-node-protocol.md) + +**Otherwise:** Using the import syntax without 'node:' prefix opens the door for [typosquatting attacks](https://en.wikipedia.org/wiki/Typosquatting) where one could mistakenly mistype a module name (e.g., 'event' instead of 'events) and get a malicious package that was built only to trick users into installing them +


⬆ Return to top

@@ -1128,9 +1458,11 @@ CMD [ "node", "dist/app.js" ] ## ![✔] 8.2. Bootstrap using `node` command, avoid `npm start` -**TL;DR:** use `CMD ['node','server.js']` to start your app, avoid using npm scripts which don't pass OS signals to the code. This prevents problems with child-processes, signal handling, graceful shutdown and having zombie processes. +**TL;DR:** Use `CMD ['node','server.js']` to start your app, avoid using npm scripts which don't pass OS signals to the code. This prevents problems with child-processes, signal handling, graceful shutdown and having zombie processes + +Update: [Starting from npm 7, npm claim](https://docs.npmjs.com/cli/v7/using-npm/changelog#706-2020-10-27) to pass signals. We follow and will update accordingly -**Otherwise:** When no signals are passed, your code will never be notified about shutdowns. Without this, it will lose its chance to close properly possibly losing current requests and/or data. +**Otherwise:** When no signals are passed, your code will never be notified about shutdowns. Without this, it will lose its chance to close properly possibly losing current requests and/or data [**Read More: Bootstrap container using node command, avoid npm start**](./sections/docker/bootstrap-using-node.md) @@ -1168,7 +1500,7 @@ CMD [ "node", "dist/app.js" ] ## ![✔] 8.6. Shutdown smartly and gracefully -**TL;DR:** Handle the process SIGTERM event and clean-up all existing connection and resources. This should be done while responding to ongoing requests. In Dockerized runtimes shutting down containers is not a rare event, rather a frequent occurrence that happen as part of routine work. Achieving this demands some thoughtful code to orchestrate several moving parts: The load balancer, keep-alive connections, the HTTP server and other resources +**TL;DR:** Handle the process SIGTERM event and clean-up all existing connection and resources. This should be done while responding to ongoing requests. In Dockerized runtimes, shutting down containers is not a rare event, rather a frequent occurrence that happen as part of routine work. Achieving this demands some thoughtful code to orchestrate several moving parts: The load balancer, keep-alive connections, the HTTP server and other resources **Otherwise:** Dying immediately means not responding to thousands of disappointed users @@ -1220,6 +1552,8 @@ In addition, referring to an image tag means that the base image is subject to c ## ![✔] 8.11. Clean-out build-time secrets, avoid secrets in args +### `🌟 #new` + **TL;DR:** Avoid secrets leaking from the Docker build environment. A Docker image is typically shared in multiple environment like CI and a registry that are not as sanitized as production. A typical example is an npm token which is usually passed to a dockerfile as argument. This token stays within the image long after it is needed and allows the attacker indefinite access to a private npm registry. This can be avoided by coping a secret file like `.npmrc` and then removing it using multi-stage build (beware, build history should be deleted as well) or by using Docker build-kit secret feature which leaves zero traces **Otherwise:** Everyone with access to the CI and docker registry will also get access to some precious organization secrets as a bonus @@ -1258,6 +1592,8 @@ In addition, referring to an image tag means that the base image is subject to c ## ![✔] 8.15. Lint your Dockerfile +### `🌟 #new` + **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:** 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. @@ -1289,8 +1625,8 @@ All translations are contributed by the community. We will be happy to get any h ### Translations in progress -- ![FR](./assets/flags/FR.png) [French](https://github.com/goldbergyoni/nodebestpractices/blob/master/README.french.md) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/129)) -- ![HE](./assets/flags/HE.png) Hebrew ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/156)) +- ![FR](./assets/flags/FR.png) [French](./README.french.md) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/129)) +- ![HE](./assets/flags/HE.png) [Hebrew](./README.hebrew.md) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/156)) - ![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)) @@ -1304,301 +1640,337 @@ Meet the steering committee members - the people who work together to provide gu [Yoni Goldberg](https://github.com/goldbergyoni) - - + + Independent Node.js consultant who works with customers in the USA, Europe, and Israel on building large-scale Node.js applications. Many of the best practices above were first published at [goldbergyoni.com](https://goldbergyoni.com). Reach Yoni at [@goldbergyoni](https://github.com/goldbergyoni) or [me@goldbergyoni.com](mailto:me@goldbergyoni.com)
- +Josh Hemphill -[Bruno Scheufler](https://github.com/BrunoScheufler) - +[Josh Hemphill](https://github.com/josh-hemphill) + + + -💻 full-stack web engineer, Node.js & GraphQL enthusiast +Full Stack Software Engineer / Developer specializing in Security, DevOps/DevSecOps, and ERP Integrations.
- +Raz Luvaton -[Kyle Martin](https://github.com/js-kyle) - - +[Raz Luvaton](https://github.com/rluvaton) + + -Full Stack Developer & Site Reliability Engineer based in New Zealand, interested in web application security, and architecting and building Node.js applications to perform at global scale. +Full Stack Developer who knows how to exit from Vim and loves Architecture, Virtualization and Security.
- - -[Kevyn Bruyere](https://github.com/kevynb) - +## Contributing -Independent full-stack developer with a taste for Ops and automation. +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 ✨ -### Steering Committee Emeriti +Thanks goes to these wonderful people who have contributed to this repository! - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Kevin Rambaud
Kevin Rambaud

🖋
Michael Fine
Michael Fine

🖋
Shreya Dahal
Shreya Dahal

🖋
Matheus Cruz Rocha
Matheus Cruz Rocha

🖋
Yog Mehta
Yog Mehta

🖋
Kudakwashe Paradzayi
Kudakwashe Paradzayi

🖋
t1st3
t1st3

🖋
mulijordan1976
mulijordan1976

🖋
Matan Kushner
Matan Kushner

🖋
Fabio Hiroki
Fabio Hiroki

🖋
James Sumners
James Sumners

🖋
Dan Gamble
Dan Gamble

🖋
PJ Trainor
PJ Trainor

🖋
Remek Ambroziak
Remek Ambroziak

🖋
Yoni Jah
Yoni Jah

🖋
Misha Khokhlov
Misha Khokhlov

🖋
Evgeny Orekhov
Evgeny Orekhov

🖋
-
-

🖋
Isaac Halvorson
Isaac Halvorson

🖋
Vedran Karačić
Vedran Karačić

🖋
lallenlowe
lallenlowe

🖋
Nathan Wells
Nathan Wells

🖋
Paulo Reis
Paulo Reis

🖋
syzer
syzer

🖋
David Sancho
David Sancho

🖋
Robert Manolea
Robert Manolea

🖋
Xavier Ho
Xavier Ho

🖋
Aaron
Aaron

🖋
Jan Charles Maghirang Adona
Jan Charles Maghirang Adona

🖋
Allen
Allen

🖋
Leonardo Villela
Leonardo Villela

🖋
Michał Załęcki
Michał Załęcki

🖋
Chris Nicola
Chris Nicola

🖋
Alejandro Corredor
Alejandro Corredor

🖋
cwar
cwar

🖋
Yuwei
Yuwei

🖋
Utkarsh Bhatt
Utkarsh Bhatt

🖋
Duarte Mendes
Duarte Mendes

🖋
Jason Kim
Jason Kim

🖋
Mitja O.
Mitja O.

🖋
Sandro Miguel Marques
Sandro Miguel Marques

🖋
Gabe
Gabe

🖋
Ron Gross
Ron Gross

🖋
Valeri Karpov
Valeri Karpov

🖋
Sergio Bernal
Sergio Bernal

🖋
Nikola Telkedzhiev
Nikola Telkedzhiev

🖋
Vitor Godoy
Vitor Godoy

🖋
Manish Saraan
Manish Saraan

🖋
Sangbeom Han
Sangbeom Han

🖋
blackmatch
blackmatch

🖋
Joe Reeve
Joe Reeve

🖋
Ryan Busby
Ryan Busby

🖋
Iman Mohamadi
Iman Mohamadi

🖋
Sergii Paryzhskyi
Sergii Paryzhskyi

🖋
Kapil Patel
Kapil Patel

🖋
迷渡
迷渡

🖋
Hozefa
Hozefa

🖋
Ethan
Ethan

🖋
Sam
Sam

🖋
Arlind
Arlind

🖋
Teddy Toussaint
Teddy Toussaint

🖋
Lewis
Lewis

🖋
Gabriel Lidenor
Gabriel Lidenor

🖋
Roman
Roman

🖋
Francozeira
Francozeira

🖋
Invvard
Invvard

🖋
Rômulo Garofalo
Rômulo Garofalo

🖋
Tho Q Luong
Tho Q Luong

🖋
Burak Shen
Burak Shen

🖋
Martin Muzatko
Martin Muzatko

🖋
Jared Collier
Jared Collier

🖋
Hilton Meyer
Hilton Meyer

🖋
ChangJoo Park(박창주)
ChangJoo Park(박창주)

🖋
Masahiro Sakaguchi
Masahiro Sakaguchi

🖋
Keith Holliday
Keith Holliday

🖋
coreyc
coreyc

🖋
Maximilian Berkmann
Maximilian Berkmann

🖋
Douglas Mariano Valero
Douglas Mariano Valero

🖋
Marcelo Melo
Marcelo Melo

🖋
Mehmet Perk
Mehmet Perk

🖋
ryan ouyang
ryan ouyang

🖋
Shabeer
Shabeer

🖋
Eduard Kyvenko
Eduard Kyvenko

🖋
Deyvison Rocha
Deyvison Rocha

🖋
George Mamer
George Mamer

🖋
Konstantinos Leimonis
Konstantinos Leimonis

🖋
Oliver Lluberes
Oliver Lluberes

🌍
Tien Do
Tien Do

🖋
Ranvir Singh
Ranvir Singh

🖋
Vadim Nicolaev
Vadim Nicolaev

🖋 🌍
German Gamboa Gonzalez
German Gamboa Gonzalez

🖋
Hafez
Hafez

🖋
Chandiran
Chandiran

🖋
VinayaSathyanarayana
VinayaSathyanarayana

🖋
Kim Kern
Kim Kern

🖋
Kenneth Freitas
Kenneth Freitas

🖋
songe
songe

🖋
Kirill Shekhovtsov
Kirill Shekhovtsov

🖋
Serge
Serge

🖋
keyrwinz
keyrwinz

🖋
Dmitry Nikitenko
Dmitry Nikitenko

🖋
bushuai
bushuai

👀 🖋
Benjamin Gruenbaum
Benjamin Gruenbaum

🖋
Ezequiel
Ezequiel

🌍
Juan José Rodríguez
Juan José Rodríguez

🌍
Or Bin
Or Bin

🖋
Andreo Vieira
Andreo Vieira

🖋
Michael Solomon
Michael Solomon

🖋
Jimmy Callin
Jimmy Callin

🖋
Siddharth
Siddharth

🖋
Ryan Smith
Ryan Smith

🖋
Tom Boettger
Tom Boettger

🖋
Joaquín Ormaechea
Joaquín Ormaechea

🌍
dfrzuz
dfrzuz

🌍
Victor Homyakov
Victor Homyakov

🖋
Josh
Josh

🖋 🛡️
Alec Francis
Alec Francis

🖋
arjun6610
arjun6610

🖋
Jan Osch
Jan Osch

🖋
Thiago Rotondo Sampaio
Thiago Rotondo Sampaio

🌍
Alexsey
Alexsey

🖋
Luis A. Acurero
Luis A. Acurero

🌍
Lucas Romano
Lucas Romano

🌍
Denise Case
Denise Case

🖋
Nick Ribal
Nick Ribal

🖋 👀
0xflotus
0xflotus

🖋
Jonathan Chen
Jonathan Chen

🖋
Dilan Srilal
Dilan Srilal

🖋
vladthelittleone
vladthelittleone

🌍
Nik Osvalds
Nik Osvalds

🖋
Daniel Kiss
Daniel Kiss

📖
Forresst
Forresst

🖋
Jonathan Svenheden
Jonathan Svenheden

🖋
AustrisC
AustrisC

🖋
kyeongtae kim
kyeongtae kim

🌍
007
007

🖋
Ane Diaz de Tuesta
Ane Diaz de Tuesta

🌍 🖋
YukiOta
YukiOta

🌍
Frazer Smith
Frazer Smith

🖋
Raz Luvaton
Raz Luvaton

🖋
Yuta Azumi
Yuta Azumi

🖋
andrewjbarbour
andrewjbarbour

🖋
mr
mr

🖋
Aleksandar
Aleksandar

🖋
Owl
Owl

🖋
Yedidya Schwartz
Yedidya Schwartz

🖋 💡
ari
ari

🖋
Thomas König
Thomas König

🖋
Kalle Lämsä
Kalle Lämsä

🖋
Wyatt
Wyatt

🖋
KHADIR Tayeb
KHADIR Tayeb

🖋
Shankar Regmi
Shankar Regmi

🖋
Shubham
Shubham

🖋
Lucas Alves
Lucas Alves

🖋
Benjamin
Benjamin

🖋
Yeoh Joer
Yeoh Joer

🖋
Miigon
Miigon

🖋
Rostislav Bogorad
Rostislav Bogorad

🖋
Flouse
Flouse

🖋
Tarantini Pereira
Tarantini Pereira

🖋
Kazuki Matsuo
Kazuki Matsuo

🖋
Adam Smith
Adam Smith

🖋
Dohyeon Ko
Dohyeon Ko

🖋
Vladislav Legkov
Vladislav Legkov

🖋
Kerollos Magdy
Kerollos Magdy

🖋
Erez Lieberman
Erez Lieberman

🖋
Breno Macedo
Breno Macedo

🖋
Fernando Flores
Fernando Flores

🌍
Rafael Brito
Rafael Brito

🌍
Emiliano Peralta
Emiliano Peralta

🌍
Shin, SJ
Shin, SJ

🖋
Benjamin Forster
Benjamin Forster

🖋
Daniele Fedeli
Daniele Fedeli

🖋
djob195
djob195

🖋
antspk
antspk

🖋
정진영
정진영

🖋
kkk-cashwalk
kkk-cashwalk

🖋
apainintheneck
apainintheneck

🖋
Fajar Budhi Iswanda
Fajar Budhi Iswanda

🖋
이주호
이주호

🖋
Singh
Singh

🖋
Alex Dumitru
Alex Dumitru

🖋
Anton Lykhatskyi
Anton Lykhatskyi

🖋
sangwonlee
sangwonlee

🖋
Eugenio Berretta
Eugenio Berretta

🖋
soranakk
soranakk

🖋
고준영
고준영

🖋 💻
Guilherme Portella
Guilherme Portella

🖋
André Esser
André Esser

🖋
Scc
Scc

🌍
Mauro Accornero
Mauro Accornero

🖋
no-yan
no-yan

🖋
hodbauer
hodbauer

🌍
-[Sagir Khan](https://github.com/sagirk) - - - + + -Deep specialist in JavaScript and its ecosystem — React, Node.js, TypeScript, GraphQL, MongoDB, pretty much anything that involves JS/JSON in any layer of the system — building products using the web platform for the world’s most recognized brands. Individual Member of the Node.js Foundation. + -
+### Steering Committee Emeriti -## Collaborators +[Bruno Scheufler](https://github.com/BrunoScheufler) + -Thank you to all our collaborators! 🙏 +💻 full-stack web engineer, Node.js & GraphQL enthusiast -Our collaborators are members who are contributing to the repository on a regular basis, through suggesting new best practices, triaging issues, reviewing pull requests and more. If you are interested in helping us guide thousands of people to craft better Node.js applications, please read our [contributor guidelines](./.operations/CONTRIBUTING.md) 🎉 +
-| | | Raz Luvaton | Josh Hemphill | -| :--: | :--: | :--: | :--: | -| [Ido Richter (Founder)](https://github.com/idori) | [Keith Holliday](https://github.com/TheHollidayInn) | [Raz Luvaton](https://github.com/rluvaton) | [Josh Hemphill](https://github.com/josh-hemphill) | + -### Collaborator Emeriti +[Kyle Martin](https://github.com/js-kyle) + + -| | -| :-------------------------------------------------------------------------------------------------------------------------: | -| [Refael Ackermann](https://github.com/refack) | +Full Stack Developer & Site Reliability Engineer based in New Zealand, interested in web application security, and architecting and building Node.js applications to perform at global scale.
-## 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. +[Kevyn Bruyere](https://github.com/kevynb) + -## Contributors ✨ +Independent full-stack developer with a taste for Ops and automation. -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

🖋

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

📖

Forresst

🖋

Jonathan Svenheden

🖋

AustrisC

🖋

kyeongtae kim

🌍

007

🖋

Ane Diaz de Tuesta

🌍 🖋

YukiOta

🌍

Frazer Smith

🖋

Raz Luvaton

🖋

Yuta Azumi

🖋

andrewjbarbour

🖋

mr

🖋

Aleksandar

🖋

Owl

🖋

Yedidya Schwartz

🖋 💡

ari

🖋

Thomas König

🖋

Kalle Lämsä

🖋

Wyatt

🖋

KHADIR Tayeb

🖋

Shankar Regmi

🖋

Shubham

🖋

Lucas Alves

🖋

Benjamin

🖋

Yeoh Joer

🖋

Miigon

🖋

Rostislav Bogorad

🖋

Flouse

🖋

Tarantini Pereira

🖋

Kazuki Matsuo

🖋

Adam Smith

🖋

Dohyeon Ko

🖋

Vladislav Legkov

🖋

Kerollos Magdy

🖋

Erez Lieberman

🖋
+ - - +[Sagir Khan](https://github.com/sagirk) + + + - +Deep specialist in JavaScript and its ecosystem — React, Node.js, TypeScript, GraphQL, MongoDB, pretty much anything that involves JS/JSON in any layer of the system — building products using the web platform for the world’s most recognized brands. Individual Member of the Node.js Foundation. diff --git a/README.polish.md b/README.polish.md index 1f33f8d8a..3fdae83d2 100644 --- a/README.polish.md +++ b/README.polish.md @@ -256,7 +256,8 @@ function someFunction() { } // Avoid -function someFunction() { +function someFunction() +{ // code block } ``` @@ -275,7 +276,7 @@ Bez względu na to, czy używasz średników, czy też nie rozdzielasz swoich in **W przeciwnym razie:** Jak widać w poprzedniej sekcji, interpreter JavaScript automatycznie dodaje średnik na końcu instrukcji, jeśli nie istnieje, lub uważa instrukcję za niezakończoną tam, gdzie powinna, co może prowadzić do niepożądanych wyników. Możesz używać przypisań i unikać używania natychmiastowych wywoływanych wyrażeń funkcyjnych, aby zapobiec większości nieoczekiwanych błędów. -### Przykład kodu +### Przykład Kodu ```javascript // Do @@ -899,7 +900,7 @@ Wszystkie powyższe instrukcje zwrócą wartość false, jeśli zostaną użyte -**TL;DR:** `eval` jest złe, ponieważ pozwala na wykonanie niestandardowego kodu JavaScript w czasie wykonywania. Jest to nie tylko kwestia wydajności, ale także ważna kwestia bezpieczeństwa ze względu na złośliwy kod JavaScript, który może pochodzić z danych wejściowych użytkownika. Inną cechą językową, której należy unikać, jest konstruktor `new Function`. `setTimeout` i` setInterval` nigdy nie powinny być przekazywane dynamicznemu kodowi JavaScript. +**TL;DR:** `eval` jest złe, ponieważ pozwala na wykonanie niestandardowego kodu JavaScript w czasie wykonywania. Jest to nie tylko kwestia wydajności, ale także ważna kwestia bezpieczeństwa ze względu na złośliwy kod JavaScript, który może pochodzić z danych wejściowych użytkownika. Inną cechą językową, której należy unikać, jest konstruktor `new Function`. `setTimeout` i`setInterval` nigdy nie powinny być przekazywane dynamicznemu kodowi JavaScript. **W przeciwnym razie:** Złośliwy kod JavaScript znajduje drogę do tekstu przekazywanego do `eval` lub innych funkcji języka JavaScript oceniających w czasie rzeczywistym, i uzyskuje pełny dostęp do uprawnień JavaScript na stronie. Luka ta często objawia się jako atak XSS. @@ -1015,7 +1016,7 @@ Wszystkie powyższe instrukcje zwrócą wartość false, jeśli zostaną użyte -**TL;DR:** Należy podjąć środki ostrożności, aby uniknąć ryzyka przypadkowego opublikowania danych wrażliwych w publicznych rejestrach npm. Plik `.npmignore` może być użyty do umieszczenia na czarnej liście określonych plików lub folderów, lub tablica` files` w `package.json` może działać jako biała lista. +**TL;DR:** Należy podjąć środki ostrożności, aby uniknąć ryzyka przypadkowego opublikowania danych wrażliwych w publicznych rejestrach npm. Plik `.npmignore` może być użyty do umieszczenia na czarnej liście określonych plików lub folderów, lub tablica`files` w `package.json` może działać jako biała lista. **W przeciwnym razie:** Klucze API, hasła i inne dane wrażliwe twojego projektu są otwarte na wykorzystywanie przez każdego, kto je napotka, co może spowodować straty finansowe, podszywanie się pod inne osoby i inne ryzyko. diff --git a/README.russian.md b/README.russian.md index 9387a29e1..7030112dd 100644 --- a/README.russian.md +++ b/README.russian.md @@ -34,7 +34,7 @@

-# Добро пожаловать! 3 вещи, которые вы должны знать в первую очередь: +# Добро пожаловать! 3 вещи, которые вы должны знать в первую очередь **1. На самом деле вы читаете десятки лучших статей Node.js -** этот репозиторий представляет собой краткий обзор и список наиболее популярных материалов по рекомендациям Node.js, а также материалов, написанных здесь соавторами. @@ -46,13 +46,13 @@ ## Оглавление -1. [Практики структуры проекта (5)](#1-Практики-структуры-проекта) -2. [Практики обработки ошибок (11)](#2-Практики-обработки-ошибок) -3. [Практики стиля кода (12)](#3-Практики-стиля-кода) -4. [Тестирование и общие методы контроля качества (12)](#4-Тестирование-и-общие-методы-контроля-качества) -5. [Переход к производственным практикам (18)](#5-Переход-к-производственным-практикам) -6. [Практики безопасности (25)](#6-Практики-безопасности) -7. [Практики эффективности (2) (Работа в процессе️ ✍️)](#7-черновик-практики-эффективности) +1. [Практики структуры проекта (5)](#1-Практики-структуры-проекта) +2. [Практики обработки ошибок (11)](#2-Практики-обработки-ошибок) +3. [Практики стиля кода (12)](#3-Практики-стиля-кода) +4. [Тестирование и общие методы контроля качества (12)](#4-Тестирование-и-общие-методы-контроля-качества) +5. [Переход к производственным практикам (18)](#5-Переход-к-производственным-практикам) +6. [Практики безопасности (25)](#6-Практики-безопасности) +7. [Практики эффективности (2) (Работа в процессе️ ✍️)](#7-черновик-практики-эффективности)

@@ -259,7 +259,7 @@

-##! [✔] 3.3 Начинайте кодовый блок фигурными скобками на той же линии. +## ! [✔] 3.3 Начинайте кодовый блок фигурными скобками на той же линии **TL;DR:** Открывающие фигурные скобки блока кода должны находиться на той же строке, что и оператор открытия. @@ -272,7 +272,7 @@ function someFunction() { } // Избегайте -function someFunction() +function someFunction() { // code block } @@ -284,7 +284,7 @@ function someFunction()

-##! [✔] 3.4 Разделяйте свои выражения правильно +## ! [✔] 3.4 Разделяйте свои выражения правильно Независимо от того, используете ли вы точки с запятой или нет для разделения своих операторов, знание общих ошибок неправильных разрывов строк или автоматической вставки точек с запятой поможет вам устранить обычные синтаксические ошибки. @@ -292,7 +292,7 @@ function someFunction() **Иначе:** Как видно из предыдущего раздела, интерпретатор JavaScript автоматически добавляет точку с запятой в конце оператора, если его нет, или считает, что оператор не завершен, где он должен, что может привести к нежелательным результатам. , Вы можете использовать присваивания и избегать немедленного вызова выражений функций для предотвращения большинства непредвиденных ошибок. -### Пример кода +### 3.4 Пример кода ```javascript // Делайте так @@ -342,7 +342,7 @@ const count = 2 // it tries to run 2(), but 2 is not a function **Иначе:** Javascript -- это единственный язык в мире, который позволяет напрямую вызывать конструктор ("Class") без его инициализации. Следовательно, классы и конструкторы функций должщны различаться, начинаясь с UpperCamelCase. -### Пример кода +### 3.6 Пример кода ```javascript // для класса мы используем UpperCamelCase @@ -384,7 +384,7 @@ function doSomething() {} **Иначе:** Изменение внутренней структуры файлов или подписи может нарушить интерфейс с клиентами. -### Пример кода +### 3.9 Пример кода ```javascript // Делайте так @@ -404,7 +404,7 @@ module.exports.SMSNumberResolver = require("./SMSNumberResolver/SMSNumberResolve **Иначе:** Неравные переменные могут возвращать true при сравнении с оператором `==`. -### Пример кода +### 3.10 Пример кода ```javascript "" == "0"; // false @@ -559,7 +559,7 @@ null == undefined; // true # `5. Переход к производственным практикам` -## ![✔] 5.1. Мониторинг! +## ![✔] 5.1. Мониторинг **TL;DR:** Мониторинг -- это игра для выявления проблем до того, как их решат клиенты, очевидно, этому следует придать беспрецедентную важность. Рынок перегружен предложениями, поэтому подумайте о том, чтобы начать с определения основных метрик, которым вы должны следовать (мои предложения в подробностях), затем перейти к дополнительным необычным функциям и выбрать решение, которое помечает все поля. Нажмите "Подробнее" ниже для обзора решений. @@ -793,7 +793,7 @@ null == undefined; // true

-##! [✔] 6.5. Сборник общих рекомендаций по безопасности +## ! [✔] 6.5. Сборник общих рекомендаций по безопасности **TL;DR:** Это набор рекомендаций по безопасности, которые не связаны напрямую с Node.js -- реализация Node мало чем отличается от любого другого языка. Нажмите "Подробнее", чтобы просмотреть. @@ -837,7 +837,7 @@ null == undefined; // true

-##! [✔] 6.9. Экранируйте вывод HTML, JS и CSS +## ! [✔] 6.9. Экранируйте вывод HTML, JS и CSS @@ -916,7 +916,7 @@ null == undefined; // true -**TL;DR:** `eval` -- это зло, поскольку оно позволяет выполнять пользовательский код JavaScript во время выполнения. Это не только проблема производительности, но и важная проблема безопасности из-за вредоносного кода JavaScript, который может быть получен из пользовательского ввода. Другой языковой особенностью, которую следует избегать, является конструктор `new Function`. `setTimeout` и` setInterval` также никогда не должны передавать динамический код JavaScript. +**TL;DR:** `eval` -- это зло, поскольку оно позволяет выполнять пользовательский код JavaScript во время выполнения. Это не только проблема производительности, но и важная проблема безопасности из-за вредоносного кода JavaScript, который может быть получен из пользовательского ввода. Другой языковой особенностью, которую следует избегать, является конструктор `new Function`. `setTimeout` и`setInterval` также никогда не должны передавать динамический код JavaScript. **Иначе:** Вредоносный код JavaScript находит путь в текст, передаваемый в `eval` или другие функции оценки языка JavaScript в режиме реального времени, и получает полный доступ к разрешениям JavaScript на странице. Эта уязвимость часто проявляется как атака XSS. @@ -1032,7 +1032,7 @@ null == undefined; // true -**TL;DR:** Следует принять меры предосторожности, чтобы избежать риска случайной публикации секретов в открытых реестрах npm. Файл `.npmignore` может использоваться для внесения в черный список определенных файлов или папок, или массив` files` в `package.json` может выступать в качестве белого списка. +**TL;DR:** Следует принять меры предосторожности, чтобы избежать риска случайной публикации секретов в открытых реестрах npm. Файл `.npmignore` может использоваться для внесения в черный список определенных файлов или папок, или массив`files` в `package.json` может выступать в качестве белого списка. **Иначе:** Ключи API вашего проекта, пароли или другие секреты открыты для злоупотребления любым, кто сталкивается с ними, что может привести к финансовым потерям, подлогу и другим рискам. diff --git a/README.spanish.md b/README.spanish.md index fa4a99ebc..c4e4fe471 100644 --- a/README.spanish.md +++ b/README.spanish.md @@ -9,102 +9,324 @@
- 102 items Last update: July 04, 2021 Updated for Node 14.0.0 + 102 items Last update: January 3rd, 2024 Updated for Node 22.0.0

-[![nodepractices](/assets/images/twitter-s.png)](https://twitter.com/nodepractices/) **¡Síguenos en** [**@nodepractices**](https://twitter.com/nodepractices/) +[]https://twitter.com/nodepractices/) **¡Síguenos en Twitter!** [**@nodepractices**](https://twitter.com/nodepractices/)
-Lee en un idioma diferente: [![CN](/assets/flags/CN.png)**CN**](/README.chinese.md), [![FR](/assets/flags/FR.png)**FR**](/README.french.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), [![EU](/assets/flags/EU.png)**EU**](/README.basque.md) [(![ES](/assets/flags/ES.png)**ES**, ![HE](/assets/flags/HE.png)**HE**, ![KR](/assets/flags/KR.png)**KR** and ![TR](/assets/flags/TR.png)**TR** ¡En proceso! )](#translations) +Leelo en otro idioma: [![CN](./assets/flags/CN.png)**CN**](./README.chinese.md), [![FR](./assets/flags/FR.png)**FR**](./README.french.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), [![EU](./assets/flags/EU.png)**EU**](./README.basque.md) [(![ES](./assets/flags/ES.png)**ES**, ![HE](./assets/flags/HE.png)**HE**, ![KR](./assets/flags/KR.png)**KR** and ![TR](./assets/flags/TR.png)**TR** in progress! )](#translations)
-###### Built and maintained by our [Steering Committee](#steering-committee) and [Collaborators](#collaborators) +# 🎊 ¡La edición 2024 está aquí! -# Latest Best Practices and News +- **🛰 Modernizado al 2024**: Montones de ediciones de texto, nuevas bibliotecas recomendadas y varias nuevas mejores prácticas -- **![FR](/assets/flags/FR.png) French translation!1! :** The latest translation that joins our international guide is French. Bienvenue +- **✨ Enfocate facilmente en nuevo contenido**: ¿Ya lo has visitado? Busca las etiquetas `#new` o `#updated` exclusivas para contenido nuevo -- **🇯🇵 Japanese translation:** Our guide is now also translated to Japanese! Courtesy of the amazing [YukiOta](https://github.com/YukiOta) and [Yuta Azumi](https://github.com/YA21) - -- **🎊 60,000 stars!**: Our repo was starred and trusted by 60,100 developers. We're speechless +- **🔖 ¿Tienes curiosidad por ver ejemplos? Tenemos un Starter**: Visita [Practica.js](https://github.com/practicajs/practica), nuestro ejemplo de aplicación y plantilla (beta) para ver algunas prácticas en acción

-# ¡Bienvenido! 3 cosas que deberías saber primero: -**1. Aquí encontrarás docenas de los mejores artículos sobre Node.JS -** este es un resumen y conservación del contenido mejor clasificado de las mejores prácticas de NodeJS +# ¡Bienvenido! 3 cosas que deberías saber primero -**2. Es la compilación más grande y crece cada semana -** actualmente, se presentan más de 80 prácticas, guías de estilo y consejos arquitectónicos. Nuevos issues y pull request son creados cada día para mantener esta guía actualizada. Nos encantaría verte contribuyendo, ya sea arreglando errores en el código, ayudando en traducciones, o sugiriendo nuevas ideas. Ve las [Normas de contribución](./operations/writing-guidelines.spanish.md) +**1. Está leyendo docenas de los mejores artículos de Node.js -** este repositorio es un resumen y curación del contenido mejor clasificado de las mejores prácticas de NodeJS, así como el contenido escrito aquí por colaboradores -**3. La mayoría de los puntos tienen información adicional -** Encontrarás cerca de cada punto de mejores prácticas el enlace **🔗Leer más** que te dará algunos ejemplos de código, citas de blogs seleccionados y mas información +**2. Es la compilación más grande y crece cada semana -** actualmente, se presentan más de 80 prácticas, guías de estilo y consejos arquitectónicos. Nuevos issues y pull request son creados cada día para mantener esta guía actualizada. Nos encantaría verte contribuyendo, ya sea arreglando errores en el código, ayudando en las traducciones, o sugiriendo brillantes nuevas ideas. Ve las [Normas de contribución](./.operations/writing-guidelines.spanish.md) -


+**3. Las mejores prácticas tienen información adicional -** la mayoría de los puntos incluyen el enlace **🔗Leer más** que expanden la práctica con ejemplos de código, citas de blogs seleccionados y mas información + +

+ +# By Yoni Goldberg + +### Aprenda conmigo: como consultor, participo con equipos de todo el mundo en diversas actividades, como talleres y revisiones de código. 🎉Y... Espera, acabo de lanzar mi [curso de pruebas más allá de lo básico, que está en oferta por tiempo limitado](https://testjavascript.com/) hasta el 7 de agosto + +

## Tabla de contenidos -1. [Prácticas para estructura del proyecto (5)](#1-prácticas-de-estructura-del-proyecto) -2. [Prácticas en manejo de errores (12) ](#2-prácticas-en-manejo-de-errores) -3. [Prácticas de estilo de código (12) ](#3-prácticas-de-estilo-de-código) -4. [Prácticas de prueba y calidad en general (13) ](#4-pruebas-y-prácticas-generales-de-calidad) -5. [Prácticas de puesta en producción (19) ](#5-yendo-a-las-prácticas-de-producción) -6. [Prácticas de seguridad (25)](#6-mejores-prácticas-de-seguridad) -7. [Prácticas de rendimiento (2) (En Progreso ✍️)](#7-borrador-mejores-prácticas-de-rendimiento) -8. [Prácticas de Docker (15)](#8-mejores-prácticas-de-docker) +
+ + 1. Prácticas para estructura del proyecto (6) + + +  [1.1. Estructura tu solución en componentes `#strategic` `#updated`](#-11-estructura-tu-solución-en-componentes-de-negocio)
+  [1.2. Pon tus componentes en capas, mantén la capa web dentro de sus límites `#strategic` `#updated`](#-12-pon-tus-componentes-en-capas-mantén-la-capa-web-dentro-de-sus-límites)
+  [1.3. Engloba utilidades comunes como paquetes, considera publicarlos](#-13-engloba-utilidades-comunes-como-paquetes-considera-publicarlos)
+  [1.4 Usa una configuración consciente del entorno,segura y jerárquica `#updated`](#-14-usa-una-configuración-consciente-del-entornosegura-y-jerárquica)
+  [1.5 Considera todas las consecuencias al elegir el framwork principal `#new`](#-15-considera-todas-las-consecuencias-al-elegir-el-framwork-principal)
+  [1.6 Utiliza TypeScript con moderación y consideración `#new`](#-16-utiliza-typescript-con-moderación-y-consideración)
+ +
+ +
+ + 2. Prácticas en manejo de errores (12) + + +  [2.1 Usa Async-Await o promesas para el manejo de errores asíncronos](#-21-usa-async-await-o-promesas-para-el-manejo-de-errores-asíncronos)
+  [2.2 Extiende el objeto Error nativo `#strategic` `#updated`](#-22-extiende-el-objeto-error-nativo)
+  [2.3 Distingue errores catastróficos de errores operacionales `#strategic` `#updated`](#-23-distingue-errores-catastróficos-de-errores-operacionales)
+  [2.4 Maneja los errores centralmente, no dentro de un middleware `#strategic`](#-24-maneja-los-errores-centralmente-no-dentro-de-un-middleware)
+  [2.5 Documenta errores del API con OpenAPI o GraphQL](#-25-documenta-errores-del-api-con-open-api-o-graphql)
+  [2.6 Cierra el proceso elegantemente cuando un extraño llega a la ciudad `#strategic`](#-26-cierra-el-proceso-elegantemente-cuando-un-extraño-llega-a-la-ciudad)
+  [2.7 Usa un logger maduro para aumentar la visibilidad de los errores `#updated`](#-27-usa-un-logger-maduro-para-aumentar-la-visibilidad-de-los-errores)
+  [2.8 Pruebas los flujos de errores usando tu framework de prueba favorito `#updated`](#-28-pruebas-los-flujos-de-errores-usando-tu-framework-de-prueba-favorito)
+  [2.9 Descubre errores y tiempo de inactividad usando productos de APM](#-29-descubre-errores-y-tiempo-de-inactividad-usando-productos-de-apm)
+  [2.10 Captura los rechazos de promesas no controladas `#updated`](#-210-captura-los-rechazos-de-promesas-no-controladas)
+  [2.11 Falla rápidamente, valida los argumentos usando una biblioteca dedicada](#-211-falla-rápidamente-valida-los-argumentos-usando-una-biblioteca-dedicada)
+  [2.12 Siempre resuelve las promesas antes de retornarlas para evitar un stacktrace parcial `#new`](#-212-always-await-promises-before-returning-to-avoid-a-partial-stacktrace)
+  [2.13 Subscribete al evento 'error' de los emisores de eventos `#new`](#-213-subscribete-al-evento-'error'-de-los-emisores-de-eventos)
+ +
+ +
+ + 3. Prácticas de estilo de código (13) + + +  [3.1 Utiliza ESLint `#strategic`](#-31-utiliza-eslint)
+  [3.2 Utiliza las extensiones de eslint para para Node.js `#updated`](#-32-utiliza-las-extensiones-de-eslint-para-para-nodejs)
+  [3.3 Inicia las llaves de un bloque de código en la misma línea](#-33-inicia-las-llaves-de-un-bloque-de-código-en-la-misma-línea)
+  [3.4 Separa tus sentencias correctamente](#-34-Separa tus sentencias correctamente)
+  [3.5 Nombra a tus funciones](#-35-nombra-a-tus-funciones)
+  [3.6 Usa convenciones de nombre para variables, constantes, funciones y clases](#-36-usa-convenciones-de-nombre-para-variables-constantes-funciones-y-clases)
+  [3.7 Prefiere const antes que let. No uses var](#-37-prefiere-const-antes-que-let-no-uses-var)
+  [3.8 Importa los módulos primero, no dentro de funciones](#-38-importa-los-módulos-primero-no-dentro-de-funciones)
+  [3.9 Establece un punto de entrada explícito a un módulo/carpeta `#updated`](#-39-establece-un-punto-de-entrada-explícito-a-un-módulocarpeta)
+  [3.10 Usa el operador ===](#-310-usa el-operador-)
+  [3.11 Usa Async Await, evita los callbacks `#strategic`](#-311-usa-async-await-evita-los-callbacks)
+  [3.12 Usa expresiones de función flecha (=>)](#-312-usa-expresiones-de-funcion-flecha-)
+  [3.13 Evita efectos fuera de las funciones `#new`](#-313-evita-efectos-fuera-de-las-funciones)
+ +
+ +
+ + 4. Prácticas de prueba y calidad en general (13) + + +  [4.1 Por lo menos, escribe las pruebas de la API (componente) `#strategic`](#-41-por-lo-menos,-escribe-las-pruebas-de-la-api-)
+  [4.2 Incluye 3 partes en cada nombre de prueba `#new`](#-42-incluye-3-partes-en-cada-nombre-de-prueba)
+  [4.3 Estructura las pruebas utilizando el patrón AAA `#strategic`](#-43-estructura-las-pruebas-utilizando-el-patrón-aaa)
+  [4.4 Asegurate que la versión de Node esté unificada `#new`](#-44-asegurate-que-la-versión-de-node-esté-unificada)
+  [4.5 Evita estados de prueba (fixtures) y semillas globales, agrega datos por prueba `#strategic`](#-45-evita-estados-de-prueba-fixtures-y-semillas-globales-agrega-datos-por-prueba)
+  [4.6 Etiqueta tus pruebas `#advanced`](#-4etiqueta-tus-pruebas)
+  [4.7 Verifica la cobertura de tus pruebas, ayuda a identificar patrones de prueba incorrectos](#-47-verifica-la-cobertura-de-tus-pruebas-ayuda-a-identificar-patrones-de-prueba-incorrectos)
+  [4.8 Usa un ambiente similar al de producción para pruebas e2e](#-48-usa-un-ambiente-similar-al-de-producción-para-pruebas-e2e)
+  [4.9 Refactoriza regularmente utilizando herramientas de análisis estático de código](#-49-refactor-regularly-using-static-analysis-tools)
+  [4.10 Simula las respuestas de servicios HTTP externos #advanced `#new` `#advanced`](#-410-simula-las-respuestas-de-servicios-http-externos)
+  [4.11 Prueba tus middlewares por separado](#-411-prueba-tus-middlewares-por-separado)
+  [4.12 Especifica un puerto en producción, aleatorizalo en las pruebas `#new`](#-412-especifica-un-puerto-en-producción-aleatorizalo-en-las-pruebas)
+  [4.13 Prueba los cinco posibles resultados #strategic `#new`](#-413-prueba-los-cinco-posibles-resultados)
+ +
+ +
+ + 5. Prácticas de puesta en producción (19) + + +  [5.1. Monitoreo `#strategic`](#-51-monitoreo)
+  [5.2. Aumenta la observabilidad utilizando logging inteligente `#strategic`](#-52-aumenta-la-observabilidad-utilizando-logging-inteligente)
+  [5.3. Delega todo lo posible (por ejemplo, gzip, SSL) a un proxy inverso `#strategic`](#-53-delega-todo-lo-posible-por-ejemplo-gzip-ssl-a-un-proxy-inverso)
+  [5.4. Bloquea dependencias](#-54-bloquea-dependencias)
+  [5.5. Proteje la disponibilidad del proceso utilizando la herramienta adecuada](#-55-proteje-la-disponibilidad-del-proceso-utilizando-la-herramienta-adecuada)
+  [5.6. Utiliza todos los núcleos de la CPU](#-56-utiliza-todos-los-núcleos-de-la-cpu)
+  [5.7. Crea un "endpoint de mantenimiento"](#-57-crea-un-endpoint-de-mantenimiento)
+  [5.8. Descubre lo desconocido utilizando productos de APM `#advanced` `#updated`](#-58-descubre-lo-desconocido-utilizando-productos-de-apm)
+  [5.9. Haz tu código listo para producción](#-59-haz-tu-código-listo-para-producción)
+  [5.10. Mide y protege el uso de la memoria `#advanced`](#-510-mide-y-protege-el-uso-de-la-memoria)
+  [5.11. Saca tus recursos frontend de Node](#-511-saca-tus-recursos-frontend-de-node)
+  [5.12. Esfuerzate por ser stateless `#strategic`](#-512-esfuerzate-por-ser-stateless)
+  [5.13. Usa herramientas que detecten automáticamente vulnerabilidades](#-513-usa-herramientas-que-detecten-automáticamente-vulnerabilidades)
+  [5.14. Asigna un id de transacción a cada registro del log `#advanced`](#-514-asigna-un-id-de-transacción-a-cada-registro-del-log)
+  [5.15. Establece `NODE_ENV=production`](#-515-establece-node_envproduction)
+  [5.16. Diseña despliegues automatizados, atómicos y sin tiempo de inactividad `#advanced`](#-516-diseña-despliegues-automatizados-atómicos-y-sin-tiempo-de-inactividad)
+  [5.17. Usa una versión LTS de Node.js](#-517-usa-una-version-lts-de-nodejs)
+  [5.18. Loguea hacia stdout, evita especificar un destino de log dentro de la aplicación `#updated`](#-518-loguea-hacia-stdout-evita-especificar-un-destino-de-log-dentro-de-la-aplicación)
+  [5.19. Instala tus paquetes con `npm ci`` `#new`](#-519-instala-tus-paquetess-con-npm-ci)
+ +
+ +
+ + 6. Prácticas de seguridad (25) + + +  [6.1. Adopta las reglas de seguridad del linter](#-61-adopta-las-reglas-de-seguridad-del-linter)
+  [6.2. Limita las solicitudes concurrentes utilizando un middleware](#-62-limita-las-solicitudes-concurrentes-utilizando-un-middleware)
+  [6.3. Quita los secretos de los archivos de configuración o utiliza paquetes para cifrarlos `#strategic`](#-63-quita-los-secretos-de-los-archivos-de-configuración-o-utiliza-paquetes-para-cifrarlos)
+  [6.4. Evita vulnerabilidades de inyección de consultas con bibliotecas ORM / ODM `#strategic`](#-64-evita-vulnerabilidades-de-inyección-de-consultas-con-bibliotecas-orm--odm)
+  [6.5. Colección de mejores prácticas de seguridad genéricas](#-65-colección-de-mejores-prácticas-de-seguridad-genéricas)
+  [6.6. Ajusta los encabezados de respuesta HTTP para mayor seguridad](#-66-ajusta-los-encabezados-de-respuesta-http-para-mayor-seguridad)
+  [6.7. Inspecciona constante y automáticamente en busca de dependencias vulnerables `#strategic`](#-67-inspecciona-constante-y-automáticamente-en-busca-de-dependencias-vulnerables)
+  [6.8. Protege las contraseñas/secretos de sus usuarios usando bcrypt o scrypt `#strategic`](#-68-protege-las-contraseñas/secretos-de-sus-usuarios-usando-bcrypt-o-scrypt)
+  [6.9. Escapa la salida de HTML, JS y CSS](#-69-escapa-la-salida-de-html-js-y-css)
+  [6.10. Valida esquemas JSON entrantes `#strategic`](#-610-Valida esquemas JSON entrantes)
+  [6.11. Soporta listas de bloqueo de JWTs](#-611-soporta-listas-de-bloqueo-de-jwts)
+  [6.12. Evita ataques de fuerza bruta contra la autorización `#advanced`](#-612-evita-ataques-de-fuerza-bruta-contra-la-autorización)
+  [6.13. Ejecuta Node.js como usuario no root](#-613-ejecuta-nodejs-como-usuario-no-root)
+  [6.14. Limita el tamaño del mensaje utilizando un proxy inverso o un middleware](#-614-limita-el-tamaño-del-mensaje-utilizando-un-proxy-inverso-o-un-middleware)
+  [6.15. Evita las sentencias eval de JavaScript](#-615-evita-las-sentencias-eval-de-java-script)
+  [6.16. Evita que una RegEx maliciosa sobrecargue la ejecución del único hilo](#-616-evita-que-una-reg-ex-maliciosa-sobrecargue-la-ejecución-del-único-hilo)
+  [6.17. Evita cargar módulos usando variables](#-617-evita-cargar-módulos-usando-variables)
+  [6.18. Ejecuta código inseguro en un sandbox](#-618-ejecuta-código-inseguro-en-un-sandbox)
+  [6.19. Ten especial cuidado al trabajar con procesos secundarios `#advanced`](#-619-ten-especial-cuidado-al-trabajar-con-procesos-secundarios)
+  [6.20. Oculta los detalles de error de los clientes](#-620-oculta-los-detalles-de-error-de-los-clientes)
+  [6.21. Configura 2FA para npm o Yarn `#strategic`](#-621-configura-2fa-para-npm-o-yarn)
+  [6.22. Modifica la configuración del middleware de sesión](#-622-modifica-la-configuración-del-middleware-de-sesión)
+  [6.23. Evita los ataques de DoS estableciendo explícitamente cuándo debe fallar un proceso `#advanced`](#-623-evita-los-ataques-de-do-s-estableciendo-explícitamente-cuándo-debe-fallar-un-proceso)
+  [6.24. Evita redirecciones inseguras](#-624-evita-redirecciones-inseguras)
+  [6.25. Evita publicar secretos en el registro npm](#-625-evita-publicar-secretos-en-el-registro-npm)
+  [6.26. Inspecciona si hay paquetes obsoletos](#-626-inspect-for-outdated-packages)
+  [6.27. Importa los módulos integrados utilizando el protocolo 'node:' `#new`](#-627-inspecciona-si-hay-paquetes-obsoletos)
+ +
+ +
+ + 7. Prácticas de rendimiento (2) (En Progreso ✍️) + + +  [7.1. No bloquees el Event Loop](#-71-no-bloquees-el-event-loop)
+  [7.2. Prefiere los métodos nativos a los de utilidades de usuario como Lodash](#-72-prefiere-los-métodos-nativos-a-los-de-utilidades-de-usuario-como-lodash)
+ +
+ +
+ + 8. Prácticas de Docker (15) + + +  [8.1. Usa compilaciones de múltiples etapas para obtener imágenes de Docker más sencillas y seguras `#strategic`](#-81-usa-compilaciones-de-múltiples-etapas-para-obtener-imágenes-de-docker-más-sencillas-y-seguras)
+  [8.2. Arranca usando el comando `node`, evita `npm start`](#-82-arranca-usando-el-comando-node-evita-npm-start)
+  [8.3. Permite al entorno de ejecución de Docker manejar la replicación y el tiempo de actividad `#strategic`](#-83-permite-al-entorno-de-ejecución-de-docker-manejar-la-replicación)
+  [8.4. Usa .dockerignore para evitar la fuga de secretos](#-84-usa-dockerignore-para-evitar-la-fuga-de-secretos)
+  [8.5. Limpia las dependencias antes de ir a producción](#-85-limpia-las-dependencias-antes-de-ir-a-producción)
+  [8.6. Apaga de manera inteligente y elegante `#advanced`](#-86-apaga-de-manera-inteligente-y-elegante)
+  [8.7. Establece límites de memoria utilizando Docker y v8 `#advanced` `#strategic`](#-87-establece-límites-de-memoria-utilizando-docker-y-v8)
+  [8.8. Planifica un almacenamiento en caché eficiente](#-88-planifica-un-almacenamiento-en-caché-eficiente)
+  [8.9. Utiliza una referencia de imagen explícita, evita la etiqueta `latest`](#-89-utiliza-una-referencia-de-imagen-explícita-evita-la-etiqueta-latest)
+  [8.10. Prefiere imágenes base de Docker pequeñas](#-810-prefiere-imágenes-base-de-docker-pequeñas)
+  [8.11. Limpia los secretos de tiempo de compilación, evita los secretos en args `#strategic #new`](#-811-limpia-los-secretos-de-tiempo-de-compilación-evita-los-secretos-en-args)
+  [8.12. Escanea las imágenes en busca de vulnerabilidades multi-capas `#advanced`](#-812-escanea-las-imágenes-en-busca-de-vulnerabilidades-multi-capas)
+  [8.13 Limpia la caché de NODE_MODULE](#-813-limpia-la-caché-de-node-module)
+  [8.14. Prácticas generales de Docker](#-814-prácticas-generales-de-docker)
+  [8.15. Usa un linter en tu Dockerfile `#new`](#-815-usa-un-linter-en tu-dockerfile)
+ +
+ +

-


# `1. Prácticas de estructura del proyecto` -## ![✔] 1.1 Estructura tu solución en componentes +## ![✔] 1.1. Estructura tu solución en componentes de negocio + +### `📝 #updated` -**TL;DR:** El peor inconveniente de las grandes aplicaciones es mantener una gran base de código con cientos de dependencias, un monolito que ralentiza a los desarrolladores que intentan incorporar nuevas características. En cambio, divide tu código en componentes, cada uno obtiene su propia carpeta o una base de código dedicada, y asegúrate de que cada unidad se mantenga pequeña y simple. Visita 'Leer más' a continuación para ver ejemplos de la estructura correcta del proyecto +**TL;DR:** La raíz de un sistema debe contener carpetas o repositorios que representen módulos de negocio de tamaño razonable. Cada componente representa un dominio de producto (es decir, contexto limitado), como 'componente de usuario', 'componente de pedido', etc. Cada componente tiene su propia API, lógica y base de datos lógica. ¿Cuál es el mérito significativo? Con un componente autónomo, cada cambio se realiza en un alcance granular y más pequeño: la sobrecarga mental, la fricción en el desarrollo y el miedo al despliegue son mucho menores. Como resultado, los desarrolladores pueden avanzar mucho más rápido. Esto no necesariamente exige una separación física y se puede lograr usando un Monorepo o un multi-repo. -**De lo contrario:** Cuando desarrolladores codifican nuevas características luchan por darse cuenta del impacto de su cambio y temen romper otros componentes dependientes - las implementaciones se vuelven más lentas y más riesgosas. También se considera más difícil escalar cuando todas las unidades de negocios no están separadas +```bash +my-system +├─ apps (componentes) +│ ├─ orders +│ ├─ users +│ ├─ payments +├─ libraries (funcionalidad genérica transversal a componentes) +│ ├─ logger +│ ├─ authenticator +``` + +**De lo contrario:** cuando se mezclan artefactos de varios módulos/temas, existen grandes posibilidades de que se forme un sistema 'espagueti' estrechamente acoplado. Por ejemplo, en una arquitectura donde el 'controlador del módulo a' puede llamar al 'servicio del módulo b', no hay límites claros de modularidad: cada cambio de código puede afectar cualquier otra cosa. Con este enfoque, sin límites claros entre módulos, los desarrolladores que codifican nuevas funcionalidades luchan por darse cuenta del alcance y el impacto de su cambio. En consecuencia, temen romper otros módulos y cada implementación se vuelve más lenta y riesgosa. 🔗 [**Leer más: estructura en componentes**](./sections/projectstructre/breakintcomponents.spanish.md)

-## ![✔] 1.2 Aplicar capas para componentes, mantén Express dentro de sus límites +## ![✔] 1.2. Pon tus componentes en capas, mantén la capa web dentro de sus límites + +### `📝 #updated` -**TL;DR:** Cada componente debería contener 'capas'- un objeto dedicado para la web, la lógica y código para acceso a datos. Esto no solo genera una clara separación de conceptos sino que también facilita significativamente los mocks y la pruebas del sistema. Aunque este es un patrón muy común, los desarrolladores de APIs tienden a mezclar capas pasando los objetos de la capa web (Express req, res) a la lógica de negocios y capas de datos, esto hace que su aplicación dependa y solo sea accesible por Express. +**TL;DR:** Cada componente debe contener "capas", una carpeta dedicada a temas comunes: "punto de entrada" donde reside el controlador, "dominio" donde reside la lógica y "acceso a datos". El principio principal de las arquitecturas más populares es separar las cuestiones técnicas (por ejemplo, HTTP, DB, etc.) de la lógica pura de la aplicación para que un desarrollador pueda codificar más funciones sin preocuparse por cuestiones de infraestructura. Poner cada inquietud en una carpeta dedicada, también conocida como [patrón de 3 capas] (https://es.wikipedia.org/wiki/Arquitectura_multicapa), es la forma más sencilla de lograr este objetivo. -**De lo contrario:** Una aplicación que mezcla objectos de web con otras capas no puede ser accedida por código de pruebas, CRON jobs, eventos de colas de mensajes, entre otros. +```bash +my-system +├─ apps (componentes) +│ ├─ component-a + │ ├─ entry-points (puntos de entrada) + │ │ ├─ api # el controlador va aquí + │ │ ├─ message-queue # el consumidor de mensaje va aqui + │ ├─ domain (dominio) # funcionalidades y flujos: DTO, servicios, lógica + │ ├─ data-access (acceso a datos) # Llamadas a DB sin ORM +``` + +**De lo contrario:** A menudo se ve que el desarrollador pasa objetos web como solicitud/respuesta a funciones en el dominio/capa lógica; esto viola el principio de separación y dificulta el acceso posterior al código lógico por parte de otros clientes, como código de prueba, tareas programadas, colas de mensajes. , etc. 🔗 [**Leer más: Aplicar capas a tu aplicación**](./sections/projectstructre/createlayers.spanish.md)

-## ![✔] 1.3 Envuelve las utilidades comunes como paquetes de NPM +## ![✔] 1.3. Engloba utilidades comunes como paquetes, considera publicarlos + +**TL;DR:** Coloca todos los módulos reutilizables en una carpeta dedicada, por ejemplo, "libraries" (bibliotecas), y debajo de cada módulo en su propia carpeta, por ejemplo, "/libraries/logger". Convierte a cada módulo en un paquete independiente con su propio archivo package.json para aumentar la encapsulación del módulo y permitir la publicación futura en un repositorio. En una configuración de Monorepo, los módulos se pueden consumir mediante un 'enlace npm' a sus rutas físicas, usando ts-paths o publicando e instalando desde un repositorio de paquetes como el registro npm. -**TL;DR:** En una aplicación grande que se constituye de múltiples bases de código, utilidades transversales como los loggers, cifrado y similares, deben de estar envueltos por su propio código y expuestos como paquetes privados de NPM. Esto permite compartirlos entre múltiples base de código y proyectos. +```bash +my-system +├─ apps (componentes) + │ ├─ component-a +├─ libraries (funcionalidad genérica transversal a componente) +│ ├─ logger +│ │ ├─ package.json +│ │ ├─ src +│ │ │ ├─ index.js + +``` -**De lo contrario:** Tendrás que inventar tu propia implementación y rueda de dependencia +**De lo contrario:** Los clientes de un módulo pueden importar y acoplarse a la funcionalidad interna de un módulo. Con un package.json en la raíz, se puede configurar un package.json.main o un package.json.exports para indicar explícitamente qué archivos y funciones forman parte de la interfaz pública. 🔗 [**Leer más: Estructura por característica**](./sections/projectstructre/wraputilities.spanish.md)

-## ![✔] 1.4 Separar 'servidor' y 'aplicación' de express +## ![✔] 1.4 Usa una configuración consciente del entorno,segura y jerárquica -**TL;DR:** Evite el desagradable hábito de definir toda la aplicación [Express](https://expressjs.com/) en un único archivo enorme; separa tú definición de 'Express' en al menos dos archivos: la declaración del API (app.js) y los características de red (WWW). Incluso para una mejor estructura, ubica tu declaración del API dentro de los componentes. +### `📝 #updated` -**De lo contrario:** Se podrá acceder a tu API para realizar pruebas solo a través de llamadas HTTP (más lento y mucho más difícil para generar informes de cobertura). Probablemente tampoco sea un placer enorme mantener cientos de líneas de código en un solo archivo +**TL;DR:** La configuración perfecta e impecable debe incluir: a) los entradas que se pueden leer desde el archivo Y desde la variable de entorno; b) los secretos se guardan fuera del código al que se ha hecho commit; c) la configuración es jerárquica para facilitar la localización; d) soporte al tipado; e) validación para fallar rápido; f) especificar un valor por defecto para cada entrada. Solo hay unos pocos paquetes que pueden ayudar a cumplir con la mayoría de estos casos como [convict](https://www.npmjs.com/package/convict), [env-var](https://github.com/evanshortiss/env-var), [zod](https://github.com/colinhacks/zod), otros. -🔗 [**Leer más: separar 'servidor' y 'aplicación' de express**](./sections/projectstructre/separateexpress.spanish.md) +**De lo contrario:** Considera una variable de entorno obligatoria que no se proporcionó. La aplicación se inicia correctamente y atiende solicitudes; parte de la información ya se conserva en la base de datos. Luego, se da cuenta de que sin esta clave obligatoria la solicitud no se puede completar, lo que deja la aplicación en un estado sucio. + +🔗 [**Leer más: buenas prácticas de configuración**](./sections/projectstructre/configguide.spanish.md)

-## ![✔] 1.5 Usar una configuración segura, jerárquica y consciente del entorno +## ![✔] 1.5. Considera todas las consecuencias al elegir el framwork principal -**TL;DR:** La configuración perfecta e impecable debe incluir (a) claves que se pueden leer desde el archivo Y desde la variable de entorno (b) los secretos se guardan fuera del código al que se ha hecho commit (c) config es jerárquica para facilitar la localización. Solo hay unos pocos paquetes que pueden ayudar a validar la mayoría de estos casos como [rc](https://www.npmjs.com/package/rc), [nconf](https://www.npmjs.com/package/nconf), [config](https://www.npmjs.com/package/config), y [convict](https://www.npmjs.com/package/convict) +### `🌟 #new` -**De lo contrario:** No cumplir con ninguno de los requisitos de configuración simplemente frena al equipo de desarrollo o al equipo de devOps. Probablemente ambos +**TL;DR:** Al crear aplicaciones y APIs, utilizar un framwork es obligatorio. Es fácil pasar por alto framworks alternativos o consideraciones importantes y finalmente elegir una opción subóptima. En 2023/2024, creemos que vale la pena considerar estos cuatro framwork: [Nest.js](https://nestjs.com/), [Fastify](https://www.fastify.io/), [express ](https://expressjs.com/) y [Koa](https://koajs.com/). Haga clic en leer más a continuación para conocer los pros y los contras detallados de cada framwork. De manera simplista, creemos que Nest.js es la mejor opción para los equipos que desean utilizar programación orientada a objetos y/o crear aplicaciones a gran escala que no se pueden dividir en componentes _autónomos_ más pequeños. Fastify es nuestra recomendación para aplicaciones con componentes de tamaño razonable (por ejemplo, microservicios) que se basan en mecánicas simples de Node.js. Lea nuestra [guía de consideraciones completas aquí] (./sections/projectstructre/choose-framework.spanish.md). -🔗 [**Leer más: buenas prácticas de configuración**](./sections/projectstructre/configguide.spanish.md) +**De lo contrario:** Debido a la abrumadora cantidad de consideraciones, es fácil tomar decisiones basadas en información parcial y comparar peras con manzanas. Por ejemplo, se cree que Fastify es un servidor web mínimo que debería compararse únicamente con Express. En realidad, es un framwork rico con muchos complementos oficiales que cubren muchas problemáticas. + +🔗 [**Leer más: Eligiendo el framework correcto**](./sections/projectstructre/choose-framework.spanish.md) + +

+ +## ![✔] 1.6. Utiliza TypeScript con moderación y consideración + +### `🌟 #new` + +**TL;DR:** Programar sin seguridad de tipos ya no es una opción; TypeScript es la opción más popular para este objetivo. Úsalo para definir variables y tipos de retorno de funciones. Con eso, también es un arma de doble filo que puede _fomentar_ enormemente la complejidad con sus ~ 50 palabras clave adicionales y características sofisticadas. Considera usarlo con moderación, principalmente con tipos simples, y utiliza funciones avanzadas solo cuando surja una necesidad real. + +**De lo contrario:** [Las investigaciones](https://earlbarr.com/publications/typestudy.pdf) muestran que el uso de TypeScript puede ayudar a detectar aproximadamente un 20% de errores antes. Sin él, la experiencia del desarrollador en el IDE también es intolerable. Por otro lado, el 80% de los otros errores no se descubrieron utilizando tipos. En consecuencia, la sintaxis tipada es valiosa pero limitada. Sólo las pruebas eficientes pueden descubrir todo un espectro de errores, incluidos los relacionados con el tipo. También podría frustrar su propósito: es probable que las características sofisticadas del código aumenten su complejidad, lo que por sí aumenta tanto la cantidad de errores como el tiempo promedio de corrección de los mismos. +🔗 [**Leer más: Consideraciones sobre TypeScript**](./sections/projectstructre/typescript-considerations.spanish.md)


@@ -112,62 +334,65 @@ Lee en un idioma diferente: [![CN](/assets/flags/CN.png)**CN**](/README.chinese. # `2. Prácticas en manejo de errores` -## ![✔] 2.1 Usa Async-Await o promesas para manejo de errores asíncronos +## ![✔] 2.1 Usa Async-Await o promesas para el manejo de errores asíncronos -**TL;DR:** El manejo de errores asíncronos en el estilo de callback es probablemente la manera más rápida de ir al infierno (a.k.a, pyramid of doom o pirámide de la perdición). El mejor regalo que le puedes dar a tu código es utilizar una biblioteca de promesas seria o async-await que proporciona una sintaxis de código muy compacta y similar al try-catch +**TL;DR:** El manejo de errores asíncronos en el estilo de callback es probablemente la manera más rápida de ir al infierno (a.k.a, pyramid of doom o pirámide de la perdición). El mejor regalo que le puedes dar a tu código es Promise con async-await que proporciona una sintaxis de código más compacta y similar al try-catch -**De lo contrario:** El estilo de callback de Node.JS, function (err, response), es una forma prometedora de código no mantenible debido a la combinación de manejo de errores con código normal, anidación excesiva y patrones de codificación incómodos +**De lo contrario:** El estilo de callback de Node.JS, function (err, response), es una forma prometedora de hacer código no mantenible debido a la combinación de manejo de errores con código normal, anidación excesiva y patrones de codificación incómodos 🔗 [**Leer más: evitar callbacks**](./sections/errorhandling/asyncerrorhandling.spanish.md)

+## ![✔] 2.2 Extiende el objeto Error nativo -## ![✔] 2.2 Usa solo el objeto Error nativo +### `📝 #updated` -**TL;DR:** Muchos arrojan errores como una cadena o como un tipo personalizado; esto complica la lógica de manejo de errores y la interoperatividad entre módulos. Ya sea que rechace una promesa, genere una excepción o emita un error, usar solo el objeto de Error nativo (o un objecto que herede del objeto Error nativo) aumentará la uniformidad y evitará la pérdida de información. Existe la regla `no-throw-literal` de ESLint que revisa esto (aunque tiene unas [limitaciones](http://eslint.org/docs/rules/no-throw-literal) que pueden ser solucionadas al usar TypeScript y configurando la regla `eslint/no-throw-literal`). +**TL;DR:** Varias bibliotecas arrojan errores como una cadena de caracteres o como un tipo personalizado; esto complica la lógica de manejo de errores y la interoperatividad entre módulos. En su lugar, crea un objeto/clase de error de aplicación que extienda el objeto Error y utilízalo siempre que rechaces, arrojes o emitas un error. El error de la aplicación debería agregar propiedades útiles como el nombre/código del error y isCatastrophic. Al hacerlo, todos los errores tendrán una estructura unificada y permitirán un mejor manejo de errores. Existe la regla `no-throw-literal` de ESLint que chequea esto (aunque tiene unas [limitaciones](http://eslint.org/docs/rules/no-throw-literal) que pueden ser solucionadas al usar TypeScript y configurando la regla `@typescript-eslint/no-throw-literal`). -**De lo contrario:** Al invocar algún componente, no estar seguro de qué tipo de errores son retornados, hace que sea mucho más difícil manejar los errores de forma adecuada. Peor aún, el uso de tipos personalizados para describir los errores puede conducir a la pérdida de información de error crítico como el seguimiento de la pila. +**De lo contrario:** Cuando invoques algún compontente, al no estar seguro de qué tipo de errores son retornados, será mucho más difícil manejar los errores de forma adecuada. Peor aún, el uso de tipos personalizados para describir los errores puede conducir a la pérdida de información de crítica de los errores como el seguimiento de la pila. 🔗 [**Leer más: utilizando el objeto de Error incorporado**](./sections/errorhandling/useonlythebuiltinerror.spanish.md)

-## ![✔] 2.3 Distinguir errores operacionales contra errores del programador +## ![✔] 2.3 Distingue errores catastróficos de errores operacionales -**TL;DR:** Los errores operacionales (por ejemplo, el API recibió una entrada no válida) se refieren a casos conocidos en los que el impacto del error se entiende completamente y se pueden manejar con cuidado. Por otro lado, el error del programador (por ejemplo, tratar de leer la variable no definida) se refiere a fallas desconocidas del código que ordenan reiniciar correctamente la aplicación. +### `📝 #updated` -**De lo contrario:** Siempre puedes reiniciar la aplicación cuando aparece un error, pero ¿Por qué dejar ~5000 usuarios en línea abajo debido a un error operacional menor, previsto? lo contrario tampoco es ideal: Mantener la aplicación activa cuando se produce un problema desconocido (error del programador) puede provocar un comportamiento imprevisto. La diferenciación de los dos permite actuar con tacto y aplicar un enfoque equilibrado basado en el contexto dado. +**TL;DR:** Los errores operacionales (por ejemplo, el API recibió una entrada inválida) se refieren a casos conocidos en los que el impacto del error se entiende completamente y se pueden manejar con cuidado. Por otro lado, los errores catastróficos (también conocidos como errores del programador) se refiere a fallas desconocidas del código que obliga a reiniciar correctamente la aplicación. + +**De lo contrario:** Siempre puedes reiniciar la aplicación cuando aparece un error, pero ¿por qué dejar sin servicio ~5000 usuarios en línea debido a un error previsto, menor y operacional? Lo contrario tampoco es ideal: Mantener la aplicación activa cuando se produce un problema desconocido (error del programador) puede provocar un comportamiento impredecible. Diferenciar los dos permite actuar con tacto y aplicando un enfoque equilibrado basado en el contexto dado. 🔗 [**Leer más: error operacional vs programador**](./sections/errorhandling/operationalvsprogrammererror.spanish.md)

-## ![✔] 2.4 Manejar los errores centralmente, no dentro de un middleware Express +## ![✔] 2.4 Maneja los errores centralmente, no dentro de un middleware -**TL;DR:** La lógica de manejo de errores, como un correo al administrador y registro de logs, debe encapsularse en un objeto dedicado y centralizado al que todos los end-points (por ejemplo, Express middleware, cron jobs, unit-testing) llamen cuando se produce un error. +**TL;DR:** La lógica de manejo de errores como el registro en logs, dicidir cuando fallar y las métricas de monitoreo, deben encapsularse en un objeto dedicado y centralizado al que todos los puntos de entrada (por ejemplo, API, trabajos cron, trabajos programados) puedan llamar cuando se presente un error. -**De lo contrario:** No manejar los errores dentro de un solo lugar dará lugar a la duplicación del código y, probablemente, a los errores que se manejan de forma incorrecta +**De lo contrario:** No manejar los errores dentro de un solo lugar dará lugar a duplicación de código y, probablemente, a manejo inapropiado de errores. 🔗 [**Leer más: manejo de errores en un lugar centralizado**](./sections/errorhandling/centralizedhandling.spanish.md)

-## ![✔] 2.5 Errores del API Document con Swagger o GraphQL +## ![✔] 2.5 Documenta errores del API con OpenAPI o GraphQL -**TL;DR:** Deja que los clientes de tu API sepan qué errores podrían presentarse como respuesta, para que puedan manejarlos cuidadosamente sin fallar. Para API's RESTful esto se hace generalmente con frameworks de documentación REST API como Swagger. Si estás utilizando GraphQL, también puedes utilizar tus esquemas y comentarios. +**TL;DR:** Deja que los clientes de tu API sepan qué errores podrían presentarse como respuesta, para que puedan manejarlos cuidadosamente sin fallar. Para API's RESTful esto se hace generalmente con frameworks de documentación REST API como OpenAPI. Si estás utilizando GraphQL, también puedes utilizar tus esquemas y comentarios. -**De lo contrario:** Un cliente del API podría decidir bloquearse y reiniciarse solo porque recibió un error que no pudo entender. Nota: la persona que llama de su API puede ser tu (muy típico en un entorno de microservicios). +**De lo contrario:** Un cliente de la API podría decidir bloquearse y reiniciarse solo porque recibió un error que no pudo entender. Nota: la persona que llama a tu API puedes ser tu (muy típico en un entorno de microservicios). 🔗 [**Leer más: documentación de errores en Swagger o GraphQL**](./sections/errorhandling/documentingusingswagger.spanish.md)

-## ![✔] 2.6 Cerrar el proceso elegantemente cuando un extraño llega +## ![✔] 2.6 Cierra el proceso elegantemente cuando un extraño llega a la ciudad -**TL; DR:** Cuando se produce un error desconocido (un error del desarrollador, consulta el número de práctica recomendada número 2.3): existe incertidumbre acerca del estado de la aplicación. Una práctica común sugiere reiniciar el proceso cuidadosamente usando una herramienta de gestión de procesos como [Forever](https://www.npmjs.com/package/forever) y [PM2](https://pm2.keymetrics.io/). +**TL; DR:** Cuando se produce un error desconocido (un error catastrófico, consulta la práctica 2.3): existe incertidumbre acerca del estado de salud de la aplicación. En este caso, no hay otra opción que hacer observable el error, cerrar las conexiones y terminar el proceso. Cualquier framework de ejecución confiable, como servicios Dockerizados o soluciones en la nube sin servidor, se encargarán de reiniciar -**De lo contrario:** Cuando se detecta una excepción desconocida, algunos objetos pueden estar en un estado defectuoso (por ejemplo, un emisor de eventos que se usa globalmente y que ya no se activan debido a fallas internas) y todas las solicitudes futuras pueden fallar o comportarse de manera loca. +**De lo contrario:** Cuando se detecta una excepción desconocida, algunos objetos pueden quedar en un estado defectuoso (por ejemplo, un emisor de eventos que se usa globalmente y que no envía más eventos debido a fallas internas) haciendo que las solicitudes futuras puedan fallar o comportarse de manera extraña. 🔗 [**Leer más: cerrar el proceso**](./sections/errorhandling/shuttingtheprocess.spanish.md) @@ -175,37 +400,43 @@ Lee en un idioma diferente: [![CN](/assets/flags/CN.png)**CN**](/README.chinese. ## ![✔] 2.7 Usa un logger maduro para aumentar la visibilidad de los errores -**TL;DR:** Un conjunto de herramientas de registro maduras como [Pino](https://github.com/pinojs/pino) o [Log4js](https:www.npmjs.com/package/log4js) acelerará el descubrimiento y la comprensión de errores. Así que olvídate de console.log. +### `📝 #updated` + +**TL;DR:** Una herramienta de logueo robusta como [Pino](https://github.com/pinojs/pino) o [Winston](https://github.com/winstonjs/winston) aumentan la visibilidad de los errores utilizando funcionalidades como niveles de log, visualización coloreada y más. Console.log carece de estas características y debe evitarse. Los mejores logger permiten adjuntar propiedades útiles personalizadas en los logs con una penalización mínima de performance en la serialización. Los desarrolladores deben escribir los logs a `stdout` y dejar que la infraestructura realice la transmisión al agregador de logs apropiado. -**De lo contrario:** Navegando a través de console.logs o manualmente a través de un archivo de texto desordenado sin herramientas de consulta o un visor de registro decente puede mantenerte ocupado en el trabajo hasta tarde +**De lo contrario:** Navegando a través de console.logs o manualmente a través de un archivo de texto desordenado sin herramientas de consulta o un visor de logs decente puede mantenerte ocupado hasta tarde en el trabajo. -🔗 [**Leer más: utilizando un registrador maduro**](./sections/errorhandling/usematurelogger.spanish.md) +🔗 [**Leer más: utilizando un logger maduro**](./sections/errorhandling/usematurelogger.spanish.md)

-## ![✔] 2.8 Flujos de errores de prueba usando su framework de prueba favorito +## ![✔] 2.8 Prueba los flujos de errores usando tu framework de prueba favorito + +### `📝 #updated` -**TL;DR:** Ya sea que se trate de un profesional de QA automatizado o de una prueba de desarrollador manual: asegúrate de que tu código no solo satisfaga un escenario positivo sino que también maneje y devuelva los errores correctos. Frameworks de prueba como Mocha & Chai pueden manejar esto fácilmente (vea ejemplos de código dentro del "Gist emergente"). +**TL;DR:** Ya sea que se trate de una prueba automatizada de QA profesional o de una de desarrollador manual: asegúrate de que tu código no solo satisfaga un escenario positivo sino que también maneje y devuelva los errores correctos. Además de esto, simule flujos de errores más profundos, como excepciones no capturadas, y asegúrese de que el controlador de errores los trate adecuadamente (vea ejemplos de código en la sección "leer más"). -**De lo contrario:** Sin pruebas, ya sea automática o manualmente, no puedes confiar en su código para devolver los errores correctos. Sin errores significativos, no hay manejo de errores. +**De lo contrario:** Sin pruebas, ya sean automáticas o manuales, no puedes confiar en tu código para devolver los errores correctos. Sin errores útiles, no hay manejo de errores. 🔗 [**Leer más: probar los flujos de error**](./sections/errorhandling/testingerrorflows.spanish.md)

-## ![✔] 2.9 Descubre errores y tiempo de inactividad usando productos APM +## ![✔] 2.9 Descubre errores y tiempo de inactividad usando productos de APM -**TL;DR:** Los productos de monitoreo y rendimiento (a.k.a APM) miden de forma proactiva tu base de código o API para auto-mágicamente resaltar errores, bloqueos y ralentizar partes que no te das cuenta. +**TL;DR:** Los productos de monitoreo y rendimiento (a.k.a APM) miden de forma proactiva tu base de código o API para auto-mágicamente resaltar errores, caídas y partes lentas que no has notado. -**De lo contrario:** Es posible que dediques un gran esfuerzo a medir el rendimiento y los tiempos de inactividad de la API, probablemente nunca sabrás cuáles son las piezas de código más lentas en el escenario del mundo real y cómo afectan estas a la experiencia del usuario. +**De lo contrario:** Es posible que dediques un gran esfuerzo en medir el rendimiento y los tiempos de caída de la API y probablemente nunca sabrás cuáles son las piezas de código más lentas en el escenario del mundo real y cómo afectan estas a la experiencia del usuario. 🔗 [**Leer más: utilizando productos APM**](./sections/errorhandling/apmproducts.spanish.md)

-## ![✔] 2.10 Captura rechazos de promesas no controladas +## ![✔] 2.10 Captura los rechazos de promesas no controladas -**TL;DR:** Cualquier excepción lanzada dentro de una promesa será tragada y descartada a menos que un desarrollador no se olvide de manejarla de manera explícita. ¡Incluso si su código está suscrito a `process.uncaughtException`! Supera esto registrándose en el proceso del evento `process.unhandledRejection`. +### `📝 #updated` + +**TL;DR:** Cualquier excepción lanzada dentro de una promesa será tragada y descartada a menos que un desarrollador no se olvide de manejarla de manera explícita. ¡Incluso si su código está suscrito a `process.uncaughtException`! Supera esto registrándote al evento `process.unhandledRejection`. **De lo contrario:** Tus errores serán tragados y no dejarán rastros. Nada de que preocuparse @@ -213,17 +444,19 @@ Lee en un idioma diferente: [![CN](/assets/flags/CN.png)**CN**](/README.chinese.

-## ![✔] 2.11 Falla rápidamente, valida argumentos usando una biblioteca dedicada +## ![✔] 2.11 Falla rápidamente, valida los argumentos usando una biblioteca dedicada -**TL; DR:** Valida los datos de entrada en la API para evitar bugs molestos que son difíciles de rastrear mas adelante. La validación de código suele ser tediosa amenos que tengas ona librería que pueda ayudar como [ajv](https://www.npmjs.com/package/ajv) y [Joi](https://www.npmjs.com/package/joi). +**TL; DR:** Valida los datos de entrada a la API para evitar bugs molestos que son difíciles de rastrear luego. El código de validación suele ser tediosa amenos que utilices una biblioteca de validación moderna como [ajv](https://www.npmjs.com/package/ajv), [zod](https://github.com/colinhacks/zod) o [typebox](https://github.com/sinclairzx81/typebox) -**De lo contrario:** Considera esto: tu función espera un argumento numérico "Descuento" que la persona que llama la función olvida pasar, más adelante su código comprueba si Descuento!= 0 (cantidad de descuento permitido es mayor que cero), entonces permitirás el usuario que disfrute de un descuento. Dios mío, qué desagradable error. ¿Puedes verlo? +**De lo contrario:** Considera esto: tu función espera un argumento numérico "Descuento" que el invocador de la función olvida pasar, más adelante su código chequea si Descuento!= 0 (cantidad de descuento permitido es mayor que cero), entonces permitirá que el usuario que disfrute de un descuento. Dios mío, qué desagradable error. ¿Puedes verlo? 🔗 [**Leer más: falla rápidamente**](./sections/errorhandling/failfast.spanish.md)

-## ![✔] 2.12 Siempre resuelve las promesas antes de retornarlas para evitar stacktrace parcial +## ![✔] 2.12 Siempre resuelve las promesas antes de retornarlas para evitar un stacktrace parcial + +### `🌟 #new` **TL;DR:** Siempre utiliza `return await` cuando regreses una promesa para tener un error stacktrace completo. Si la función regresa una promesa, esa función debe ser declarada como `async` y explícitamente esperar (`await`) la promesa antes de retornarla. @@ -231,30 +464,43 @@ Lee en un idioma diferente: [![CN](/assets/flags/CN.png)**CN**](/README.chinese. 🔗 [**Leer más: retornar promesas**](./sections/errorhandling/returningpromises.spanish.md) +

+ +## ![✔] 2.13 Subscribete al evento 'error' de los emisores de eventos + +## `🌟 #new` + +**TL;DR:** A diferencia de las funciones típicas, una cláusula try-catch no obtendrá errores que se originen en emisores de eventos (`Event Emitters`) ni en nada heredado de ellos (por ejemplo, `streams`). En lugar de try-catch, suscríbase al evento de 'error' de un emisor de eventos para que su código pueda manejar el error en contexto. Cuando se trata de [EventTargets](https://nodejs.org/api/events.html#eventtarget-and-event-api) (la versión web estándar de `Event Emitters``) no hay ningún evento de "error" y todos los errores terminan en el evento global Process.on('error) - en este caso, al menos asegúrese de que el proceso falle o no según el contexto deseado. Además, tenga en cuenta que los errores que se originan en los controladores de eventos _asincrónicos_ no se detectan a menos que el emisor del evento se inicialice con {captureRejections: true}. + +**Otherwise:** Los emisores de eventos se utilizan comúnmente para funciones de aplicaciones clave y globales, como conexiones de bases de datos o colas de mensajes. Cuando este tipo de objetos cruciales arrojan un error, en el mejor de los casos el proceso fallará debido a una excepción no controlada. Peor aún, permanecerá vivo como un zombi mientras una función clave esté desactivada. +


⬆ Volver arriba

# `3. Prácticas de estilo de código` -## ![✔] 3.1 Utilizar ESLint +## ![✔] 3.1 Usa ESLint -**TL;DR:** [ESLint](https://eslint.org) es el estándar para verificar posibles errores de código y corregir el estilo del código, no solo para identificar problemas básicos, sino también para detectar anti-patrones de código graves, como los desarrolladores que arrojan errores sin clasificación. Aunque ESLint puede corregir automáticamente los estilos de código, otras herramientas como [prettier](https://www.npmjs.com/package/prettier) y [beautify](https://www.npmjs.com/package/js-beautify) son más potentes para formatear la solución y funcionan en conjunto con ESLint +**TL;DR:** [ESLint](https://eslint.org) es el estándar de-facto para detectar errores de código y corregir estilo, no solo para identificar problemas básicos, sino también para detectar anti-patrones de código graves, como los desarrolladores lanzando errores sin clasificación. Aunque ESLint puede corregir automáticamente los estilos de código, otras herramientas como [prettier](https://www.npmjs.com/package/prettier) son más potentes para formatear la solución y funcionan en conjunto con ESLint- -**De lo contrario:** Los desarrolladores podrían desperdiciar demasiado tiempo centrándose demasiado en el corregir los espacios y el ancho de línea del código +**De lo contrario:** Los desarrolladores se centrarán en los espacios y el ancho de línea del código y desperdicierán tiempo sobrepensando el estilo de código del proyecto. 🔗 [**Leer más: Usando ESLint y Prettier**](./sections/codestylepractices/eslint_prettier.spanish.md)

-## ![✔] 3.2 Paquetes específicos para Node.js +## ![✔] 3.2 Utiliza las extensiones de eslint para para Node.js + +### `📝 #updated` + +**TL;DR:** Además de las reglas estándar de ESLint que cubre a JavaScript vainilla, es bueno agregar complementos específicos como [eslint-plugin-n](https://www.npmjs.com/package/eslint-plugin-n), [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) y [eslint-plugin-node-security](https://www.npmjs.com/package/eslint-plugin-security), [eslint-plugin-require](https://www.npmjs.com/package/eslint-plugin-require), [/eslint-plugin-jest](https://www.npmjs.com/package/eslint-plugin-jest) y otras reglas útiles -**TL;DR:** Además de las reglas estándar de ESLint que cubre a JavaScript vainilla, es bueno agregar complementos específicos de Node.js como [eslint-plugin-node](https://www.npmjs.com/package/eslint-plugin-node), [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) y [eslint-plugin-node-security](https://www.npmjs.com/package/eslint-plugin-security) +**De lo contrario:** Muchos patrones defectuosos de Node.js pueden escaparse. Por ejemplo, los desarrolladores pueden requerir archivos (variableAsPath) con una variable dada como ruta que permita a los atacantes ejecutar cualquier script JS. Los linters de Node.js pueden detectar tales patrones y avisar tempranamente -**De lo contrario:** Muchos patrones defectuosos de Node.js pueden no ser detectados. Por ejemplo, los desarrolladores pueden requerir archivos (variableAsPath) con una variable dada como ruta que permita a los atacantes ejecutar cualquier script JS. Los linters de Node.js pueden detectar tales patrones y ayudar a que esto no ocurra

-## ![✔] 3.3 Empieza con las llaves en la misma línea en el código +## ![✔] 3.3 Inicia las llaves de un bloque de código en la misma línea **TL;DR:** Las llaves de apertura de un bloque de código deben estar en la misma línea que la declaración de apertura @@ -279,13 +525,13 @@ function someFunction()

-## ![✔] 3.4 Separa tus declaraciones correctamente +## ![✔] 3.4 Separa tus sentencias correctamente -No importa si usas punto y coma o no para separar tus declaraciones, conocer las trampas comunes de los saltos de línea inadecuados o la inserción automática de punto y coma, te ayudará a eliminar los errores de sintaxis habituales. +No importa si usas punto y coma o no para separar tus sentencias, conocer las trampas comunes de los saltos de línea inadecuados o la inserción automática de punto y coma, te ayudará a eliminar los errores de sintaxis habituales. -**TL;DR:** Utiliza ESLint para obtener conciencia sobre las preocupaciones de separación. [Prettier](https://prettier.io/) o [Standardjs](https://standardjs.com/) puede resolver automáticamente estos inconvenientes. +**TL;DR:** Utiliza ESLint para ganar conciencia sobre la separación de intereses. [Prettier](https://prettier.io/) o [Standardjs](https://standardjs.com/) pueden resolver automáticamente estos inconvenientes. -**De lo contrario:** Como se vio en la sección anterior, el intérprete de JavaScript agrega automáticamente un punto y coma al final de una declaración si no hay una, o considera que una declaración no terminó donde debería, lo que podría generar algunos resultados no deseados. Puedes usar asignaciones y evitar el uso de expresiones de funciones invocadas inmediatas para evitar la mayoría de los errores inesperados. +**De lo contrario:** Como se vio en la sección anterior, el intérprete de JavaScript agrega automáticamente un punto y coma al final de una sentencia si no hay una, o considera que una declaración no terminó donde debería, lo que podría generar resultados inesperados. Puedes usar asignaciones y evitar el uso de expresiones de funciones invocadas inmediatamente para evitar la mayoría de los errores inesperados. ### Ejemplo de código @@ -315,7 +561,7 @@ const count = 2 // intenta ejecutar 2(), pero 2 no es una función (function doSomething() { // do something amazing }()) -// Pon un punto y coma antes de la función invocada inmediata, después de la definición constante, guarda el valor de retorno de la función anónima en una variable o evite los IIFE por completo +// Pon un punto y coma antes de la función invocada inmediatamente y después de la definición de una constante; guarda el valor de retorno de la función anónima en una variable o evita los IIFE por completo ``` 🔗 [**Leer más:** "Semi ESLint rule"](https://eslint.org/docs/rules/semi) @@ -323,41 +569,60 @@ const count = 2 // intenta ejecutar 2(), pero 2 no es una función

-## ![✔] 3.5 Pon nombre a tus funciones +## ![✔] 3.5 Nombra a tus funciones -**TL;DR:** Nombra todas las funciones, incluidos los cierres y las devoluciones de llamada. Evita funciones anónimas. Esto es especialmente útil cuando se perfila una aplicación de Node. Nombrar todas las funciones le permitirá comprender fácilmente lo que está viendo al revisar un registro de memoria +**TL;DR:** Nombra todas las funciones, incluidos los closures y callbacks. Evita las funciones anónimas. Esto es especialmente útil cuando se perfila una aplicación Node. Nombrar todas las funciones le permitirá comprender fácilmente lo que está viendo al revisar una instantanea de la memoria. -**De lo contrario:** La depuración de problemas de producción utilizando un registro de memoria (log) puede ser un desafío ya que observa un número significativo de funciones anónimas +**De lo contrario:** La depuración de problemas de producción utilizando un volcado de memoria (instantenea de memoria) puede ser un desafío al observar un consumo significativo de memoria por parte de funciones anónimas.

-## ![✔] 3.6 Usa convenciones de nomenclatura para variables, constantes, funciones y clases. +## ![✔] 3.6 Usa convenciones de nombre para variables, constantes, funciones y clases -**TL;DR:** Utiliza **_lowerCamelCase_** al nombrar constantes, variables y funciones y utiliza **_UpperCamelCase_** (la primera en mayúscula también) cuando nombres clases. Esto lo ayudará a distinguir fácilmente entre variables / funciones simples y clases que requieren instanciación. Use nombres descriptivos, pero trate de mantenerlos cortos +**TL;DR:** Usa **_lowerCamelCase_** al nombrar constantes, variables y funciones y utiliza **_UpperCamelCase_** (la primera en mayúscula también) cuando nombres clases y **_UPPER_SNAKE_CASE_** al nombrar variables globales o estáticas. Esto lo ayudará a distinguir fácilmente entre variables, funciones, clases que requieren instanciación y variables declarardas en el scope global del módulo. Usa nombres descriptivos, pero trata de mantenerlos cortos. -**De lo contrario:** Javascript es el único lenguaje en el mundo que permite invocar a un constructor ("Clase") directamente sin instanciarlo primero. En consecuencia, las clases y los constructores de funciones se diferencian comenzando con UpperCamelCase +**De lo contrario:** Javascript es el único lenguaje en el mundo que permite invocar a un constructor ("Clase") directamente sin instanciarlo primero. En consecuencia, las clases y constructores de funciones se diferencian comenzando con UpperCamelCase ### 3.6 Ejemplo de código ```javascript -// para una clase utilizamos UpperCamelCase -class SomeClassExample {} - -// para las constantes utilizamos la palabra reservada const y lowerCamelCase -const config = { - key: 'value' +// para nombres de variables globales usamos el keyword const/let y UPPER_SNAKE_CASE +let MUTABLE_GLOBAL = "mutable value"; +const GLOBAL_CONSTANT = "immutable value"; +const CONFIG = { + key: "value", }; -// para las variables y funciones utilizamos lowerCamelCase -let someVariableExample = 'value'; -function doSomething() {} +// ejemplos de la convención de UPPER_SNAKE_CASE en el ecosistema nodejs/javascript + +// en el moóulo Math.PI de JavaScript +const PI = 3.141592653589793; + +// https://github.com/nodejs/node/blob/b9f36062d7b5c5039498e98d2f2c180dca2a7065/lib/internal/http2/core.js#L303 +// en el modulo http2 de NodeJS +const HTTP_STATUS_OK = 200; +const HTTP_STATUS_CREATED = 201; + +// para nombre de clases usamos UpperCamelCase +class SomeClassExample { + // para propiedades estáticas de clase usamos UPPER_SNAKE_CASE + static STATIC_PROPERTY = "value"; +} + +// para funciones usamos lowerCamelCase +function doSomething() { + // for scoped variable names we use the const/let keyword and lowerCamelCase + // para variables dentro de un scope usamos utilizamos la keyword const/let y lowerCamelCase + const someConstExample = "immutable value"; + let someMutableExample = "mutable value"; +} ```

-## ![✔] 3.7 Escoge const antes que let. No uses var +## ![✔] 3.7 Prefiere const antes que let. No uses var -**TL;DR:** Usar `const` significa que una vez que se asigna una variable, no se puede reasignar. Prefiriendo `const` te ayudará a no sentirte tentado a usar la misma variable para diferentes usos y a aclarar tu código. Si una variable necesita ser reasignada, en un bucle for, por ejemplo, usa `let` para declararlo. Otro aspecto importante de `let`es que una variable declarada usando solo está disponible en el ámbito del bloque en el que se definió. `var` tiene ámbito de función, no ámbito de bloque, y [no debería ser usada en ES6](https://hackernoon.com/why-you-shouldnt-use-var-anymore-f109a58b9b70) ahora que tienes `const` y `let` a tu disposición +**TL;DR:** Usar `const` significa que una vez que se asigna una variable, no se puede reasignar. Prefiriendo `const` te ayudará a no sentirte tentado a usar la misma variable para diferentes usos y hace tu código más claro. Si una variable necesita ser reasignada, por ejemplo en un bucle for, usa `let` para declararla. Otro aspecto importante es que una variable declarada con `let` solo está disponible en el ámbito del bloque en la que se definió. `var` tiene ámbito de función, no de bloque, y [no debería ser usada en ES6](https://hackernoon.com/why-you-shouldnt-use-var-anymore-f109a58b9b70) ahora que tienes `const` y `let` a tu disposición. **De lo contrario:** La depuración se vuelve mucho más engorrosa cuando se sigue una variable que cambia con frecuencia @@ -367,86 +632,109 @@ function doSomething() {} ## ![✔] 3.8 Importa los módulos primero, no dentro de funciones -**TL;DR:** Importa los módulos al comienzo de cada archivo, antes y fuera de cualquier función. Esta práctica recomendada simple no solo lo ayudará a identificar fácil y rápidamente las dependencias de un archivo en la parte superior, sino que también evitará un par de posibles problemas. +**TL;DR:** Importa los módulos al comienzo de cada archivo, antes y fuera de cualquier función. Esta simple práctica recomendada no solo te ayudará a identificar fácil y rápidamente las dependencias de un archivo en la parte superior, sino que también evitará un par de posibles problemas. -**De lo contrario:** Los requisitos se ejecutan de manera síncrona por Node.js. Si se los llama desde una función, puede bloquear el manejo de otras solicitudes en un momento más crítico. Además, si un módulo requerido o cualquiera de sus propias dependencias arroja un error y bloquea el servidor, es mejor averiguarlo lo antes posible, lo que podría no ser el caso si ese módulo se requiere desde una función +**De lo contrario:** Los requisitos se ejecutan de manera síncrona por Node.js. Si se los llama desde una función, puede bloquear el manejo de otras solicitudes en un momentos críticos. Además, si un módulo requerido o cualquiera de sus propias dependencias arroja un error y tirar el servidor, es mejor averiguarlo lo antes posible, lo que podría no ser así si el módulo se requiere desde una función.

-## ![✔] 3.9 Importa los módulos por carpetas y no por archivos directamente +## ![✔] 3.9 Establece un punto de entrada explícito a un módulo/carpeta -**TL;DR:** Al desarrollar un módulo / biblioteca en una carpeta, coloca un archivo index.js que exponga los componentes internos del módulo para que todos los consumidores lo atraviesen. Esto sirve como una 'interfaz' para tu módulo y facilita los cambios futuros sin romper el contrato +### `📝 #updated` -**De lo contrario:** Cambiar la estructura interna de los archivos o la firma puede romper la interfaz con los clientes +**TL;DR:** Al desarrollar un módulo/biblioteca, establece un archivo raíz explícito que exporte el código público e interesante. Disuade al código del cliente de importar archivos profundos y de familiarizarse con la estructura interna. Con commonjs (require), esto se puede hacer con un archivo index.js en la raíz de la carpeta o en el campo package.json.main. Con ESM (import), si existe un paquete.json en la raíz, el campo "exportaciones" permite especificar el archivo raíz del módulo. Si no existe ningún paquete.json, puedes colocar un archivo index.js en la raíz que reexporte toda la funcionalidad pública. -### 3.9 Ejemplo de código +**De lo contrario:** Tener un archivo raíz explícito actúa como una "interfaz" pública que encapsula lo interno, dirige al invocador al código público y facilita cambios futuros sin romper el contrato. + +### 3.9 Ejemplo de código - evita el acoplamiento del cliente con la estructura del módulo ```javascript -// Haz esto -module.exports.SMSProvider = require('./SMSProvider'); -module.exports.SMSNumberResolver = require('./SMSNumberResolver'); +// Evita: el client tiene mucha familiaridad con lo interno -// Evita esto -module.exports.SMSProvider = require('./SMSProvider/SMSProvider.js'); -module.exports.SMSNumberResolver = require('./SMSNumberResolver/SMSNumberResolver.js'); +// Código cliente +const SMSWithMedia = require("./SMSProvider/providers/media/media-provider.js"); + +// Mejor: exporta explícitamente la funciones públicas + +//index.js, código del módulo +module.exports.SMSWithMedia = require("./SMSProvider/providers/media/media-provider.js"); + +// Client code +const { SMSWithMedia } = require("./SMSProvider"); ```

## ![✔] 3.10 Usa el operador `===` -**TL;DR:** Prioriza el operador de igualdad estricto `===` sobre el operador de igualdad abstracto `==`. `==` comparará dos variables después de convertirlas a un tipo común. No hay conversión de tipo en `===`, y ambas variables deben ser del mismo tipo para ser iguales +**TL;DR:** Prefiere el operador de igualdad estricto `===` por sobre el operador de igualdad abstracto `==`. `==` comparará dos variables después de convertirlas a un tipo común. Con `===` no hay conversión de tipo, y ambas variables deben ser del mismo tipo para ser iguales **De lo contrario:** Variables que no son iguales pueden devolver `true` con el operador `==` ### 3.10 Ejemplo 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 ``` -Todo lo de encima hubiera devuelto `false` si se hubiera usado `===` +Todas las sentencias de arriba retornarían `false` si se hubiera usado `===`.

## ![✔] 3.11 Usa Async Await, evita callbacks -**TL;DR:** Node 8 LTS ahora tiene soporte completo para Async-await. Esta es una nueva forma de lidiar con el código asíncrono que reemplaza las devoluciones de llamada y las promesas. Async-await no bloquea y hace que el código asíncrono se vea síncrono. El mejor regalo que puede dar a su código es usar async-await, que proporciona una sintaxis de código mucho más compacta y familiar a try-catch. +**TL;DR:** Async-await es la forma más sencilla de expresar un flujo asincrónico, ya que hace que el código asincrónico parezca sincrónico. Async-await también dará como resultado un código mucho más compacto y soporte para try-catch. Esta técnica ahora reemplaza los callbacks y las promesas en la _mayoría_ de los casos. Usarlo en tu código es probablemente el mejor regalo que le puedas hacer al lector del código. -**De lo contrario:** El manejo de errores asíncronos en el estilo de callback es probablemente la forma más rápida de ir al infierno: este estilo obliga a verificar los errores por todas partes, lidiar con la incómoda anidación de código y hace que sea difícil razonar sobre el flujo de código +**De lo contrario:** Manejar errores asíncronos en el estilo de callback es probablemente el camino más rápido al infierno. Ese estilo obliga a verificar los errores por todas partes, lidiar con el anidamiento de código y dificulta razonar sobre el flujo de código. 🔗[**Leer más:** Guide to async await 1.0](https://github.com/yortus/asyncawait)

-## ![✔] 3.12 Usar funciones de flecha (=>) +## ![✔] 3.12 Usa expresiones de función flecha (=>) **TL;DR:** Aunque se recomienda usar async-await y evitar parámetros de función cuando se trata de API más antiguas que aceptan promesas o callbacks. Las funciones de flecha hacen que la estructura del código sea más compacta y mantienen el contexto léxico de la función raíz (i.e. `this`) -**De lo contrario:** El código más largo (en las funciones de ES5) es más propenso a errores y engorroso de leer +**De lo contrario:** El código más largo (en las funciones ES5) es más propenso a errores y engorroso de leer. 🔗 [**Leer más: It’s Time to Embrace Arrow Functions**](https://medium.com/javascript-scene/familiarity-bias-is-holding-you-back-its-time-to-embrace-arrow-functions-3d37e1a9bb75) +

+ +## ![✔] 3.13 Evita efectos fuera de las funciones + +### `🌟 #new` + +**TL;DR:** Evita colocar código con efectos como llamadas de red o de base de datos fuera de las funciones. Dicho código se ejecutará inmediatamente cuando otro archivo requiera el archivo. Este código "flotante" podría ejecutarse cuando el sistema subyacente aún no esté listo. También viene con una penalización de rendimiento incluso cuando las funciones de ese módulo finalmente no se utilicen en tiempo de ejecución. Por último, mockear estas llamadas de red/DB para realizar pruebas es más difícil afuera de las funciones. En su lugar, coloque este código dentro de funciones que deban llamarse explícitamente. Si hay código de base de datos/red que deba ejecutarse justo cuando se carga el módulo, considera usar un factory o revelar los patrones del módulo. + +**De lo contrario:** Un típico framework web establece un controlador de errores, variables de entorno y monitoreo. Cuando se realizan llamadas a la base de datos/red antes de que se inicialice el framework web, estas no serán monitoreadas o fallarán debido a la falta de datos de configuración. +


⬆ Volver arriba

# `4. Pruebas y prácticas generales de calidad` +\_Tenemos guías dedicadas a las pruebas, ver más abajo. La lista de mejores prácticas aquí es un breve resumen de estas guías. + +a. [JavaScript testing best practices](https://github.com/goldbergyoni/javascript-testing-best-practices) +b. [Node.js testing - beyond the basics](https://github.com/testjavascript/nodejs-integration-tests-best-practices) +\_ + ## ![✔] 4.1 Por lo menos, escribe las pruebas de la API (componente) -**TL;DR:** La mayoría de los proyectos simplemente no tienen pruebas automatizadas debido a los cortos horarios o, a menudo, el 'proyecto de prueba' se salió de control y fue abandonado. Por esa razón, priorice y comience con las pruebas API, que es la forma más fácil de escribir y proporciona más cobertura que las pruebas unitarias (incluso puede crear pruebas API sin código utilizando herramientas como [Postman](https://www.getpostman.com/). Luego, si tiene más recursos y tiempo, continúe con los tipos de pruebas avanzadas como pruebas unitarias, pruebas de base de datos, pruebas de rendimiento, etc. +**TL;DR:** La mayoría de los proyectos simplemente no tienen pruebas automatizadas debido a los cortos horarios o, a menudo, el 'proyecto de pruebas' se salió de control y fue abandonado. Por esa razón, priorice y comience con las pruebas API, que es la forma más fácil de escribir y proporciona más cobertura que las pruebas unitarias (incluso puede crear pruebas API sin código utilizando herramientas como [Postman](https://www.getpostman.com/). Luego, si tiene más recursos y tiempo, continúe con los tipos de pruebas avanzadas como pruebas unitarias, pruebas de base de datos, pruebas de rendimiento, etc. **De lo contrario:** Puede pasar largos días escribiendo pruebas unitarias para descubrir que solo tiene un 20% de cobertura del sistema @@ -454,35 +742,41 @@ Todo lo de encima hubiera devuelto `false` si se hubiera usado `===` ## ![✔] 4.2 Incluye 3 partes en cada nombre de prueba -**TL;DR:** Haga que la prueba hable a nivel de requisitos para que se explique por sí mismo también a los ingenieros y desarrolladores de control de calidad que no están familiarizados con el código interno. Indique en el nombre de la prueba qué se está probando (unidad bajo prueba), en qué circunstancias y cuál es el resultado esperado +### `🌟 #new` + +**TL;DR:** Haga que las pruebas hablen a nivel de requisitos para que se expliquen por sí mismos también a los ingenieros de QA y desarrolladores que no están familiarizados con el detalle interno del código. Indique en el nombre de la prueba qué se está probando (unidad bajo prueba), en qué circunstancias y cuál es el resultado esperado -**De lo contrario:** Una implementación simplemente falló, una prueba llamada "Agregar producto" falló. ¿Esto te dice exactamente qué está funcionando mal? +**De lo contrario:** Una implementación acaba de fallar y una prueba llamada "Agregar producto" falló. ¿Esto te dice exactamente qué está funcionando mal? 🔗 [**Leer más: Incluye 3 partes en cada nombre de prueba**](./sections/testingandquality/3-parts-in-name.spanish.md)

-## ![✔] 4.3 Pruebas de estructura por el patrón AAA +## ![✔] 4.3 Estructura las pruebas utilizando el patrón AAA -**TL;DR:** Estructura tus pruebas con 3 secciones bien separadas: Organizar, Actuar y Afirmar (AAA - Arrange, Act & Assert). La primera parte incluye la configuración de la prueba, luego la ejecución de la unidad bajo prueba y finalmente la fase de afirmación. Seguir esta estructura garantiza que el lector no gaste CPU cerebral en comprender el plan de prueba +### `🌟 #new` -**De lo contrario:** No solo pasa largas horas diarias entendiendo el código principal, ahora también lo que debería haber sido la parte simple del día (pruebas) ha ejercitado tu cerebro +**TL;DR:** Estructura tus pruebas con 3 secciones bien separadas: Organizar, Actuar y Afirmar (AAA - Arrange, Act & Assert). La primera parte incluye la configuración de la prueba, la segunda la ejecución de la unidad bajo prueba y finalmente la fase de afirmaciones. Seguir esta estructura garantiza que el lector no gaste CPU cerebral en comprender el plan de prueba + +**De lo contrario:** No solo pasas largas horas diarias entendiendo el código principal, ahora también lo que debería haber sido la parte simple del día (pruebas) ejercita tu cerebro 🔗 [**Leer más: Pruebas de estructura por el patrón AAA**](./sections/testingandquality/aaa.spanish.md)

-## ![✔] 4.4 Detecta problemas de código con un linter +## ![✔] 4.4 Asegurate que la versión de Node esté unificada + +### `🌟 #new` -**TL;DR:** Usa un código de interfaz para verificar la calidad básica y detectar anti-patrones temprano. Ejecútala antes de cualquier prueba y agrégalo como un git-hook previo al commit para minimizar el tiempo necesario para revisar y corregir cualquier problema. También verifica la [Sección 3](#3-code-style-practices) sobre las prácticas de estilo de código. +**TL;DR:** Usa herramientas que fomenten o impongan la misma versión de Node.js en diferentes entornos y desarrolladores. Herramientas como [nvm](https://github.com/nvm-sh/nvm) y [Volta](https://volta.sh/) permiten especificar la versión del proyecto en un archivo para que cada miembro del equipo pueda ejecutar un comando único para ajustarse a la versión del proyecto. Opcionalmente, esta definición se puede replicar en CI y en el entorno de ejecución de producción (por ejemplo, copiar el valor especificado en la compilación .Dockerfile y en el archivo de declaración de CI). -**De lo contrario:** Puede dejar pasar algún código anti-patrón y posible código vulnerable a su entorno de producción. +**De lo contrario:** Un desarrollador puede enfrentar o pasar por alto un error porque usa una versión de Node.js diferente a la de sus compañeros de equipo. Peor aún: el entorno de ejecución de producción puede ser diferente al entorno donde se ejecutaron las pruebas.

-## ![✔] 4.5 Evita datos globales, agrega datos personalizados por prueba +## ![✔] 4.5 Evita los estados de prueba (fixtures) y semillas globales, agrega datos por prueba -**TL;DR:** Para evitar el acoplamiento de pruebas y razonar fácilmente sobre el flujo de prueba, cada prueba debe agregar y actuar en su propio conjunto de filas de base de datos. Cada vez que una prueba necesita extraer o asumir la existencia de algunos datos de base de datos, debes agregar explícitamente esos datos y evitar la mutación de cualquier otro registro +**TL;DR:** Para evitar el acoplamiento de pruebas y razonar fácilmente sobre el flujo de prueba, cada prueba debe agregar y actuar en su propio conjunto de registros de base de datos. Cada vez que una prueba necesita extraer o asumir la existencia de algunos datos de base de datos, debes agregar explícitamente esos datos y evitar la mutación de cualquier otro registro. **De lo contrario:** Considera un escenario en el que se cancela la implementación debido a las pruebas fallidas, el equipo ahora pasará un tiempo de investigación precioso que termina en una triste conclusión: el sistema funciona bien, las pruebas sin embargo interfieren entre sí y rompen la construcción @@ -490,83 +784,93 @@ Todo lo de encima hubiera devuelto `false` si se hubiera usado `===`

-## ![✔] 4.6 Inspecciona constantemente las dependencias vulnerables. +## ![✔] 4.6 Etiqueta tus pruebas -**TL;DR:** Incluso las dependencias de mayor reputación como Express tienen vulnerabilidades conocidas. Esto se puede controlar fácilmente utilizando herramientas comunitarias y comerciales como 🔗 [npm audit](https://docs.npmjs.com/cli/audit) y 🔗 [snyk.io](https://snyk.io) que se puede invocar desde su CI en cada compilación +**TL;DR:** Pruebas diferentes deben ejecutarse en diferentes escenarios: "smoke rápido", "sin IO", pruebas que deben ejecutarse cuando un desarrollador guarda o hace commit a un archivo, pruebas completas de punta a punta que generalmente se ejecutan cuando se envía una nueva pull request, etc. Esto se puede lograr etiquetando las pruebas con palabras clave como #cold #api #sanity para que pueda aprovechar su andamiaje de pruebas e invocar el subconjunto deseado. Por ejemplo, así es como invocaría solo al grupo de prueba de sanidad con [Mocha](https://mochajs.org/): mocha --grep 'sanity' -**De lo contrario:** Mantener su código limpio de vulnerabilidades sin herramientas dedicadas requerirá seguir constantemente las publicaciones en línea sobre nuevas amenazas. Bastante tedioso +**De lo contrario:** La ejecución de todas las pruebas, incluidas las pruebas que realizan docenas de consultas DB, cada vez que un desarrollador realiza un pequeño cambio puede ser extremadamente lento y mantiene a los desarrolladores lejos de ejecutar pruebas

-## ![✔] 4.7 Etiqueta tus pruebas +## ![✔] 4.7 Verifica la cobertura de tus pruebas, ayuda a identificar patrones de prueba incorrectos -**TL;DR:** Deben ejecutarse diferentes pruebas en diferentes escenarios: "quick smoke", "IO-less", pruebas que deben ejecutarse cuando un desarrollador guarda o hace commit a un archivo, pruebas completas de extremo a extremo generalmente se ejecutan cuando se envía una nueva solicitud de pull , etc. Esto se puede lograr etiquetando las pruebas con palabras clave como #cold #api #sanity para que pueda aprovechar su arnés de prueba e invocar el subconjunto deseado. Por ejemplo, así es como invocaría solo al grupo de prueba de sanidad con [Mocha](https://mochajs.org/): mocha --grep 'sanity' +**TL;DR:** Herramientas de cobertura de código como [Istanbul](https://github.com/istanbuljs/istanbuljs)/[NYC](https://github.com/istanbuljs/nyc) son excelentes por 3 razones: son gratis (no se requiere ningún esfuerzo para realizar estos informes), ayudan a identificar una disminución en la cobertura de las pruebas y, por último, pero no menos importante, resaltan los desajustes de las pruebas: al mirar los informes de cobertura de códigos de colores puede que veas, por ejemplo, áreas de código que nunca se prueban como cláusulas catch (lo que significa que las pruebas solo invocan las rutas felices y no cómo se comporta la aplicación ante los errores). Configúrelo para generar fallos si la cobertura cae por debajo de un cierto umbral -**De lo contrario:** La ejecución de todas las pruebas, incluidas las pruebas que realizan docenas de consultas DB, cada vez que un desarrollador realiza un pequeño cambio puede ser extremadamente lento y mantiene a los desarrolladores lejos de ejecutar pruebas +**De lo contrario:** No habrá ninguna métrica automatizada que le indique cuándo una gran parte de su código no está cubierto por las pruebas

-## ![✔] 4.8 Verifique su cobertura de prueba, ayuda a identificar patrones de prueba incorrectos +## ![✔] 4.8 Usa un ambiente similar al de producción para pruebas e2e -**TL;DR:** Herramientas de cobertura de código como [Istanbul](https://github.com/istanbuljs/istanbuljs)/[NYC](https://github.com/istanbuljs/nyc) son excelentes por 3 razones: son gratis (no se requiere ningún esfuerzo para realizar estos informes), ayudan a identificar una disminución en la cobertura de las pruebas y, por último, pero no menos importante, resaltan los desajustes de las pruebas: al mirar los informes de cobertura de códigos de colores puede que veas, por ejemplo, áreas de código que nunca se prueban como cláusulas catch (lo que significa que las pruebas solo invocan las rutas felices y no cómo se comporta la aplicación ante los errores). Configúrelo para generar fallos si la cobertura cae por debajo de un cierto umbral +**TL;DR:** La prueba de punta a punta (e2e) que incluye datos en vivo solía ser el eslabón más débil del proceso de CI, ya que depende de múltiples servicios pesados como la BDD. Usa un entorno que esté lo más cerca posible de su producción real como una continuación -**De lo contrario:** No habrá ninguna métrica automatizada que le indique cuándo una gran parte de su código no está cubierto por las pruebas +**De lo contrario:** Sin 'docker-compose',los equipos deben mantener una base de datos de prueba para cada entorno de prueba, incluidas las máquinas de los desarrolladores, mantener todas esas bases de datos sincronizadas para que los resultados de la prueba no varíen entre entornos.

-## ![✔] 4.9 Inspecciona los paquetes obsoletos +## ![✔] 4.9 Refactoriza regularmente utilizando herramientas de análisis estático de código -**TL;DR:** Usa tu herramienta preferida (e.g. 'npm outdated' o [npm-check-updates](https://www.npmjs.com/package/npm-check-updates) para detectar paquetes instalados que están desactualizados, inyecte esta verificación en su canalización de CI e incluso haga que una compilación falle en un escenario grave. Por ejemplo, un escenario grave podría ser cuando un paquete instalado tiene 5 parches confirmados (por ejemplo, la versión local es 1.3.1 y la versión del repositorio es 1.3.8) o está etiquetado como obsoleto por su autor: elimine la compilación y evite implementar esto versión +**TL;DR:** El uso de herramientas de análisis estático ayudan al proporcionar formas objetivas de mejorar la calidad del código y mantienen tu código mantenible. Puedes agregar herramientas de análisis estático a tu compilación de CI para que falle cuando encuentre problemas en código. Sus principales puntos de venta sobre el linting son la capacidad de inspeccionar la calidad en el contexto de múltiples archivos (por ejemplo, detectar duplicaciones), realizar análisis avanzados (por ejemplo, complejidad del código) y seguir el historial y el progreso de los problemas de código. Dos ejemplos de herramientas que puede usar son [Sonarqube](https://www.sonarqube.org/) (2,600+ [stars](https://github.com/SonarSource/sonarqube)) y [Code Climate](https://codeclimate.com/) (1,500+ [stars](https://github.com/codeclimate/codeclimate)). -**De lo contrario:** Su producción ejecutará paquetes que han sido etiquetados explícitamente por su autor como riesgosos +**De lo contrario:** Con una mala calidad de código, los errores y el rendimiento siempre serán un problema que ninguna nueva y brillante biblioteca o características de última generación podrá solucionar + +🔗 [**Leer más: Refactorización!**](./sections/testingandquality/refactoring.spanish.md)

-## ![✔] 4.10 Usa ambiente similar al de producción para pruebas e2e +## ![✔] 4.10 Simula las respuestas de servicios HTTP externos -**TL;DR:** La prueba de extremo a extremo (e2e) que incluye datos en vivo solía ser el eslabón más débil del proceso de CI, ya que depende de múltiples servicios pesados como DB. Usa un entorno que esté lo más cerca posible de su producción real como a-continue +### `🌟 #new` -**De lo contrario:** Sin 'docker-compose',los equipos deben mantener una base de datos de prueba para cada entorno de prueba, incluidas las máquinas de los desarrolladores, mantener todas esas bases de datos sincronizadas para que los resultados de la prueba no varíen entre entornos. +**TL;DR:** Utilice herramientas de mocking de red para simular las respuestas de servicios de colaboradores externos se accedan a través de la red (por ejemplo, REST, GraphQL). Es imperativo no sólo para aislar el componente bajo prueba sino principalmente para simular los caminos no felices. Herramientas como [nock](https://github.com/nock/nock) (en proceso) o [Mock-Server](https://www.mock-server.com/) permiten definir respuestas específicas de un servicio externo en una sola línea de código. Recuerda simular también los errores, retrasos, tiempos de espera agotados y cualquier otro evento que pueda ocurrir en producción. + +**De lo contrario:** Permitir que tu componente lleguen a instancias reales de servicios externos probablemente dará como resultado pruebas ingenuas que en su mayoría cubren solo los caminos felices. Las pruebas también pueden ser inestables y lentas. + +🔗 [**Read More: Mock external services**](./sections/testingandquality/mock-external-services.spanish.md)

-## ![✔] 4.11 Refactoriza regularmente utilizando herramientas de análisis estático +## ![✔] 4.11 Prueba tus middlewares por separado -**TL;DR:** El uso de herramientas de análisis estático ayuda al proporcionar formas objetivas para mejorar la calidad del código y mantiene tu código mantenible. Puedes agregar herramientas de análisis estático a su compilación de CI para que falle cuando encuentre que el código huele. Sus principales puntos de venta sobre el revestimiento simple son la capacidad de inspeccionar la calidad en el contexto de múltiples archivos (por ejemplo, detectar duplicaciones), realizar análisis avanzados (por ejemplo, complejidad del código) y seguir el historial y el progreso de los problemas de código. Dos ejemplos de herramientas que puede usar son [Sonarqube](https://www.sonarqube.org/) (2,600+ [stars](https://github.com/SonarSource/sonarqube)) y [Code Climate](https://codeclimate.com/) (1,500+ [stars](https://github.com/codeclimate/codeclimate)). +**TL;DR:** Cuando tu middleware tiene una lógica inmensa que se extiende a muchas peticiones, vale la pena realizar pruebas por separado, sin necesidad de levantar todo el framework web. Esto puede hacerse fácilmente simulando y espiando los objetos {req, res, next}. -**De lo contrario:** Con una mala calidad de código, los errores y el rendimiento siempre serán un problema que ninguna biblioteca nueva brillante o características de última generación podrá solucionar +**De lo contrario** Un bug en un middleware de express === un bug en todas o casi todas las peticiones -🔗 [**Leer más: Refactoriza!**](./sections/testingandquality/refactoring.spanish.md) +🔗 [**Leer más: Prueba tu middleware por separado**](./sections/testingandquality/test-middlewares.spanish.md)

-## ![✔] 4.12 Elije con cuidado tu plataforma CI (Jenkins vs CircleCI vs Travis vs Resto del mundo) +## ![✔] 4.12 Especifica un puerto en producción, aleatorizalo en las pruebas -**TL;DR:** Tu plataforma de integración continua (CI/CD) alojará todas las herramientas de calidad (por ejemplo, prueba, lint), por lo que debería venir con un ecosistema vibrante de complementos. [Jenkins](https://jenkins.io/) solía ser el valor predeterminado para muchos proyectos, ya que tiene la comunidad más grande junto con una plataforma muy poderosa al precio de una configuración compleja que exige una curva de aprendizaje empinada. Hoy en día, se ha vuelto mucho más fácil configurar una solución de CI utilizando herramientas SaaS como [CircleCI](https://circleci.com) y otros. Estas herramientas permiten crear una tubería de CI flexible sin la carga de administrar toda la infraestructura. Eventualmente, es una compensación entre robustez y velocidad: elije tu lado con cuidado +### `🌟 #new` -**De lo contrario:** Elegir un proveedor de nicho puede bloquearlo una vez que necesite una personalización avanzada. Por otro lado, ir con Jenkins podría quemar un tiempo precioso en la configuración de la infraestructura +**TL;DR:** Al realizar pruebas con la API, es común y deseable inicializar el servidor web dentro de las pruebas. Deje que el servidor aleatorice el puerto del servidor web durante las pruebas para evitar colisiones. Si está utilizando el servidor http de Node.js (utilizado por la mayoría de los fraweworks), hacerlo no exige nada más que pasar un número de puerto cero; esto aleatorizará un puerto disponible. -🔗 [**Leer más: Elige tu plataforma CI**](./sections/testingandquality/citools.spanish.md) +**Otherwise:** Especificar un puerto fijo evitará que se ejecuten dos procesos de prueba al mismo tiempo. La mayoría de los ejecutores de pruebas modernos se ejecutan con múltiples procesos de forma predeterminada. -

+🔗 [**Leer más: Aleatoriza un puerto para pruebas**](./sections/testingandquality/randomize-port.spanish.md) -## ![✔] 4.13 Prueba tu middleware por separado +

-**TL;DR:** Cuando tu middleware tiene una lógica inmensa que se extiende a muchas peticiones, vale la pena realizar pruebas por separado, sin necesidad de despertar todo el framework web. Esto puede hacerse fácilmente pisando y espiando en los objetos {req, res, next}. +## ![✔] 4.13 Prueba los cinco posibles resultados -**De lo contrario** Un bug en un middleware de express === un bug en todas o casi todas las peticiones +### `🌟 #new` -🔗 [**Leer más: Prueba tu middleware por separado**](./sections/testingandquality/test-middlewares.spanish.md) +**TL;DR:** Al probar un flujo, asegúrate de cubrir las cinco categorías potenciales. Cada vez que se desencadena alguna acción (por ejemplo, una llamada a la API), ocurre una reacción, un **resultado** significativo es generado y se solicita una prueba. Hay cinco tipos de resultados posibles para cada flujo: una respuesta, un cambio de estado visible (por ejemplo, BDD), una llamada de API saliente, un nuevo mensaje en una cola y una llamada de observabilidad (por ejemplo, logging, métrica). Consulta una [lista aquí] (https://testjavascript.com/wp-content/uploads/2021/10/the-backend-checklist.pdf). Cada tipo de resultado presenta desafíos únicos y técnicas para mitigar esos desafíos; tenemos una guía dedicada a este tema: [Node.js testing - beyond the basics](https://github.com/testjavascript/nodejs-integration-tests-best-practices). + +**Otherwise:** Considera el caso de probar el agregar un nuevo producto al sistema. Es común ver pruebas que se basan únicamente en una respuesta válida. ¿Qué pasa si el producto no persiste a pesar de la respuesta positiva? ¿Qué pasa si al agregar un nuevo producto se requiere llamar a algún servicio externo o poner un mensaje en la cola? ¿No debería la prueba confirmar estos resultados también? Es fácil pasar por alto varios caminos, aquí es donde una [lista resulta útil] (https://testjavascript.com/wp-content/uploads/2021/10/the-backend-checklist.pdf). + +🔗 [**Leer más: Prueba cinco resultados**](./sections/testingandquality/test-five-outcomes.spanish.md)


⬆ Volver arriba

-# `5. Yendo a las prácticas de producción` +# `5. Prácticas de puesta en producción` -## ![✔] 5.1. Monitorización +## ![✔] 5.1. Monitoreo -**TL;DR:** Monitorear es un juego para descubrir problemas antes de que lo hagan los clientes; obviamente, se le debe asignar una importancia sin precedentes. El mercado está abrumado por las ofertas, por lo tanto, considera empezar con la definición de las métricas básicas que debe seguir (mis sugerencias en el interior), luego repasar características sofisticadas adicionales y elegir la solución que cumple todos los requisitos. Haga clic en "Lo esencial" a continuación para obtener una descripción general de las soluciones +**TL;DR:** Monitorear es un juego para descubrir problemas antes de que lo hagan los clientes; obviamente, se le debe asignar una importancia sin precedentes. El mercado está abrumado por las ofertas, por lo tanto, considera empezar con la definición de las métricas básicas que debe seguir (mis sugerencias dentro), luego vé por características sofisticadas adicionales y elige la solución que cumpla con todos los requisitos. En cualquier caso, se deben cubrir las 4 capas de observabilidad: tiempo de actividad, métricas centradas en los síntomas de cara al usuario y métricas técnicas de Node.js como la demora del Event Loop, medición de flujos distribuidos con Open Telemetry y logueo. Haga clic en "Leer más" debajo para una descripción general de las soluciones. **De lo contrario:** Fallar === clientes decepcionados. Simple @@ -574,41 +878,41 @@ Todo lo de encima hubiera devuelto `false` si se hubiera usado `===`

-## ![✔] 5.2. Aumenta la transparencia utilizando unos registros inteligentes +## ![✔] 5.2. Aumenta la observabilidad utilizando logging inteligente -**TL;DR:** Los registros pueden ser un almacén tonto de declaraciones de depuración o el habilitador de un hermoso tablero que cuenta la historia de tu aplicación. Planifica tu plataforma de registro desde el día 1: cómo se recopilan, almacenan y analizan los registros para garantizar que la información deseada (por ejemplo, tasa de error, seguir una transacción completa a través de servicios y servidores, etc.) realmente se pueda extraer +**TL;DR:** Los logs pueden ser un almacén tonto de sentencias de depuración o el habilitador de un hermoso tablero que cuenta la historia de tu aplicación. Planifica tu plataforma de logs desde el día 1: cómo se recopilan, almacenan y analizan los registros para garantizar que la información deseada realmente se pueda extraer (por ejemplo, la tasa de error, seguir una transacción completa a través de servicios y servidores, etc.). -**De lo contrario:** Terminarás con un cuadro negro con el que es difícil razonar y luego empezaras a reescribir todas las declaraciones de registro para agregar información adicional +**De lo contrario:** Terminarás con un caja negra con la que es difícil pensar y luego empezaras a reescribir todas las declaraciones de registro para agregar información adicional -🔗 [**Leer mas: Aumenta la transparencia utilizando unos registros inteligentes**](./sections/production/smartlogging.spanish.md) +🔗 [**Leer mas: Aumenta la transparencia utilizando logging inteligentes**](./sections/production/smartlogging.spanish.md)

## ![✔] 5.3. Delega todo lo posible (por ejemplo, gzip, SSL) a un proxy inverso -**TL;DR:** Node es terriblemente malo para realizar tareas intensivas de CPU como gzipping, terminación SSL, etc. En su lugar, debes usar servicios de middleware "reales" como nginx, HAproxy o servicios de proveedores en la nube +**TL;DR:** Node es terriblemente malo para realizar tareas intensivas de CPU como compresión, terminación SSL, etc. En su lugar deberías usar servicios de infraestructura especializados como nginx, HAproxy o servicios de proveedores en la nube -**De lo contrario:** Tu único subproceso se mantendrá ocupado haciendo tareas de infraestructura en lugar de ocuparse del núcleo de tu aplicación y el rendimiento se degradará en consecuencia +**De lo contrario:** Tu pobre monohilo se mantendrá ocupado haciendo tareas de infraestructura en lugar de ocuparse del núcleo de tu aplicación y el rendimiento se degradará en consecuencia 🔗 [**Leer más: Delega todo lo posible a un proxy inverso**](./sections/production/delegatetoproxy.spanish.md)

-## ![✔] 5.4. Bloquear dependencias +## ![✔] 5.4. Bloquea dependencias -**TL;DR:** Tu código debe ser idéntico en todos los entornos, pero sorprendentemente npm permite que las dependencias se desplacen entre los entornos de forma predeterminada: cuando instala paquetes en varios entornos, intenta obtener la última versión del parche de los paquetes. Evita esto utilizando archivos de configuración npm, .npmrc, que le indican a cada entorno que guarde la versión exacta (no la última) de cada paquete. Alternativamente, para un control más fino usa `npm shrinkwrap`. \ * Actualización: a partir de NPM5, las dependencias están bloqueadas de forma predeterminada. El nuevo administrador de paquetes, Yarn, también lo cubre por defecto +**TL;DR:** Tu código debe ser idéntico en todos los entornos, pero sin un archivo de bloqueo especial npm permite que las dependencias fluctúen entre los entornos. Asegúrese de agregar a su repositorio el archivo paquete-lock.json para que todos los entornos sean idénticos. -**De lo contrario:** El control de calidad probará a fondo el código y aprobará una versión que se comportará de manera diferente cuando está en producción. Peor aún, diferentes servidores en el mismo clúster de producción pueden ejecutar código diferente +**De lo contrario:** QA probará a fondo el código y aprobará una versión que se comportará de manera diferente cuando está en producción. Peor aún, diferentes servidores en el mismo clúster de producción podrían ejecutar código diferente 🔗 [**Leer más: Bloquear dependencias**](./sections/production/lockdependencies.spanish.md)

-## ![✔] 5.5. Proteja la disponibilidad del proceso utilizando la herramienta adecuada +## ![✔] 5.5. Proteje la disponibilidad del proceso utilizando la herramienta adecuada -**TL;DR:** El proceso debe continuar y reiniciarse si falla. Para escenarios simples, las herramientas de administración de procesos como PM2 pueden ser suficientes, pero en el mundo "dockerizado" de hoy en día, las herramientas de administración de clústeres también deben considerarse +**TL;DR:** El proceso debe continuar y reiniciarse en caso de fallas. Las plataformas de ejecución modernas, como las plataformas dockerizadas (por ejemplo, Kubernetes) y Serverless, se encargan de esto automáticamente. Cuando la aplicación está alojada en un servidor básico, uno deben gestionar las herramientas de gestión de procesos como [systemd](https://systemd.io/). Evite incluir una herramienta de gestión de procesos personalizada en una plataforma moderna que monitoree una instancia de aplicación (por ejemplo, Kubernetes); al hacerlo, se ocultarán las fallas de la infraestructura. Cuando la infraestructura subyacente no reconoce los errores, no puede realizar medidas de mitigación útiles, como reemplazar la instancia en una ubicación diferente. -**De lo contrario:** Ejecutar docenas de instancias sin una estrategia clara y demasiadas herramientas juntas (administración de clúster, docker, PM2) podría conducir al caos de DevOps +**De lo contrario:** Ejecutar docenas de instancias sin una estrategia clara y demasiadas herramientas juntas (administración de clúster, docker, PM2) podría conducir al caos de DevOps. 🔗 [**Leer más: Proteja la disponibilidad del proceso utilizando la herramienta adecuada**](./sections/production/guardprocess.spanish.md) @@ -616,7 +920,7 @@ Todo lo de encima hubiera devuelto `false` si se hubiera usado `===` ## ![✔] 5.6. Utiliza todos los núcleos de la CPU -**TL;DR:** En su forma básica, una aplicación Node se ejecuta en un solo núcleo de CPU mientras que todas las demás quedan inactivas. Es tu deber replicar el proceso Node y utilizar todas las CPU: para aplicaciones pequeñas y medianas, puedes usar Node Cluster o PM2. Para una aplicación más grande, considera replicar el proceso utilizando algún clúster de Docker (por ejemplo, K8S, ECS) o scripts de implementación basados en el sistema de inicio Linux (ej. systemd) +**TL;DR:** En su forma básica, una aplicación Node se ejecuta en un solo núcleo de CPU mientras que todas las demás quedan inactivas. Es tu deber replicar el proceso Node y utilizar todas las CPU. La mayoría de las plataformas de ejecución modernas (por ejemplo, Kubernetes) permiten replicar instancias de la aplicación, pero no verifican que se utilicen todos los núcleos; este es su deber. Si la aplicación está alojada en un servidor básico, también es su deber utilizar alguna solución de replicación de procesos (por ejemplo, systemd). **De lo contrario:** Es probable que tu aplicación utilice solo el 25% de sus recursos disponibles (!) O incluso menos. Ten en cuenta que un servidor típico tiene 4 núcleos de CPU o más, la implementación ingenua de Node.js utiliza solo 1 (¡incluso utilizando servicios PaaS como AWS beanstalk!) @@ -624,19 +928,21 @@ Todo lo de encima hubiera devuelto `false` si se hubiera usado `===`

-## ![✔] 5.7. Crear un "end point de mantenimiento" +## ![✔] 5.7. Crea un "end point de mantenimiento" -**TL;DR:** Descubre un conjunto de información relacionada con el sistema, como el uso de memoria y REPL, etc. en una API segura. Aunque es muy recomendable confiar en herramientas estándar y de pruebas de batalla, parte de la información y las operaciones valiosas se hacen más fácilmente usando código +**TL;DR:** Descubre un conjunto de información relacionada con el sistema, como el uso de memoria y REPL, etc. en una API segura. Aunque es muy recomendable confiar en herramientas estándar y probadas, parte de la información valiosa y de las operaciones se obtienen más fácilmente usando código -**De lo contrario:** Descubrirás que estás realizando muchas "implementaciones de diagnóstico": envío de código a producción solo para extraer cierta información con fines de diagnóstico +**De lo contrario:** Descubrirás que estás realizando muchas "implementaciones de diagnóstico", es decir, el envío de código a producción solo para extraer cierta información con fines de diagnóstico. 🔗 [**Leer más: Crea un ‘endpoint de mantenimiento**](./sections/production/createmaintenanceendpoint.spanish.md)

-## ![✔] 5.8. Descubre errores y tiempos de inactividad utilizando productos APM +## ![✔] 5.8. Descubre lo desconocido utilizando productos de APM + +### `📝 #updated` -**TL;DR:** Los productos de monitoreo y rendimiento de aplicaciones (también conocido como APM) miden proactivamente la base de código y la API para que puedan ir automáticamente más allá del monitoreo tradicional y medir la experiencia general del usuario en todos los servicios y niveles. Por ejemplo, algunos productos APM pueden resaltar una transacción que se carga demasiado lentamente en el lado de los usuarios finales al tiempo que sugiere lo que lo podría provocar +**TL;DR:** Considera agregar otra capa de seguridad a la pila de producción: APM. Si bien la mayoría de los síntomas y causas pueden detectarse mediante técnicas de monitoreo tradicionales, en un sistema distribuido hay más de lo que parece. Los productos de rendimiento y monitoreo de aplicaciones (también conocidos como APM) pueden ir automáticamente más allá del monitoreo tradicional y proporcionar una capa adicional de descubrimiento y experiencia para desarrolladores. Por ejemplo, algunos productos APM pueden resaltar una transacción que se carga demasiado lenta en el **lado del usuario final** y al mismo tiempo sugerir la causa raíz. Los APM también brindan más contexto para los desarrolladores que intentan solucionar un error de registro al mostrar en qué estaba ocupado el servidor cuando ocurrió el error. Por nombrar algunos ejemplos. **De lo contrario:** Es posible que dediques un gran esfuerzo a medir el rendimiento de la API y los tiempos de inactividad, probablemente nunca te darás cuenta de cuáles son tus partes de código más lentas en un escenario del mundo real y cómo afectan a la experiencia de usuario @@ -644,21 +950,21 @@ Todo lo de encima hubiera devuelto `false` si se hubiera usado `===`

-## ![✔] 5.9. Prepara tu código para la producción +## ![✔] 5.9. Haz tu código listo para producción -**TL;DR:** Codifica con el fin en mente, planifica la producción desde el día 1. Esto suena un poco vago, así que he compilado algunos consejos de desarrollo que están estrechamente relacionados con el mantenimiento de la producción (haga clic en Gist a continuación) +**TL;DR:** Codifica con el fin en mente, planifica la producción desde el día 1. Esto suena un poco vago, así que he compilado algunos consejos de desarrollo que están estrechamente relacionados con el mantenimiento de la producción (haz clic en "Leer más") -**De lo contrario:** Un campeón mundial de IT/DevOps no salvará un sistema mal escrito +**De lo contrario:** Un campeón mundial de IT/DevOps no salvará un sistema que está mal escrito -🔗 [**Leer más: Prepara tu código para la producción**](./sections/production/productioncode.spanish.md) +🔗 [**Leer más: Has tu código listo para producción**](./sections/production/productioncode.spanish.md)

-## ![✔] 5.10. Medir y proteger el uso de la memoria +## ![✔] 5.10. Mide y protege el uso de la memoria -**TL;DR:** Node.js tiene relaciones controversiales con la memoria: el motor v8 tiene límites suaves en el uso de la memoria (1,4 GB) y hay maneras conocidas para perder memoria en el código de Node, por lo que es imprescindible observar la memoria de proceso de Node. En aplicaciones pequeñas, puedes medir la memoria periódicamente utilizando comandos de shell, pero en aplicaciones medianas y grandes, considera convertir tu reloj de memoria en un sistema de monitoreo robusto +**TL;DR:** Node.js tiene relaciones controversiales con la memoria: el motor v8 tiene límites suaves en el uso de la memoria (1,4 GB) y hay formas conocidas de perder memoria en el código de Node, por lo que es imprescindible observar la memoria de proceso de Node. En aplicaciones pequeñas, puedes medir la memoria periódicamente utilizando comandos de shell, pero en aplicaciones medianas y grandes, considera convertir tu observación de la memoria en un sistema de monitoreo robusto -**De lo contrario:** Tu memoria de proceso podría perder cien megabytes por día, como sucedió a [Walmart](https://www.joyent.com/blog/walmart-node-js-memory-leak) +**De lo contrario:** Tu proceso podría perder memoria al ritmo de cien megabytes por día, como le sucedió a [Walmart](https://www.joyent.com/blog/walmart-node-js-memory-leak) 🔗 [**Leer más: Medir y proteger el uso de la memoria**](./sections/production/measurememory.spanish.md) @@ -666,7 +972,7 @@ Todo lo de encima hubiera devuelto `false` si se hubiera usado `===` ## ![✔] 5.11. Saca tus recursos frontend de Node -**TL;DR:** Sirve el contenido frontend usando middleware dedicado (nginx, S3, CDN) porque el rendimiento de Node se ve realmente afectado cuando se trata con muchos archivos estáticos debido a su modelo de subproceso único +**TL;DR:** Sirve el contenido frontend usando middleware dedicado (nginx, S3, CDN) porque el rendimiento de Node se ve realmente afectado cuando se trata con muchos archivos estáticos debido a su modelo de único hilo. Una excepción a esta guía es cuando se hace server-side rendering. **De lo contrario:** Tu único hilo Node estará ocupado transmitiendo cientos de archivos html / images / angular / react en lugar de asignar todos sus recursos para la tarea para la que nació: servir contenido dinámico @@ -674,19 +980,19 @@ Todo lo de encima hubiera devuelto `false` si se hubiera usado `===`

-## ![✔] 5.12. Se anti-estado, mata tus servidores casi todos los días +## ![✔] 5.12. Esfuerzate por ser stateless -**TL;DR:** Almacena cualquier tipo de datos (por ejemplo, sesiones de usuario, caché, archivos cargados) en almacenes de datos externos. Considera "matar" sus servidores periódicamente o utilice la plataforma "sin servidor" (por ejemplo, AWS Lambda) que aplica explícitamente un comportamiento sin estado +**TL;DR:** Almacena cualquier tipo de _datos_ (por ejemplo, sesiones de usuario, caché, archivos cargados) en almacenes de datos externos. Cuando la aplicación mantiene datos en proceso, esto agrega una capa adicional de complejidad de mantenimiento, como enrutar a los usuarios a la misma instancia y un mayor costo de reiniciar un proceso. Para imponer y fomentar un enfoque sin estado, la mayoría de las plataformas de ejecución modernas permiten "reaplicar" instancias periódicamente. **De lo contrario:** Un fallo en un servidor dará como resultado el tiempo de inactividad de la aplicación en lugar de simplemente matar una máquina defectuosa. Además, la elasticidad de escalamiento será más difícil debido a la dependencia de un servidor específico -🔗 [**Leer más: Se anti-estado, mata tus servidores casi todos los días**](./sections/production/bestateless.spanish.md) +🔗 [**Leer más: Se stateless, mata tus servidores casi todos los días**](./sections/production/bestateless.spanish.md)

-## ![✔] 5.13. Usa herramientas que detecten vulnerabilidades automáticamente +## ![✔] 5.13. Usa herramientas que detecten automáticamente vulnerabilidades -**TL;DR:** Incluso las dependencias de mayor reputación como Express tienen vulnerabilidades conocidas (de vez en cuando) que pueden poner en riesgo un sistema. Esto se puede dominar fácilmente usando herramientas comunitarias y comerciales que constantemente verifican vulnerabilidades y advierten (localmente o en GitHub), algunos incluso pueden parchearlas de inmediato +**TL;DR:** Incluso las dependencias de mayor reputación como Express tienen vulnerabilidades conocidas (de vez en cuando) que pueden poner en riesgo un sistema. Esto se puede manejar fácilmente usando herramientas comunitarias y comerciales que constantemente verifican vulnerabilidades y advierten (localmente o en GitHub), algunas incluso pueden parchearlas de inmediato **De lo contrario:** Mantener tu código limpio de vulnerabilidades sin herramientas dedicadas requerirá que sigas constantemente las publicaciones en línea sobre nuevas amenazas. Bastante tedioso @@ -694,31 +1000,29 @@ Todo lo de encima hubiera devuelto `false` si se hubiera usado `===`

-## ![✔] 5.14. Asigna un id de transacción a cada instrucción del registro +## ![✔] 5.14. Asigna un id de transacción a cada registro del log -También conocido como correlation id / transit id / tracing id / request id / request context / etc. +**TL;DR:** Asigna el mismo identificador, id-transacción: uuid(), a cada entrada de registro dentro de una solicitud (también conocido como correlation id, tracing id, request context, etc.). Luego, al inspeccionar los errores en los logs, encontrarás fácilmente lo que sucedió antes y después. Node tiene un mecanismo incorporado, [AsyncLocalStorage](https://nodejs.org/api/async_context.html), para mantener el mismo contexto en llamadas asincrónicas. Ver los ejemplos de código dentro. -**TL;DR:** Asigna el mismo identificador, id-transacción: {algún valor}, a cada entrada de registro dentro de una sola solicitud. Luego, al inspeccionar los errores en los registros, encontrarás fácilmente lo que sucedió antes y después. Antes de la version 14 de Node, esto no era fácil de hacer debido a la naturaleza asíncrona de Node, pero desde `AsyncLocalStorage` llegó, esto se volvió posible y mas fácil que nunca. Ver códigos de ejemplo adentro +**De lo contrario:** Ver un log de error de producción sin el contexto, lo que sucedió antes, hace que sea mucho más difícil y lento razonar sobre el problema. -**De lo contrario:** Ver un registro de errores de producción sin el contexto, lo que sucedió antes, hace que sea mucho más difícil y lento razonar sobre el problema - -🔗 [**Leer más: asigna un ‘Id de transacción’ a cada instrucción del registro**](./sections/production/assigntransactionid.spanish.md) +🔗 [**Leer más: Asigna un ‘TransactionId’ a cada registro de log**](./sections/production/assigntransactionid.spanish.md)

-## ![✔] 5.15. Establecer `NODE_ENV=production` +## ![✔] 5.15. Establece `NODE_ENV=production` -**TL;DR:** Establece la variable de entorno NODE_ENV a "producción" o "desarrollo" para marcar si las optimizaciones de producción deben activarse; muchos paquetes npm determinan el entorno actual y optimizan su código para la producción +**TL;DR:** Establece la variable de entorno NODE_ENV a "producción" o "desarrollo" para marcar si las optimizaciones de producción deben activarse; varios paquetes npm determinan el entorno actual y optimizan su código para la producción -**De lo contrario:** Omitir esta simple propiedad podría degradar en gran medida el rendimiento. Por ejemplo, cuando se usa Express para la representación del lado del servidor, omitir `NODE_ENV` lo hace un tercio más lento. +**De lo contrario:** Omitir esta simple propiedad podría degradar en gran medida cuando se utilizand determinas bibliotecas como por ejemplo server-side rendering en Express. -🔗 [**Leer más: Establecer NODE_ENV=production**](./sections/production/setnodeenv.spanish.md) +🔗 [**Leer más: Establece NODE_ENV=production**](./sections/production/setnodeenv.spanish.md)

-## ![✔] 5.16. Diseña implementaciones automatizadas, atómicas y sin tiempo de inactividad +## ![✔] 5.16. Diseña despliegues automatizados, atómicos y sin tiempo de inactividad -**TL;DR:** Las investigaciónes muestran que los equipos que realizan muchas implementaciones reducen la probabilidad de problemas graves de producción. Las implementaciones rápidas y automatizadas que no requieren pasos manuales riesgosos y el tiempo de inactividad del servicio mejoran significativamente el proceso de implementación. Deberías lograr esto usando Docker combinado con herramientas de CI, ya que se convirtieron en el estándar de la industria para la implementación simplificada +**TL;DR:** Las investigaciónes muestran que los equipos que realizan muchas implementaciones reducen la probabilidad de problemas graves de producción. Las implementaciones rápidas y automatizadas que no requieren riesgos pasos manuales ni tiempo de inactividad del servicio mejoran significativamente el proceso de implementación. Deberías lograr esto usando Docker combinado con herramientas de CI, ya que se convirtieron en el estándar de la industria para la implementación optimizada **De lo contrario:** Implementaciones largas -> tiempo de inactividad de producción y error humano -> equipo desconfiado en la implementación -> menos implementaciones y características @@ -728,29 +1032,31 @@ También conocido como correlation id / transit id / tracing id / request id / r **TL;DR:** Asegúrate de estar utilizando una versión LTS (de soporte a largo plazo) de Node.js para recibir correcciones de errores críticos, actualizaciones de seguridad y mejoras de rendimiento. -**De lo contrario:** Los errores o vulnerabilidades recientemente descubiertos podrían utilizarse para explotar una aplicación que se ejecuta en producción, y su aplicación puede dejar de ser compatible con varios módulos y ser más difícil de mantener +**De lo contrario:** Los errores o vulnerabilidades recientemente descubiertos podrían utilizarse para explotar una aplicación que se ejecuta en producción, y tu aplicación puede dejar de ser compatible con varios módulos y ser más difícil de mantener. 🔗 [**Leer más: Usa una versión LTS de Node.js**](./sections/production/LTSrelease.spanish.md)

-## ![✔] 5.18. No enrutes registros dentro de la aplicación +## ![✔] 5.18. Loguea hacia stdout, evita especificar un destino de log dentro de la aplicación + +### `📝 #updated` -**TL;DR:** Los desarrolladores no deben codificar los destinos de registro dentro del código de la aplicación, sino que deben estar definidos por el entorno de ejecución en el que se ejecuta la aplicación. Los desarrolladores deben escribir registros en 'stdout' utilizando una utilidad de registro y luego dejar que el entorno de ejecución (contenedor, servidor, etc.) canalice la secuencia `stdout` al destino apropiado (es decir, Splunk, Graylog, ElasticSearch, etc.). +**TL;DR:** Los desarrolladores no deben programar los destinos de los logs dentro del código de la aplicación, sino que deben definirlos según el entorno de ejecución en el que se corre la aplicación. Los desarrolladores deben escribir logs en `stdout` usando una utilidad de logueo y dejar que el entorno de ejecución (contenedor, servidor, etc.) canalize el flujo de `stdout` al destino apropiado (es decir, Splunk, Graylog, ElasticSearch, etc.). -**De lo contrario** Aplicación de enrutamiento de registro de manejo === difícil de escalar, pérdida de registros, mala separación de preocupaciones +**De lo contrario** Si los desarrolladores establecen el enrutamiento de los logs, queda menos flexibilidad para el profesional de operaciones que desee personalizarlo. Más allá de esto, si la aplicación intenta iniciar sesión directamente en una ubicación remota (por ejemplo, Elastic Search), en caso de pánico o caída, no llegarán más registros que puedan explicar el problema. -🔗 [**Leer más: Enrutamiento de registros**](./sections/production/logrouting.spanish.md) +🔗 [**Leer más: Enrutamiento de logs**](./sections/production/logrouting.spanish.md)

## ![✔] 5.19. Instala tus paquetes con `npm ci` -**TL;DR:** Tienes que asegurate que el código de producción utiliza la misma versión de los paquetes con los que realizaste pruebas. Corre `npm ci` para estrictamente instalar de manera limpia las dependencias que correspondan al package.json y package-lock.json. Usando este comando es recomendado en ambientes automatizados, como los canalizadores de integración contínua (continuos integration pipelines). +**TL;DR:** Ejecuta `npm ci` para realizar estrictamente una instalación limpia de sus dependencias que coincidan con los archivos package.json y package-lock.json. Obviamente, el código de producción debe utilizar la versión exacta de los paquetes que se utilizaron para las pruebas. Si bien el archivo package-lock.json establece una versión estricta para las dependencias, en caso de que no coincida con el archivo package.json, el comando 'npm install' tratará a package.json como la fuente de la verdad. Por otro lado, el comando 'npm ci' terminará con error en caso de que estos archivos no coincidan. **De lo contrario** QA va probar exhaustivamente el código y aprobar una version que se va a comportar diferente en producción. Peor aún, servidores en el mismo cluster de producción podría correr distinto código. -🔗 [**Leer más: Instala tus paquetes con npm ci**](./sections/production/installpackageswithnpmci.spanish.md) +🔗 [**Leer más: Usa con npm ci**](./sections/production/installpackageswithnpmci.spanish.md)


@@ -762,13 +1068,13 @@ También conocido como correlation id / transit id / tracing id / request id / r 54 items
-## ![✔] 6.1. Adopta las reglas de seguridad de linter +## ![✔] 6.1. Adopta las reglas de seguridad del linter -**TL;DR:** Utiliza los complementos de interfaz relacionados con la seguridad, como [eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security) para detectar vulnerabilidades y problemas de seguridad lo antes posible, preferiblemente mientras se codifican. Esto puede ayudar a detectar debilidades de seguridad, como usar eval, invocar un proceso secundario o importar un módulo con un literal de cadena (por ejemplo, entrada del usuario). Haga clic en "Leer más" a continuación para ver ejemplos de código que quedarán atrapados por una interfaz de seguridad +**TL;DR:** Utiliza los complementos del linter relacionados con la seguridad, como [eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security) para detectar vulnerabilidades y problemas de seguridad lo antes posible, preferiblemente mientras se codifican. Esto puede ayudar a detectar debilidades de seguridad, como el uso de eval, invocar un proceso secundario o importar un módulo con un literal de string (por ejemplo, entrada del usuario). Haz clic en "Leer más" a continuación para ver ejemplos de código que quedarán atrapados por un linter de seguridad -**De lo contrario:** Lo que podría haber sido una debilidad de seguridad directa durante el desarrollo se convierte en un problema importante en la producción. Además, el proyecto puede no seguir prácticas de seguridad de código consistentes, lo que lleva a la introducción de vulnerabilidades o secretos confidenciales confiados en repositorios remotos +**De lo contrario:** Lo que podría haber sido una debilidad de seguridad directa durante el desarrollo se convierte en un problema importante en la producción. Además, el proyecto puede no seguir prácticas de seguridad de código consistentes, lo que lleva a la introducción de vulnerabilidades o secretos confidenciales enviados a repositorios remotos. 🔗 [**Leer más: Reglas de seguridad de linter**](./sections/security/lintrules.spanish.md) @@ -778,7 +1084,7 @@ También conocido como correlation id / transit id / tracing id / request id / r -**TL;DR:** Los ataques DOS son muy populares y relativamente fáciles de realizar. Implementa la limitación de velocidad utilizando un servicio externo como balanceadores de carga en la nube, firewalls en la nube, nginx, [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible) paquete, o (para aplicaciones más pequeñas y menos críticas) un middleware que limita la velocidad (e.j. [express-rate-limit](https://www.npmjs.com/package/express-rate-limit)) +**TL;DR:** Los ataques DOS son muy populares y relativamente fáciles de realizar. Implementa una limitación de tasa de solicitudes utilizando un servicio externo como balanceadores de carga en la nube, firewalls en la nube, nginx, el paquete[rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible) o (para aplicaciones más pequeñas y menos críticas) un middleware que limite la tasa de solicitudes (e.j. [express-rate-limit](https://www.npmjs.com/package/express-rate-limit)) **De lo contrario:** Una aplicación podría estar sujeta a un ataque que resulte en una denegación de servicio donde los usuarios reales reciban un servicio degradado o no disponible. @@ -786,25 +1092,25 @@ También conocido como correlation id / transit id / tracing id / request id / r

-## ![✔] 6.3 Quita los secretos de los archivos de configuración o usa paquetes para cifrarlos +## ![✔] 6.3. Quita los secretos de los archivos de configuración o utiliza paquetes para cifrarlos -**TL;DR:** Nunca almacenes secretos sin formato en archivos de configuración o código fuente. En su lugar, utiliza sistemas de gestión secreta como productos Vault, Kubernetes / Docker Secrets o variables de entorno. Como último recurso, los secretos almacenados en el control de código fuente deben ser encriptados y administrados (claves rodantes, vencimiento, auditoría, etc.). Utiliza los ganchos en pre-commit/push para evitar que se guarden secretos accidentalmente +**TL;DR:** Nunca almacenes secretos sin formato en archivos de configuración o código fuente. En su lugar, utiliza sistemas de gestión de secretos como productos Vault, Kubernetes / Docker Secrets o variables de entorno. Como último recurso, los secretos almacenados en sistemas de control de código fuente deben ser encriptados y administrados (rotación de claves, vencimiento, auditoría, etc.). Utiliza los hooks de pre-commit/push para evitar que se guarden secretos accidentalmente. -**De lo contrario:** El control del código fuente, incluso para repositorios privados, puede hacerse público por error, momento en el que se exponen todos los secretos. El acceso al control de origen para una parte externa proporcionará inadvertidamente acceso a sistemas relacionados (bases de datos, API, servicios, etc.). +**De lo contrario:** El control del código fuente, incluso para repositorios privados, puede hacerse público por error, momento en el que se exponen todos los secretos. El acceso al control de código fuente para una grupo externo proporcionará inadvertidamente acceso a sistemas relacionados (bases de datos, API, servicios, etc.). 🔗 [**Leer más: Manejo de secretos**](./sections/security/secretmanagement.spanish.md)

-## ![✔] 6.4. Prevenir vulnerabilidades de inyección de consultas con bibliotecas ORM / ODM +## ![✔] 6.4. Evita vulnerabilidades de inyección de consultas con bibliotecas ORM / ODM -**TL;DR:** Para evitar la inyección de SQL / NoSQL y otros ataques maliciosos, utilice siempre un ORM / ODM o una biblioteca de base de datos que escape a los datos o admita consultas parametrizadas con nombre o indexadas, y se encarga de validar la entrada del usuario para los tipos esperados. Nunca utilices cadenas de plantillas de JavaScript o concatenación de cadenas para inyectar valores en las consultas, ya que esto abre su aplicación a un amplio espectro de vulnerabilidades. Todas las bibliotecas acreditadas de acceso a datos de Node.js (e.g. [Sequelize](https://github.com/sequelize/sequelize), [Knex](https://github.com/tgriesser/knex), [mongoose](https://github.com/Automattic/mongoose)) tienen protección incorporada contra ataques de inyección. +**TL;DR:** Para evitar la inyección de SQL / NoSQL y otros ataques maliciosos, utiliza siempre un ORM / ODM o una biblioteca de base de datos que escape los datos o admita consultas parametrizadas por nombre o indexadas, y que se encargue de validar la entrada del usuario para los tipos esperados. Nunca utilices plantillas de string de JavaScript o concatenación de string para inyectar valores en las consultas, ya que esto abre su aplicación a un amplio espectro de vulnerabilidades. Todas las bibliotecas confiables de acceso a datos de Node.js (e.g. [Sequelize](https://github.com/sequelize/sequelize), [Knex](https://github.com/tgriesser/knex), [mongoose](https://github.com/Automattic/mongoose)) tienen protección incorporada contra ataques de inyección. -**De lo contrario:** La entrada de usuario no validada o no higiénica podría conducir a la inyección del operador cuando se trabaja con MongoDB para NoSQL, y no usar un sistema de desinfección adecuado u ORM permitirá fácilmente ataques de inyección SQL, creando una vulnerabilidad gigante. +**De lo contrario:** La entrada de usuario no validada o sanitizada podría conducir a la inyección del operador cuando se trabaja con MongoDB para NoSQL, y no usar un sistema de sanitización adecuado u ORM permitirá fácilmente ataques de inyección SQL, creando una vulnerabilidad gigante. 🔗 [**Leer más: Prevención de inyección de consultas utilizando bibliotecas ORM/ODM**](./sections/security/ormodmusage.spanish.md) @@ -812,7 +1118,7 @@ También conocido como correlation id / transit id / tracing id / request id / r ## ![✔] 6.5. Colección de mejores prácticas de seguridad genéricas -**TL;DR:** Esta es una colección de consejos de seguridad que no está relacionada directamente con Node.js: la implementación de Node no es muy diferente a la de cualquier otro idioma. Haz clic en leer más para mas información. +**TL;DR:** Esta es una colección de consejos de seguridad que no está relacionada directamente con Node.js: la implementación de Node no es muy diferente a la de cualquier otro lenguaje. Haz clic en "Leer más" para mas información. 🔗 [**Leer más: Common security best practices**](./sections/security/commonsecuritybestpractices.spanish.md) @@ -822,7 +1128,7 @@ También conocido como correlation id / transit id / tracing id / request id / r -**TL;DR:** Tu aplicación debe usar encabezados seguros para evitar que los atacantes usen ataques comunes como scripting entre sitios (XSS), clickjacking y otros ataques maliciosos. Estos se pueden configurar fácilmente utilizando módulos como [helmet](https://www.npmjs.com/package/helmet). +**TL;DR:** Tu aplicación debe usar encabezados seguros para evitar que los atacantes usen ataques comunes como cross-site scripting (XSS), clickjacking y otros ataques maliciosos. Estos se pueden configurar fácilmente utilizando módulos como [helmet](https://www.npmjs.com/package/helmet). **De lo contrario:** Los atacantes pueden realizar ataques directos a los usuarios de su aplicación, lo que genera enormes vulnerabilidades de seguridad @@ -830,11 +1136,11 @@ También conocido como correlation id / transit id / tracing id / request id / r

-## ![✔] 6.7. Inspeccionar de manera constante y automática las dependencias vulnerables +## ![✔] 6.7. Inspecciona constante y automáticamente en busca de dependencias vulnerables -**TL;DR:** Con el ecosistema npm es común tener muchas dependencias para un proyecto. Las dependencias siempre deben mantenerse bajo control a medida que se encuentran nuevas vulnerabilidades. Usa herramientas como [npm audit](https://docs.npmjs.com/cli/audit) o [snyk](https://snyk.io/) para rastrear, monitorear y parchear dependencias vulnerables. Integra estas herramientas con su configuración de CI para que pueda detectar una dependencia vulnerable antes de que llegue a producción. +**TL;DR:** Con el ecosistema npm es común tener muchas dependencias para un proyecto. Las dependencias siempre deben mantenerse bajo control a medida que se encuentran nuevas vulnerabilidades. Usa herramientas como [npm audit](https://docs.npmjs.com/cli/audit) o [snyk](https://snyk.io/) para rastrear, monitorear y parchear dependencias vulnerables. Integra estas herramientas con tu configuración de CI para que puedas detectar una dependencia vulnerable antes de que llegue a producción. **De lo contrario:** Un atacante podría detectar su framework web y atacar todas sus vulnerabilidades conocidas. @@ -842,15 +1148,15 @@ También conocido como correlation id / transit id / tracing id / request id / r

-## ![✔] 6.8. Proteja las contraseñas/secretos de sus usuarios usando bcrypt o scrypt +## ![✔] 6.8. Protege las contraseñas/secretos de sus usuarios usando bcrypt o scrypt -**TL;DR:** Las contraseñas o los secretos (claves API) deben almacenarse utilizando una función segura hash + salt como `bcrypt`, o en le peor de los casos `pbkdf2`. +**TL;DR:** Las contraseñas o los secretos (ej. claves API) deben almacenarse utilizando una función segura hash + salt como `bcrypt`,`scrypt`, o en el peor de los casos `pbkdf2`. **De lo contrario:** Las contraseñas o los secretos que se conservan sin utilizar una función segura son vulnerables a la fuerza bruta y los ataques de diccionario que eventualmente conducirán a su divulgación. -🔗 [**Leer más: Usa Bcrypt**](./sections/security/bcryptpasswords.spanish.md) +🔗 [**Leer más: Contraseñas de usuario**](./sections/security/userpasswords.spanish.md)

@@ -858,27 +1164,27 @@ También conocido como correlation id / transit id / tracing id / request id / r -**TL;DR:** Los datos no confiables que se envían al navegador pueden ejecutarse en lugar de mostrarse, esto se conoce comúnmente como un ataque de scripting entre sitios (XSS). Mitiga esto mediante el uso de bibliotecas dedicadas que marquen explícitamente los datos como contenido puro que nunca debe ejecutarse (es decir, codificación, escape) +**TL;DR:** Los datos no confiables que se envían al navegador pueden ejecutarse en lugar de mostrarse, esto se conoce comúnmente como un ataque de scripting entre sitios (XSS). Mitiga esto mediante el uso de bibliotecas dedicadas que marquen explícitamente los datos como contenido puro que nunca debe ejecutarse (es decir, codificación, escape). -**De lo contrario:** Un atacante podría almacenar código JavaScript malicioso en su base de datos que luego se enviará tal cual a los pobres clientes +**De lo contrario:** Un atacante podría almacenar código JavaScript malicioso en su base de datos que luego se enviará tal cual a los pobres clientes. 🔗 [**Leer más: Escapa la salida**](./sections/security/escape-output.spanish.md)

-## ![✔] 6.10. Validar esquemas JSON entrantes +## ![✔] 6.10. Valida esquemas JSON entrantes -**TL;DR:** Valida la carga útil del cuerpo de las solicitudes entrantes y asegúrese de que cumpla con las expectativas, falle rápidamente si no lo hace. Para evitar la tediosa codificación de validación dentro de cada ruta, puede usar esquemas de validación ligeros basados en JSON, como [jsonschema](https://www.npmjs.com/package/jsonschema) o [joi](https://www.npmjs.com/package/joi) +**TL;DR:** Valida el valor del body de las solicitudes entrantes y asegúrese de que cumpla con las expectativas, falle rápidamente si no lo hace. Para evitar la tediosa codificación de validación dentro de cada ruta, puede usar esquemas de validación ligeros basados en JSON, como [jsonschema](https://www.npmjs.com/package/jsonschema) o [joi](https://www.npmjs.com/package/joi) -**De lo contrario:** Tu generosidad y enfoque permisivo aumentan enormemente la superficie de ataque y ayuda al atacante a probar muchas entradas hasta que encuentren alguna combinación para bloquear la aplicación. +**De lo contrario:** Tu generosidad y enfoque permisivo aumentan enormemente la superficie de ataque y ayuda al atacante a probar muchas entradas hasta que encuentren alguna combinación para tirar la aplicación. 🔗 [**Leer más: Valida esquemas JSON entrantes**](./sections/security/validation.spanish.md)

-## ![✔] 6.11. Admite las listas negras de JWT +## ![✔] 6.11. Soporta listas de bloqueo de JWTs @@ -886,11 +1192,11 @@ También conocido como correlation id / transit id / tracing id / request id / r **De lo contrario:** Los tokens caducados o extraviados pueden ser utilizados maliciosamente por un tercero para acceder a una aplicación y hacerse pasar por el propietario del token. -🔗 [**Leer más: Bloquea JSON Web Tokens caducados**](./sections/security/expirejwt.spanish.md) +🔗 [**Leer más: Bloquea JSON Web Tokens mediante listas**](./sections/security/expirejwt.spanish.md)

-## ![✔] 6.12. Prevenir ataques de fuerza bruta contra la autorización +## ![✔] 6.12. Evita ataques de fuerza bruta contra la autorización @@ -899,7 +1205,7 @@ También conocido como correlation id / transit id / tracing id / request id / r 1. El primero es el número de intentos fallidos consecutivos por el mismo ID / nombre único de usuario y dirección IP. 2. El segundo es el número de intentos fallidos de una dirección IP durante un largo período de tiempo. Por ejemplo, bloquee una dirección IP si realiza 100 intentos fallidos en un día. -**De lo contrario:** Un atacante puede emitir intentos de contraseña automatizados ilimitados para obtener acceso a cuentas privilegiadas en una aplicación +**De lo contrario:** Un atacante puede enviar de manera automatizada ilimitados intentos de contraseña para obtener acceso a cuentas privilegiadas en una aplicación. 🔗 [**Leer más: Limita tasa de login**](./sections/security/login-rate-limit.spanish.md) @@ -909,21 +1215,21 @@ También conocido como correlation id / transit id / tracing id / request id / r -**TL;DR:** Hay un escenario común en el que Node.js se ejecuta como usuario root con permisos ilimitados. Por ejemplo, este es el comportamiento predeterminado en los contenedores Docker. Se recomienda crear un usuario no root y hornearlo en la imagen de Docker (ejemplos a continuación) o ejecutar el proceso en nombre de este usuario invocando el contenedor con la marca "-u username" +**TL;DR:** Hay un escenario común en el que Node.js se ejecuta como usuario root con permisos ilimitados. Por ejemplo, este es el comportamiento predeterminado en los contenedores Docker. Se recomienda crear un usuario no root y utilizarlo en la imagen de Docker (ejemplos a continuación) o ejecutar el proceso en nombre de este usuario invocando el contenedor con el parámetro "-u username" -**De lo contrario:** Un atacante que logra ejecutar un script en el servidor obtiene poder ilimitado sobre la máquina local (por ejemplo, cambiar iptable y redirigir el tráfico a su servidor) +**De lo contrario:** Un atacante que logre ejecutar un script en el servidor obtendrá poder ilimitado sobre la máquina local (por ejemplo, cambiar iptable y redirigir el tráfico a su servidor) 🔗 [**Leer más: Ejecuta Node.js como usuario no root**](./sections/security/non-root-user.spanish.md)

-## ![✔] 6.14. Limita el tamaño de la carga útil utilizando un proxy inverso o un middleware +## ![✔] 6.14. Limita el tamaño del mensaje utilizando un proxy inverso o un middleware -**TL;DR:** Cuanto más grande es la carga útil del cuerpo, más difícil es que su único hilo trabaje en su procesamiento. Esta es una oportunidad para que los atacantes pongan a los servidores de rodillas sin una gran cantidad de solicitudes (ataques DOS / DDOS). Mitiga esto limitando el tamaño del cuerpo de las solicitudes entrantes en el borde (por ejemplo, firewall, ELB) o configurando [express body parser](https://github.com/expressjs/body-parser) para aceptar solo cargas pequeñas +**TL;DR:** Cuanto más grande el body de la petición, más difícil es para el único hilo trabajar en su procesamiento. Esta es una oportunidad para que los atacantes pongan a los servidores de rodillas sin una gran cantidad de solicitudes (ataques DOS / DDOS). Mitiga esto limitando el tamaño del body de las solicitudes entrantes en el perímetro (por ejemplo, firewall, ELB) o configurando [express body parser](https://github.com/expressjs/body-parser) para aceptar solo mensajes pequeños. -**De lo contrario:** Tu aplicación tendrá que lidiar con solicitudes grandes, incapaz de procesar el otro trabajo importante que tiene que realizar, lo que conlleva implicaciones de rendimiento y vulnerabilidad ante los ataques de DOS +**De lo contrario:** Tu aplicación tendrá que lidiar con solicitudes grandes, incapaz de procesar los trabajos importantes que tiene que realizar, lo que conlleva implicaciones de rendimiento y vulnerabilidad ante los ataques de DOS. 🔗 [**Leer más: Limita tamaño de carga**](./sections/security/requestpayloadsizelimit.spanish.md) @@ -933,33 +1239,33 @@ También conocido como correlation id / transit id / tracing id / request id / r -**TL;DR:** `eval` es malo, ya que permite ejecutar código JavaScript personalizado durante el tiempo de ejecución. Esto no es solo un problema de rendimiento, sino también un problema de seguridad importante debido al código JavaScript malicioso que puede obtenerse de la entrada del usuario. Otra característica del lenguaje que debe evitarse es el constructor `new Function`. `setTimeout` y` setInterval` y nunca deberían pasar el código JavaScript dinámico tampoco. +**TL;DR:** `eval` es malo, ya que permite ejecutar código JavaScript personalizado durante el tiempo de ejecución. Esto no es solo un problema de rendimiento, sino también un problema de seguridad importante debido al código JavaScript malicioso que puede obtenerse de la entrada del usuario. Otra característica del lenguaje que debe evitarse es el constructor `new Function`. Tampoco nunca debería pasarsele código JavaScript dinámico a `setTimeout` y `setInterval`. -**De lo contrario:** El código JavaScript malicioso encuentra una forma en el texto pasado a `eval` u otras funciones del lenguaje JavaScript de evaluación en tiempo real, y obtendrá acceso completo a los permisos de JavaScript en la página. Esta vulnerabilidad a menudo se manifiesta como un ataque XSS. +**De lo contrario:** Código malicioso JavaScript encuentrará una forma de texto enviado a `eval` u otras funciones del lenguaje JavaScript de evaluación en tiempo real, y obtendrá acceso completo a los permisos de JavaScript en la página. Esta vulnerabilidad a menudo se manifiesta como un ataque XSS. -🔗 [**Leer más: Evita sentencias eval**](./sections/security/avoideval.spanish.md) +🔗 [**Leer más: Evita sentencias eval de JavaScript**](./sections/security/avoideval.spanish.md)

-## ![✔] 6.16. Evita que el malvado de RegEx sobrecargue tu ejecución de subproceso único +## ![✔] 6.16. Evita que una RegEx maliciosa sobrecargue la ejecución del único hilo -**TL;DR:** Las expresiones regulares, aunque son prácticas, representan una amenaza real para las aplicaciones de JavaScript en general, y para la plataforma Node.js en particular. Una entrada de usuario para que el texto coincida puede requerir una cantidad excepcional de ciclos de CPU para procesar. El procesamiento de RegEx puede ser ineficiente hasta el punto de que una sola solicitud que valida 10 palabras puede bloquear todo el bucle de eventos durante 6 segundos y activar la CPU a 🔥. Por esa razón, escoge paquetes de validación de terceros como [validator.js](https://github.com/chriso/validator.js) en lugar de escribir sus propios patrones Regex, o hacer uso de [safe-regex](https://github.com/substack/safe-regex) para detectar patrones de expresiones regulares vulnerables +**TL;DR:** Las expresiones regulares, aunque son prácticas, representan una amenaza real para las aplicaciones de JavaScript en general, y para la plataforma Node.js en particular. Una entrada de usuario para coincida con un text puede requerir una cantidad excepcional de ciclos de CPU para procesar. El procesamiento de RegEx puede ser ineficiente hasta el punto de que una sola solicitud que valida 10 palabras puede bloquear todo el Event Loop durante 6 segundos y prender 🔥 el CPU. Por esa razón, prefiere el uso de paquetes de validación de terceros como [validator.js](https://github.com/chriso/validator.js) en lugar de escribir tus propios patrones de RegEx, o usa [safe-regex](https://github.com/substack/safe-regex) para detectar patrones de expresiones regulares vulnerables. -**De lo contrario:** Las expresiones regulares mal escritas pueden ser susceptibles a los ataques DoS de Expresión regular que bloquearán el bucle de eventos por completo. Por ejemplo, el popular paquete `moment` fue encontrado vulnerable con el uso malicioso de RegEx en noviembre de 2017 +**De lo contrario:** Las expresiones regulares mal escritas pueden ser susceptibles a los ataques DoS de expresiones regulares que bloquearán el Event Loop por completo. Por ejemplo, el popular paquete `moment` fue encontrado vulnerable al uso malicioso de RegEx en noviembre de 2017 🔗 [**Leer más: Evita RegEx malicioso**](./sections/security/regex.spanish.md)

-## ![✔] 6.17. Evita cargar módulos usando una variable +## ![✔] 6.17. Evita cargar módulos usando variables -**TL;DR:** Evita requerir / importar otro archivo con una ruta que se proporcionó como parámetro debido a la preocupación de que podría haberse originado a partir de la entrada del usuario. Esta regla se puede extender para acceder a archivos en general (es decir, `fs.readFile ()`) u otro acceso a recursos confidenciales con variables dinámicas que se originan a partir de la entrada del usuario. [Eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security) linter puede atrapar tales patrones y advertirlo de manera temprana +**TL;DR:** Evita requerir / importar otro archivo con una ruta que se proporcionó como parámetro debido a la preocupación de que podría haberse originado a partir de una entrada de usuario. Esta regla se puede extender para acceder a archivos en general (es decir, `fs.readFile ()`) u otros recursos confidenciales mediante variables dinámicas que se generan a partir de la entrada del usuario. El plugin de linter [Eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security) puede atrapar tales patrones y advertirlo de manera temprana. -**De lo contrario:** La entrada de usuario malintencionado podría encontrar su camino hacia un parámetro que se utiliza para requerir archivos manipulados, por ejemplo, un archivo cargado previamente en el sistema de archivos, o acceder a archivos del sistema ya existentes. +**De lo contrario:** La entrada de usuario malintencionado podría encontrar su camino hacia un parámetro que se utiliza para requerir archivos manipulados, por ejemplo, un archivo cargado previamente en el sistema de archivos, o acceder a archivos ya existentes del sistema. 🔗 [**Leer más: Carga de módulos segura**](./sections/security/safemoduleloading.spanish.md) @@ -977,11 +1283,11 @@ También conocido como correlation id / transit id / tracing id / request id / r

-## ![✔] 6.19. Ten mucho cuidado al trabajar con procesos secundarios. +## ![✔] 6.19. Ten especial cuidado al trabajar con procesos secundarios -**TL;DR:** Evita el uso de procesos secundarios cuando sea posible y valide y desinfecta la entrada para mitigar los ataques de inyección de shell si aún tienes que hacerlo. Usa `child_process.execFile` que, por definición, solo ejecutará un solo comando con un conjunto de atributos y no permitirá la expansión de parámetros de shell. +**TL;DR:** Evita el uso de procesos secundarios cuando sea posible y valida y sanitiza la entrada para mitigar los ataques de inyección de shell si aún tienes que hacerlo. Usa `child_process.execFile` que, por definición, solo ejecutará un solo comando con un conjunto de atributos y no permitirá la expansión de parámetros de shell. **De lo contrario:** El uso ingenuo de procesos secundarios podría provocar la ejecución remota de comandos o ataques de inyección de shell debido a la entrada maliciosa del usuario transmitida a un comando del sistema no desinfectado. @@ -989,15 +1295,15 @@ También conocido como correlation id / transit id / tracing id / request id / r

-## ![✔] 6.20. Ocultar detalles de error de los clientes +## ![✔] 6.20. Oculta los detalles de error de los clientes -**TL;DR:** Un controlador de error express integrado oculta los detalles del error de forma predeterminada. Sin embargo, son grandes las posibilidades de que implemente su propia lógica de manejo de errores con objetos de error personalizados (considerado por muchos como una práctica recomendada). Si lo haces, asegúrate de no devolver todo el objeto Error al cliente, que podría contener algunos detalles confidenciales de la aplicación +**TL;DR:** Un manejador de error express integrado oculta por defecto los detalles de un error. Sin embargo, son grandes las posibilidades de que implementes tu propia lógica de manejo de errores con objetos de error personalizados (considerado por muchos como una práctica recomendada). Si lo haces, asegurate de no devolver todo el objeto Error al cliente, el cual podría contener algunos detalles confidenciales de la aplicación -**De lo contrario:** Los detalles confidenciales de la aplicación, como las rutas de archivos del servidor, los módulos de terceros en uso y otros flujos de trabajo internos de la aplicación que podrían ser explotados por un atacante, podrían filtrarse de la información encontrada en un seguimiento de la pila. +**De lo contrario:** Los detalles confidenciales de la aplicación, como las rutas de archivos del servidor, los módulos de terceros en uso y otros flujos de trabajo internos de la aplicación que podrían ser explotados por un atacante podrían filtrarse de la información encontrada en un stack trace. -🔗 [**Leer más: Oculta detalles de error de los cliente**](./sections/security/hideerrors.spanish.md) +🔗 [**Leer más: Oculta los detalles de error de los clientes**](./sections/security/hideerrors.spanish.md)

@@ -1005,13 +1311,13 @@ También conocido como correlation id / transit id / tracing id / request id / r -**TL;DR:** Cualquier paso en la cadena de desarrollo debe protegerse con MFA (autenticación multifactor), npm / Yarn es una buena oportunidad para los atacantes que pueden tener en sus manos la contraseña de algún desarrollador. Utilizando credenciales de desarrollador, los atacantes pueden inyectar código malicioso en bibliotecas que están ampliamente instaladas en proyectos y servicios. Tal vez incluso en la web si se publica en público. Habilitar la autenticación de 2 factores en npm deja casi cero posibilidades para que los atacantes alteren el código de su paquete. +**TL;DR:** Cualquier paso en la cadena de desarrollo debe protegerse con MFA (autenticación multifactor), npm / Yarn son una buena oportunidad para los atacantes para obtener la contraseña de algún desarrollador. Utilizando las credenciales de un desarrollador, los atacantes pueden inyectar código malicioso en bibliotecas que están ampliamente instaladas en proyectos y servicios. Tal vez incluso en la web si es pública. Habilitar la autenticación de 2 factores en npm y Yarn deja casi cero posibilidades para que los atacantes alteren el código de su paquete. -**De lo contrario:** [¿Has oído hablar del desarrollador de eslint cuya contraseña fue secuestrada?](https://medium.com/@oprearocks/eslint-backdoor-what-it-is-and-how-to-fix-the-issue-221f58f1a8c8) +**De lo contrario:** [¿Has oído hablar del desarrollador de eslint cuya contraseña fue robada?](https://medium.com/@oprearocks/eslint-backdoor-what-it-is-and-how-to-fix-the-issue-221f58f1a8c8)

-## ![✔] 6.22. Modificar la configuración del middleware de sesión +## ![✔] 6.22. Modifica la configuración del middleware de sesión @@ -1019,21 +1325,21 @@ También conocido como correlation id / transit id / tracing id / request id / r **De lo contrario:** Las cookies podrían enviarse a través de conexiones inseguras, y un atacante podría usar la identificación de sesión para identificar el framework subyacente de la aplicación web, así como las vulnerabilidades específicas del módulo -🔗 [**Leer más: Seguridad de Cookies y sesiones**](./sections/security/sessions.spanish.md) +🔗 [**Leer más: Seguridad de cookies y sesiones**](./sections/security/sessions.spanish.md)

-## ![✔] 6.23. Evita los ataques de DOS estableciendo explícitamente cuándo debe fallar un proceso +## ![✔] 6.23. Evita los ataques de DoS estableciendo explícitamente cuándo debe fallar un proceso -**TL;DR:** El proceso de Node se bloqueará cuando no se manejen los errores. Muchas de las mejores prácticas incluso recomiendan salir a pesar de que se detectó un error y se manejó. Express, por ejemplo, se bloqueará en cualquier error asíncrono, a menos que ajuste las rutas con una cláusula catch. Esto abre un punto de ataque muy dulce para los atacantes que reconocen qué información hace que el proceso se bloquee y envían repetidamente la misma solicitud. No hay remedio instantáneo para esto, pero algunas técnicas pueden mitigar el dolor: alerta con severidad crítica cada vez que un proceso se bloquea debido a un error no controlado, valida la entrada y evita que el proceso se bloquee debido a una entrada inválida del usuario, envuelve todas las rutas con una captura y considera no bloquearse cuando se origine un error dentro de una solicitud (en oposición a lo que sucede globalmente) +**TL;DR:** El proceso de Node se caerá cuando no se manejen los errores. Muchas de las mejores prácticas incluso recomiendan salir a pesar de que se detectó un error y se manejó. Express, por ejemplo, se caerá en cualquier error asíncrono, a menos que ajuste las rutas con una cláusula catch. Esto abre un punto de ataque muy atractivo para los atacantes que reconocen qué información hace que el proceso se caiga y envían repetidamente la misma solicitud. No hay remedio instantáneo para esto, pero algunas técnicas pueden mitigar el dolor: alerta con severidad crítica cada vez que un proceso se caiga debido a un error no controlado, valida la entrada y evita que el proceso se caiga debido a una entrada inválida del usuario, envuelve todas las rutas con un try/catch y considera no romper cuando se origine un error dentro de una solicitud (en oposición a lo que sucede globalmente) -**De lo contrario:** Esto es solo una suposición educada: dadas muchas aplicaciones de Node.js, si intentamos pasar un cuerpo JSON vacío a todas las solicitudes POST, un puñado de aplicaciones se bloqueará. En ese momento, podemos repetir el envío de la misma solicitud para eliminar las aplicaciones con facilidad +**De lo contrario:** Esto es solo una suposición educada: dadas muchas aplicaciones de Node.js, si intentamos pasar un cuerpo JSON vacío a todas las solicitudes POST, un puñado de aplicaciones se caerá. En ese momento, podemos repetir el envío de la misma solicitud para tirar las aplicaciones con facilidad

-## ![✔] 6.24. Prevenir redireccionamientos inseguros +## ![✔] 6.24. Evita redirecciones inseguras @@ -1041,7 +1347,7 @@ También conocido como correlation id / transit id / tracing id / request id / r **De lo contrario:** Si un atacante descubre que no está validando entradas externas proporcionadas por el usuario, puede aprovechar esta vulnerabilidad al publicar enlaces especialmente diseñados en foros, redes sociales y otros lugares públicos para que los usuarios hagan clic en él. -🔗 [**Leer más: Evita redireccionamientos inseguros**](./sections/security/saferedirects.spanish.md) +🔗 [**Leer más: Evita redirecciones inseguras**](./sections/security/saferedirects.spanish.md)

@@ -1049,40 +1355,70 @@ También conocido como correlation id / transit id / tracing id / request id / r -**TL;DR:** Se deben tomar precauciones para evitar el riesgo de publicar accidentalmente secretos en registros públicos de npm. Se puede usar un archivo `.npmignore` para poner en una lista negra archivos o carpetas específicos, o el arreglo `files` en `package.json` puede actuar como una lista blanca. +**TL;DR:** Se deben tomar precauciones para evitar el riesgo de publicar accidentalmente secretos en registros públicos de npm. Puedes utilizar el archivo `.npmignore` para ignorar archivos o carpetas específicos, o el listado `files` en `package.json` puede actuar como una lista de permitidos. -**De lo contrario:** Las claves de API, las contraseñas u otros secretos de su proyecto están abiertos a ser abusados por cualquier persona que los encuentre, lo que puede provocar pérdidas financieras, suplantación y otros riesgos. +**De lo contrario:** Las claves de API, las contraseñas u otros secretos de su proyecto están abiertos a ser abusados por cualquier persona que los encuentre, lo que puede provocar pérdidas financieras, suplantación de identidad y otros riesgos. 🔗 [**Leer más: Evita publicar secretos**](./sections/security/avoid_publishing_secrets.spanish.md) +

+ +## ![✔] 6.26 Inspecciona los paquetes obsoletos + +**TL;DR:** Usa tu herramienta preferida (e.g. 'npm outdated' o [npm-check-updates](https://www.npmjs.com/package/npm-check-updates) para detectar paquetes instalados que están desactualizados, inyecta esta verificación en tu CI e incluso haz que la construcción falle en un escenario grave. Por ejemplo, un escenario grave podría ser cuando un paquete instalado tiene 5 parches confirmados (por ejemplo, la versión local es 1.3.1 y la versión del repositorio es 1.3.8) o está etiquetado como obsoleto por su autor: elimine la construcción y evite implementar esa versión + +**De lo contrario:** Su producción ejecutará paquetes que han sido etiquetados explícitamente por su autor como riesgosos +

+ +## ![✔] 6.27. Importa los módulos integrados utilizando el protocolo 'node:' + +### `🌟 #new` + + + +**TL;DR:** Importe o requiere los módulos Node.js integrados utilizando la sintaxis de 'protocolo node': + +```javascript +import { functionName } from "node:module"; // observa el prefijo 'node:' +``` + +Por ejemplo: + +```javascript +import { createServer } from "node:http"; +``` + +Este estilo garantiza que no haya ambigüedad con los paquetes npm globales y deja claro al lector que el código se refiere a un módulo oficial de confianza. Este estilo se puede aplicar con la regla de eslint ['prefer-node-protocol'](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-node-protocol.md). + +**De lo contrario:** El uso de la sintaxis de importación sin el prefijo 'node:' abre la puerta a [ataques de typosquatting](https://en.wikipedia.org/wiki/Typosquatting) donde uno podría escribir mal el nombre de un módulo (por ejemplo, 'event' en lugar de ' events) y obtener un paquete malicioso creado únicamente para engañar a los usuarios para que los instalen. +


⬆ Volver arriba

# `7. Borrador: Mejores prácticas de rendimiento` -## Nuestros colaboradores están trabajando en esta sección. [¿Te gustaría unirte?](https://github.com/i0natan/nodebestpractices/issues/256) +## Nuestros colaboradores están trabajando en esta sección. [¿Te gustaría unirte?](https://github.com/goldbergyoni/nodebestpractices/issues/256)

## ![✔] 7.1. No bloquees el bucle de eventos -**TL;DR:** Evita las tareas intensivas de la CPU, ya que bloquearán el bucle de eventos en su mayoría de un solo subproceso y descargalas en un subproceso dedicado, proceso o incluso una tecnología diferente según el contexto. +**TL;DR:** Evita las tareas intensivas de la CPU ya que bloquearán el Event Loop mayormente de un único hilo y descargalas en un hilo o proceso dedicado o incluso a una tecnología diferente según el contexto. -**De lo contrario:** A medida que se bloquea el bucle de eventos, Node.js no podrá manejar otra solicitud, lo que provocará demoras para los usuarios concurrentes. **3000 usuarios están esperando una respuesta, el contenido está listo para ser servido, pero una sola solicitud impide que el servidor envíe los resultados** +**De lo contrario:** A medida que se bloquea el Event Loop Node.js no podrá manejar otra solicitud lo que provocará demoras para los usuarios concurrentes. **3000 usuarios están esperando una respuesta, el contenido está listo para ser servido, pero una sola solicitud impide que el servidor envíe los resultados** -🔗 [**Leer más: No bloquees el bucle de eventos**](./sections/performance/block-loop.spanish.md) - -


+🔗 [**Leer más: No bloquees el Event Loop**](./sections/performance/block-loop.spanish.md) +

-## ![✔] 7.2. Escoge los métodos JS nativos sobre las utilidades de usuario como Lodash +## ![✔] 7.2. Prefiere los métodos nativos a los de utilidades de usuario como Lodash -**TL;DR:** A menudo es más penalizador usar bibliotecas de utilidades como `lodash` y ` underscore` sobre los métodos nativos, ya que conduce a dependencias innecesarias y un rendimiento más lento. -Ten en cuenta que con la introducción del nuevo motor V8 junto con los nuevos estándares ES, los métodos nativos se mejoraron de tal manera que ahora es aproximadamente un 50% más eficiente que las bibliotecas de servicios públicos. +**TL;DR:** A menudo penaliza más usar bibliotecas de utilidades como `lodash` y ` underscore` sobre los métodos nativos, ya que conduce a dependencias innecesarias y un rendimiento más lento. +Ten en cuenta que con la introducción del nuevo motor V8 junto con los nuevos estándares ES, los métodos nativos se mejoraron de tal manera que ahora es aproximadamente un 50% más eficiente que las bibliotecas de utilidades. -**De lo contrario:** Tendrás que mantener proyectos de menor rendimiento en los que simplemente podría haber usado lo que **ya estaba** disponible o haber tratado algunas líneas más a cambio de algunos archivos más. +**De lo contrario:** Tendrás que mantener proyectos de menor rendimiento en los que simplemente podría haber usado lo que **ya estaba** disponible o haber lideado en tu código con algunas líneas más a cambio de algunos archivos más. -🔗 [**Leer más: Nativo sobre implementaciones externas**](./sections/performance/nativeoverutil.spanish.md) +🔗 [**Leer más: Nativo por sobre utilidades externas**](./sections/performance/nativeoverutil.spanish.md)


@@ -1094,11 +1430,11 @@ Ten en cuenta que con la introducción del nuevo motor V8 junto con los nuevos e

-## ![✔] 8.1. Utilice compilaciones de múltiples etapas para obtener imágenes de Docker más sencillas y seguras +## ![✔] 8.1. Usa compilaciones de múltiples etapas para obtener imágenes de Docker más sencillas y seguras -**TL;DR:** Utilice la compilación de múltiples etapas para copiar únicamente los artefactos de producción necesarios. Un montón de dependencias y archivos de tiempo de compilación no son necesarios para ejecutar tu aplicación. Haciendo uso de compilaciones de múltiples etapas, estos recursos pueden ser utilizados durante la compilación mientras que el entorno de tiempo de ejecución sólo contiene lo necesario. Las compilaciones de múltiples etapas representan una forma sencilla de deshacerse del sobrepeso y las amenazas de seguridad. +**TL;DR:** Utilice la compilación de múltiples etapas para copiar únicamente los artefactos de producción necesarios. Un montón de las dependencias y archivos de tiempo de compilación no son necesarios para ejecutar tu aplicación. Haciendo uso de compilaciones de múltiples etapas, estos recursos pueden ser utilizados durante la compilación mientras que el entorno de ejecución sólo contiene lo necesario. Las compilaciones de múltiples etapas representan una forma sencilla de deshacerse del sobrepeso y las amenazas de seguridad. -**De lo contrario:** Las imágenes más grandes tomarán más tiempo en compilar y desplegarse, las herramientas de solo compilación pueden contener vulnerabilidades y los secretos que solo están destinados a la fase de compilación pueden ser filtrados. +**De lo contrario:** Las imágenes más grandes tomarán más tiempo en compilar y desplegarse, las herramientas de solo compilación pueden contener vulnerabilidades y secretos que solo están destinados a la fase de compilación y pueden ser filtrados. ### Dockerfile de ejemplo para compilaciones de múltiples etapas @@ -1108,6 +1444,7 @@ FROM node:14.4.0 AS build COPY . . RUN npm ci && npm run build + FROM node:slim-14.4.0 USER node @@ -1119,150 +1456,155 @@ RUN npm ci --production CMD [ "node", "dist/app.js" ] ``` -🔗 [**Leer más: Utilice compilaciones múltiples**](./sections/docker/multi_stage_builds.spanish.md) +🔗 [**Leer más: Utilice compilaciones de múltiples etapas**](./sections/docker/multi_stage_builds.spanish.md) -


+

-## ![✔] 8.2. Arranque usando el comando `node`, evita `npm start` +## ![✔] 8.2. Arranca usando el comando `node`, evita `npm start` -**TL;DR:** usa `CMD ['node', 'server.js']` para iniciar su aplicación, evita usar los scripts de npm, los cuales no pasan señales del sistema operativo (OS) al código. Para prevenir estos problemas en los procesos secundarios, manejo de señales y apagado simple sin tener procesos zombie. +**TL;DR:** Usa `CMD ['node', 'server.js']` para iniciar su aplicación, evita usar los scripts de npm, los cuales no pasan señales del sistema operativo (OS) al código. Esto previene problemas en los procesos hijo, manejo de señales, apagado elegante y procesos zombie. -**De lo contrario** Cuando no se pasan señales, su código nunca será notificado cuando se detenga el proceso, Sin esto, Se perderá la oportunidad de cerrar de manera apropiada, posiblemente perdiendo peticiones o datos actuales. +Update: [A partir de npm 7, npm afirma](https://docs.npmjs.com/cli/v7/using-npm/changelog#706-2020-10-27) pasar señales. Lo seguiremos y actualizaremos consecuentemente. -🔗 [**Leer más: Arranque usando node, evite npm start**](./sections/docker/bootstrap-using-node.spanish.md) +**De lo contrario** Cuando no se pasan señales, su código nunca será notificado del apagado. Sin esto, se perderá la oportunidad de cerrar de manera apropiada, posiblemente perdiendo peticiones o datos actuales. +🔗 [**Leer más: Arranca el contenedor usando node, evita npm start**](./sections/docker/bootstrap-using-node.spanish.md) -


+

-## ![✔] 8.3. Permite a Docker manejar replicación y tiempo de ejecución +## ![✔] 8.3. Permite al entorno de ejecución de Docker manejar la replicación y el tiempo de actividad -**TL;DR:** Cuando se usa un manejador de tiempo de ejecución de Docker (Por ejemplo, Kubernetes), invoque el proceso de Node.js directamente, sin manejadores de proceso intermedios o código personalizado que replica el proceso (Por ejemplo, PM2, Cluster Module). La plataforma de tiempo de ejecución tiene la mayor cantidad de datos y visibilidad al hacer la decisión de posicionamiento: Sabe mejor que nadie cuantos procesos son necesarios, como distribuirlos y que hacer en caso de errores. +**TL;DR:** Cuando se usa un orquestador de Docker en tiempo de ejecución (por ejemplo, Kubernetes), invoca el proceso de Node.js directamente intermediación de manejadores de proceso o código personalizado que replica el proceso (por ejemplo, PM2, Cluster Module). La plataforma de tiempo de ejecución tiene la mayor cantidad de datos y visibilidad para hacer la decisión de colocación. Sabe mejor que nadie cuantos procesos son necesarios, como distribuirlos y que hacer en caso de errores. -**De lo contrario** El contenedor sigue cayendo debido a la escasez de recursos se estará reiniciando de manera indefinida por el manejador de procesos. Si Kubernetes supiera esto, lo podría redirreccionar a una instancia diferente. +**De lo contrario** El contenedor seguirá cayendo debido a la escasez de recursos y el manejador de procesos lo estará reiniciando de indefinidamente. Si Kubernetes supiera esto, lo podría redirreccionar a una instancia diferente. -🔗 [**Leer más: Permita al manejador Docker reiniciar y replicar procesos**](./sections/docker/restart-and-replicate-processes.spanish.md) +🔗 [**Leer más: Permita al orquestador de Docker reiniciar y replicar procesos**](./sections/docker/restart-and-replicate-processes.spanish.md) -


+

-## ![✔] 8.4. Utilize .dockerignore para prevenir fuga de secretos +## ![✔] 8.4. Usa .dockerignore para evitar la fuga de secretos -**TL;DR:** Incluye un archivo `.dockerignore` que filtra todos los archivos con secretos comúnes y artefactos de desarrollo. Al hacer esto. Puede evitar que sus secretos salgan a la luz. Ademas el tiempo de compilación se va a reducir de manera significante. También asegúrese de no copiar todos los archivos recursivamente, mejor selecciones cuales deben ser copiados a docker de manera explícita. +**TL;DR:** Incluye un archivo `.dockerignore` que filtre todos los archivos con secretos comúnes y artefactos de desarrollo. Al hacer esto, podrías evitar que tus secretos salgan a la luz. Adicionalmente, el tiempo de compilación se va a reducir significavimanente. También asegúrese de no copiar todos los archivos recursivamente, mejor selecciones cuales deben ser copiados a docker de manera explícita. -**De lo contrario** Archivos comúnes de secretos como `.env`, `.aws`, y `.npmrc` serán compartidos con cualquiera que tenga acceso a la imágen (Por ejemplo un repositorio Docker). +**De lo contrario** Archivos comúnes de secretos como `.env`, `.aws`, y `.npmrc` serán compartidos con cualquiera que tenga acceso a la imágen (por ejemplo un repositorio Docker). -🔗 [**Leer más: Utiliza .dockerignore**](./sections/docker/docker-ignore.spanish-md) +🔗 [**Leer más: Usa .dockerignore**](./sections/docker/docker-ignore.spanish-md) -


+

-## ![✔] 8.5. Limpie dependencias antes de ir a producción +## ![✔] 8.5. Limpia las dependencias antes de ir a producción -**TL;DR:** Aunque algunas dependencias de desarrollo son necesarios durante los ciclos de compilación y prueba, eventualmente la imágen que será enviada a producción debe estar los mas limpia posible de dependencias de desarrollador. Haciendo esto garantiza que solo el código necesario es cargado y la cantidad de ataques potenciales (Por ejemplo. attack surface (ataque de superficie)) sea mínimo. Cuando se use compilación multi-pasos (Vea punto dedicado) esto puede ser logrado al instalar todas las dependencias primero y finalmente ejecutar `npm ci --production`. +**TL;DR:** Aunque algunas dependencias de desarrollo son necesarios durante los ciclos de compilación y prueba, eventualmente la imágen que será enviada a producción debe estar los mas limpia posible de dependencias de desarrollador. Haciendo esto garantizas que solo el código necesario es cargado y la cantidad de ataques potenciales (es decir la superficie de ataque) sea mínimo. Cuando use scompilación multi-pasos (vea punto dedicado) esto se puede lograr instalando todas las dependencias primero y finalmente ejecutar `npm ci --production`. -**De lo contrario** Muchas brechas de seguridad conocidas fueron encontradas dentro de paquetes de desarrollo (Por ejemplo. [eslint-scope](https://eslint.org/blog/2018/07/postmortem-for-malicious-package-publishes)). +**De lo contrario** Muchas violaciones de seguridad conocidas fueron encontradas dentro de paquetes de desarrollo (por ejemplo, [eslint-scope](https://eslint.org/blog/2018/07/postmortem-for-malicious-package-publishes)). -🔗 [**Leer más: Remueva dependencias de desarrollo**](./sections/docker/install-for-production.spanish.md) +🔗 [**Leer más: Remueva las dependencias de desarrollo**](./sections/docker/install-for-production.spanish.md) -


+

-## ![✔] 8.6. Apague de manera inteligente y gentil +## ![✔] 8.6. Apaga de manera inteligente y elegante -**TL;DR:** Maneje el evento de proceso SIGTERM y limpie todas las conexiones existentes y recursos. Esto debería hacerse mientra se responden a peticiones activas. En tiempos de ejecución de Docker, apagar contenedores no es un evento raro, sino un evento frecuente que es parte de una rutina de trabajo. Hacer esto requiere un código bien pensado para manejar muchas partes separadas: El balance de carga, mantener las conexiones, el servidor HTTP y otros recursos. +**TL;DR:** Maneja el evento de proceso SIGTERM y limpia todas las conexiones existentes y recursos. Esto debería hacerse mientra se responden a peticiones activas. En entornos de ejecución de dockerizados, apagar contenedores no es un evento raro, sino un evento frecuente que es parte de una rutina de trabajo. Hacer esto requiere un código bien pensado para manejar muchas partes separadas: el balanceo de carga, mantener las conexiones, el servidor HTTP y otros recursos. -**De lo contrario** Apagando de manera inmediata significa no responder a cientos de usuarios decepcionados. +**De lo contrario** Apagar de manera inmediata significa no responder a cientos de usuarios decepcionados. -🔗 [**Leer más: Apagado gentil**](./sections/docker/graceful-shutdown.spanish.md) +🔗 [**Leer más: Apagado elegante**](./sections/docker/graceful-shutdown.spanish.md) -


+

-## ![✔] 8.7. Asigne límites de memoria utilizando Docker y v8 +## ![✔] 8.7. Establece límites de memoria utilizando Docker y v8 -**TL;DR:** Siempre configure un límite de memoria utilizando Docker y las marcas de tiempo de ejecución de JavaScript. El límite de Docker es necesario para hacer decisiones de posicionamiento bien pensadas, la marca --v8 max-old-space es necesaria para arrancar el GC a tiempo y prevenir desperdicio de recursos. En la práctica, asignale a la marca max-old-space de v8 un tamaño un poco menor al límite del contenedor. +**TL;DR:** Siempre configura los límites de memoria utilizando tanto Docker como los parámetros de ejecución de JavaScript. El límite de Docker es necesario para hacer decisiones de colocación bien pensadas, el parámetro --v8 max-old-space es necesaria para arrancar el Garbage Collector a tiempo y prevenir subutilización de memoria. En la práctica, asignale al parámetro max-old-space de v8 un tamaño un poco menor al límite del contenedor. -**De lo contrario** La definición de Docker es necesaria para realizar decisiones bien pensadas de escalación y prevenir la escasez para otros procesos. Si tampoco defines los límites de v8, no va a utilizar completamente los recursos de contenedor; Sin instrucciones explícitas, se colapsará cuando se use ~50-60% de los recursos del host +**De lo contrario** La definición de Docker es necesaria para realizar decisiones bien pensadas de escalación y prevenir la escasez para otros procesos. Si tampoco defines los límites de v8, no va a utilizar completamente los recursos del contenedor. Sin instrucciones explícitas, se caerá cuando se use ~50-60% de los recursos del host. -🔗 [**Leer más: Asigne límites de memoria en Docker**](./sections/docker/memory-limit.spanish.md) +🔗 [**Leer más: Establece límites de memoria utilizando solo Docker**](./sections/docker/memory-limit.spanish.md) -


+

-## ![✔] 8.8. Planee caché eficientemente +## ![✔] 8.8. Planifica un almacenamiento en caché eficiente -**TL;DR:** Re-compilar toda la imágen de Docker mediante caché puede ser casi instantáneo si se hace correctamente. Las instrucciones que se actualizan con menor frecuencia deben estar hasta arriba en su Dockerfile y las que cambian constantemente (Como el código de la aplicación) deberían estar hasta abajo. +**TL;DR:** Re-compilar toda la imágen de Docker mediante caché puede ser casi instantáneo si se hace correctamente. Las instrucciones que se actualizan con menor frecuencia deben estar en la parte superior de su Dockerfile y las que cambian constantemente (como el código de la aplicación) deberían estar en la parte inferior. **De lo contrario** La compilación de Docker va a ser muy larga y consumir demasiados recursos, incluso al hacer cambios menores. 🔗 [**Leer más: Maneje el caché para reducir tiempos de compilación**](./sections/docker/use-cache-for-shorter-build-time.spanish.md) -


+

-## ![✔] 8.9. Utilize imágen de referencia explícita, evite la etiqueta `latest` +## ![✔] 8.9. Utiliza una referencia de imagen explícita, evita la etiqueta `latest` -**TL;DR:** Especifíque la etiqueta de versión de la imágen de manera explícita, nunca utilice `latest`. Desarrolladores piensan que al especificar la etiqueta `latest` recibirán la imágen mas reciente del repositorio, Sin embargo, este no es el caso, Usando una explícita garantiza que cada instancia del servicio esta corriendo exactamente el mismo código. +**TL;DR:** Especifíca la etiqueta de versión de la imágen de manera explícita, nunca utilices `latest`. Desarrolladores piensan que al especificar la etiqueta `latest` recibirán la imágen mas reciente del repositorio. Sin embargo, este no es el caso. Usando un digest garantiza que cada instancia del servicio ejecute exactamente el mismo código. -Como extra, refiriéndose a una etiqueta de imágen significa que la imágen base esta sujeta a cambios, por ello las etiquetas de imágen no pueden ser confiables para una instalación determinista. En su lugar, si se espera un instalación determinista una SHA256 puede ser usada como referencia a la imágen exacta. +Además, hacer referencia a una etiqueta de imagen significa que la imagen base está sujeta a cambios, ya que no se puede confiar en las etiquetas de imagen para una instalación determinista. En cambio, si se espera una instalación determinista, se puede utilizar un digest SHA256 para hacer referencia a una imagen exacta. **De lo contrario** Una nueva versión de la imágen base puede ser desplegada a producción con cambios severos, causando comportamiento anormal. -🔗 [**Leer más: Entender las etiquetas de imágen y utilizar las etiqueta "lates" con precaución**](./sections/docker/image-tags.spanish.md) +🔗 [**Leer más: Entendiendo las etiquetas de imágen y usar la etiqueta "latest" con precaución**](./sections/docker/image-tags.spanish.md) -


+

-## ![✔] 8.10. Utilize imágenes base pequeñas +## ![✔] 8.10. Prefiere imágenes base de Docker pequeñas -**TL;DR:** Imágenes grandes conducen a una mayor exposición de vulnerabilidades y a un aumento del uso de recursos. Usando imágenes mas apoyadas como Slim y Alpine Linux reduce este problema. +**TL;DR:** Imágenes grandes conducen a una mayor exposición de vulnerabilidades y a un aumento en el uso de recursos. Usando imágenes mas livianas como Slim y Alpine Linux reduce este problema. -**De lo contrario** Compilar, enviar y recibir cambios de imágenes va a tomar mas tiempo, terceros pueden utilizar ataques de vectores desconocidos y consumir mar recursos. +**De lo contrario** Compilar, enviar y recibir cambios de imágenes va a tomar más tiempo, terceros maliciosos pueden utilizar vectores de ataque desconocidos y más recursos son consumidos. -🔗 [**Leer más: Utilice imágenes pequeñas**](./sections/docker/image-tags.spanish.md) +🔗 [**Leer más: Usa imágenes pequeñas**](./sections/docker/image-tags.spanish.md) -


+

-## ![✔] 8.11. Limpie secretos en tiempo de compilación, evite secretos en argumentos +## ![✔] 8.11. Limpia los secretos de tiempo de compilación, evita los secretos en args -**TL;DR:** Evite la fuga de secretos en el entorno compilación de Docker. Una imágen de Docker normalmente es compartida por multiples entornos como CI y un registro que no está tan limpio como producción. Un ejemplo común is un token npm que suele ser pasado a dockerfile como argumento. Este token permanece en la imágen después de ser utilizada y permite al atacante acceso indefinido a un registro npm privado. Esto puede ser evitado al copiar un archivo secreto como `.npmrc` y después removiéndolo usando la compilación multi-pasos (Cuidado, la historia de compilación debe ser borrada también) o usando el build-kit de Docker que no deja ningún rastro. +### `🌟 #new` + +**TL;DR:** Evita la fuga de secretos en el entorno compilación de Docker. Una imágen de Docker normalmente es compartida por multiples entornos como CI y un registro que no está tan limpio como producción. Un ejemplo común es un token npm que suele ser pasado al dockerfile como argumento. Este token permanece en la imágen después de ser utilizada y permite al atacante acceso indefinido a un registro npm privado. Esto puede ser evitado copiando el secreto a un archivo como `.npmrc` y después removiéndolo con la compilación multi-pasos (cuidado, la historia de la compilación también debe ser borrada) o usando el Docker build-kit que no deja ningún rastro. **De lo contrario** Cualquiera con acceso al CI y al registro Docker también tendrá acceso a unos preciosos secretos de la empresa como regalo. 🔗 [**Leer más: Limpia tus secretos de tiempo de compilación**](./sections/docker/avoid-build-time-secrets.spanish.md) -


+

-## ![✔] 8.12. Escanea imágenes para vulnerabilidades multi-capa +## ![✔] 8.12. Escanea las imágenes en busca de vulnerabilidades multi-capas -**TL;DR:** Además de revisar vulnerabilidades de las dependencias, escanee la imágen final que será enviada a producción, Los escáneres de imágen de Docker revisan las dependencias del código, pero también los binarios del sistema operativo (OS binaries). Este escaneo de seguridad de punto a punto abarca mas espacio y verifica que nadie haya implantado cosas maliciosas durante la compilación. Consecuentemente, se recomienda hacer esto como último paso antes del despliegue. Hay una buena cantidad de escáneres gratuitos y de paga que también proporcionan extensiones CI/CD. +**TL;DR:** Además de revisar vulnerabilidades en las dependencias también escanea la imágen final que será enviada a producción. Los escáneres de imágenes Docker revisan las dependencias del código, pero también los binarios del sistema operativo (OS binaries). Este escaneo de seguridad de punta a punta cubre más terreno y verifica que nadie haya implantado cosas maliciosas durante la compilación. Consecuentemente, se recomienda hacer esto como último paso antes del despliegue. Hay una buena cantidad de escáneres gratuitos y comerciales que también proporcionan extensiones para CI/CD. -**De lo contrario** Su código puede estar completamente libre de vulnerabilidades. Pero puede llegar a ser hackeado debido a una version vulnerable de los binarios a nivel SO (Por ejemplo. OpenSSL, TarBall), los cuales son usados comúnmente por las aplicaciones. +**De lo contrario** Tu código puede estar completamente libre de vulnerabilidades. Sin embardo puede aún ser hackeado debido a una version vulnerable de los binarios a nivel SO (por ejemplo: OpenSSL, TarBall) los cuales son usados comúnmente por las aplicaciones. 🔗 [**Leer más: Escanea la imágen completa antes de producción**](./sections/docker/scan-images.spanish.md) -


+

-## ![✔] 8.13. Limpie el caché de NODE_MODULE +## ![✔] 8.13. Limpia la caché de NODE_MODULE -**TL;DR:** Después de instalar dependencias en un contenedor remueva el caché local. No tiene sentido duplicar las dependencias para instalaciones mas rápidas futuras, debido a que no habrá instalaciones futuras. Una imágen de Docker is inmutable. Utilizando una sola línea de código decenas de MB (normalmente ~10-50% del tamaño de la imágen) son podados. +**TL;DR:** Después de instalar dependencias en un contenedor remueve el caché local. No tiene sentido duplicar las dependencias para instalaciones mas rápidas futuras, debido a que no habrá instalaciones futuras. Una imágen de Docker es inmutable. Utilizando una sola línea de código decenas de MB (normalmente ~10-50% del tamaño de la imágen) son podados. -**De lo contrario** La imágen que será enviada a producción pesara un 30% extra debido a archivos que no serán utilizados. +**De lo contrario** La imágen que será enviada a producción pesará un 30% extra debido a archivos que jamás serán utilizados. -🔗 [**Leer más: Limpie el caché de NODE_MODULE**](./sections/docker/clean-cache.spanish.md) +🔗 [**Leer más: Limpia el caché de NODE_MODULE**](./sections/docker/clean-cache.spanish.md) -


+

-## ![✔] 8.14. Prácticas de Docker generales +## ![✔] 8.14. Prácticas generales de Docker -**TL;DR:** Esta es una colección de los consejos de Docker que no están relacionados directamente con Docker: La implementación de Docker no es muy diferente a cualquier otro lenguaje, Da click en leer más para mas información. +**TL;DR:** Esta es una colección de consejos de Docker que no están relacionados directamente con Node.js. La implementación para Node no es muy diferente a la de cualquier otro lenguaje. Haz clic en "Leer más" para hojearlo. 🔗 [**Leer más: Prácticas de Docker generales](./sections/docker/generic-tips.spanish.md) -


+

-## ![✔] 8.15. utilize Lint en su Dockerfile +## ![✔] 8.15. Usa un linter en tu Dockerfile -**TL;DR:** Utilizar una herramienta de lint en su Dockerfile es un paso importante para identificar problemas en su Dockerfile que difieran de las mejores prácticas. Al escanear por fallas potenciales usando un linter especializado de a Docker, se pueden identificar fácilmente mejoras a la seguridad y rendimiento, salvando incontables horas de tiempo en problemas de seguridad en código de producción. +### `🌟 #new` + +**TL;DR:** Utilizar una herramienta de lint en tu Dockerfile es un paso importante para identificar problemas en su Dockerfile que difieran de las mejores prácticas. Al escanear por fallas potenciales usando un linter especializado en Docker, se pueden identificar fácilmente mejoras a la seguridad y rendimiento, salvando incontables horas de tiempo perdido o problemas de seguridad en código productivo. **De lo contrario** Dejar por error a Root como el usuario de producción en el Dockerfile, y también usar una imágen de un repositorio de una fuente desconocida. Esto puede ser fácilmente evitado usando un linter. -🔗 [**Leer más: Utilize Lint en su Dockerfile**](./sections/docker/lint-dockerfile.spanish.md) +🔗 [**Leer más: Usa un linter en tu Dockerfile**](./sections/docker/lint-dockerfile.spanish.md) -


+


⬆ Volver arriba

@@ -1297,241 +1639,341 @@ Todas las traducciones están contribuidas por la comunidad. Estaremos encantado ## Comité Directivo -Conozca a los miembros del comité directivo: las personas que trabajan juntas para brindar orientación y dirección al proyecto. Además, cada miembro del comité lidera un proyecto seguido bajo nuestros [proyectos Github](https://github.com/i0natan/nodebestpractices/projects). +Conozca a los miembros del comité directivo: las personas que trabajan juntas para brindar orientación y dirección al proyecto. Además, cada miembro del comité lidera un proyecto seguido bajo nuestros [proyectos Github](https://github.com/goldbergyoni/nodebestpractices/projects). - + [Yoni Goldberg](https://github.com/goldbergyoni) - - + + Consultor independiente de Node.js que trabaja con clientes en EE. UU., Europa e Israel en la construcción de aplicaciones Node.js a gran escala. Muchas de las mejores prácticas anteriores se publicaron por primera vez en [goldbergyoni.com](https://goldbergyoni.com). Comuníquese con Yoni a través de [@goldbergyoni](https://github.com/goldbergyoni) o [me@goldbergyoni.com](mailto:me@goldbergyoni.com)
- +Josh Hemphill -[Bruno Scheufler](https://github.com/BrunoScheufler) - +[Josh Hemphill](https://github.com/josh-hemphill) + + + -💻 ingeniero web full-stack, entusiasta de Node.js y GraphQL +Ingeniero / desarrollador web full-stack especializado en Seguridad, DevOps/DevSecOps e integraciones con ERPs.
- +Raz Luvaton -[Kyle Martin](https://github.com/js-kyle) - - +[Raz Luvaton](https://github.com/rluvaton) + + -Desarrollador Full Stack e ingeniero de confiabilidad de sitio con sede en Nueva Zelanda, interesado en la seguridad de aplicaciones web y en la arquitectura y creación de aplicaciones Node.js que funcionan a escala global +Desarrollador Full Stack que sabe salir de Vim y ama la Arquitectura, la Virtualización y la Seguridad.
- +## Colaborar -
+Si alguna vez quisiste colaborar en código abierto, ¡ahora es tu oportunidad! Consulta los [documentos de colaboración](/.operations/CONTRIBUTING.spanish.md) para obtener más información. - - -[Kevyn Bruyere](https://github.com/kevynb) - +## Colaboradores -Desarrollador full-stack independiente, con una pizca de Ops y automatización. +¡Gracias a estas maravillosas personas que han contribuido a este repositorio! -### Comité directivo Emérito + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Kevin Rambaud
Kevin Rambaud

🖋
Michael Fine
Michael Fine

🖋
Shreya Dahal
Shreya Dahal

🖋
Matheus Cruz Rocha
Matheus Cruz Rocha

🖋
Yog Mehta
Yog Mehta

🖋
Kudakwashe Paradzayi
Kudakwashe Paradzayi

🖋
t1st3
t1st3

🖋
mulijordan1976
mulijordan1976

🖋
Matan Kushner
Matan Kushner

🖋
Fabio Hiroki
Fabio Hiroki

🖋
James Sumners
James Sumners

🖋
Dan Gamble
Dan Gamble

🖋
PJ Trainor
PJ Trainor

🖋
Remek Ambroziak
Remek Ambroziak

🖋
Yoni Jah
Yoni Jah

🖋
Misha Khokhlov
Misha Khokhlov

🖋
Evgeny Orekhov
Evgeny Orekhov

🖋
-
-

🖋
Isaac Halvorson
Isaac Halvorson

🖋
Vedran Karačić
Vedran Karačić

🖋
lallenlowe
lallenlowe

🖋
Nathan Wells
Nathan Wells

🖋
Paulo Reis
Paulo Reis

🖋
syzer
syzer

🖋
David Sancho
David Sancho

🖋
Robert Manolea
Robert Manolea

🖋
Xavier Ho
Xavier Ho

🖋
Aaron
Aaron

🖋
Jan Charles Maghirang Adona
Jan Charles Maghirang Adona

🖋
Allen
Allen

🖋
Leonardo Villela
Leonardo Villela

🖋
Michał Załęcki
Michał Załęcki

🖋
Chris Nicola
Chris Nicola

🖋
Alejandro Corredor
Alejandro Corredor

🖋
cwar
cwar

🖋
Yuwei
Yuwei

🖋
Utkarsh Bhatt
Utkarsh Bhatt

🖋
Duarte Mendes
Duarte Mendes

🖋
Jason Kim
Jason Kim

🖋
Mitja O.
Mitja O.

🖋
Sandro Miguel Marques
Sandro Miguel Marques

🖋
Gabe
Gabe

🖋
Ron Gross
Ron Gross

🖋
Valeri Karpov
Valeri Karpov

🖋
Sergio Bernal
Sergio Bernal

🖋
Nikola Telkedzhiev
Nikola Telkedzhiev

🖋
Vitor Godoy
Vitor Godoy

🖋
Manish Saraan
Manish Saraan

🖋
Sangbeom Han
Sangbeom Han

🖋
blackmatch
blackmatch

🖋
Joe Reeve
Joe Reeve

🖋
Ryan Busby
Ryan Busby

🖋
Iman Mohamadi
Iman Mohamadi

🖋
Sergii Paryzhskyi
Sergii Paryzhskyi

🖋
Kapil Patel
Kapil Patel

🖋
迷渡
迷渡

🖋
Hozefa
Hozefa

🖋
Ethan
Ethan

🖋
Sam
Sam

🖋
Arlind
Arlind

🖋
Teddy Toussaint
Teddy Toussaint

🖋
Lewis
Lewis

🖋
Gabriel Lidenor
Gabriel Lidenor

🖋
Roman
Roman

🖋
Francozeira
Francozeira

🖋
Invvard
Invvard

🖋
Rômulo Garofalo
Rômulo Garofalo

🖋
Tho Q Luong
Tho Q Luong

🖋
Burak Shen
Burak Shen

🖋
Martin Muzatko
Martin Muzatko

🖋
Jared Collier
Jared Collier

🖋
Hilton Meyer
Hilton Meyer

🖋
ChangJoo Park(박창주)
ChangJoo Park(박창주)

🖋
Masahiro Sakaguchi
Masahiro Sakaguchi

🖋
Keith Holliday
Keith Holliday

🖋
coreyc
coreyc

🖋
Maximilian Berkmann
Maximilian Berkmann

🖋
Douglas Mariano Valero
Douglas Mariano Valero

🖋
Marcelo Melo
Marcelo Melo

🖋
Mehmet Perk
Mehmet Perk

🖋
ryan ouyang
ryan ouyang

🖋
Shabeer
Shabeer

🖋
Eduard Kyvenko
Eduard Kyvenko

🖋
Deyvison Rocha
Deyvison Rocha

🖋
George Mamer
George Mamer

🖋
Konstantinos Leimonis
Konstantinos Leimonis

🖋
Oliver Lluberes
Oliver Lluberes

🌍
Tien Do
Tien Do

🖋
Ranvir Singh
Ranvir Singh

🖋
Vadim Nicolaev
Vadim Nicolaev

🖋 🌍
German Gamboa Gonzalez
German Gamboa Gonzalez

🖋
Hafez
Hafez

🖋
Chandiran
Chandiran

🖋
VinayaSathyanarayana
VinayaSathyanarayana

🖋
Kim Kern
Kim Kern

🖋
Kenneth Freitas
Kenneth Freitas

🖋
songe
songe

🖋
Kirill Shekhovtsov
Kirill Shekhovtsov

🖋
Serge
Serge

🖋
keyrwinz
keyrwinz

🖋
Dmitry Nikitenko
Dmitry Nikitenko

🖋
bushuai
bushuai

👀 🖋
Benjamin Gruenbaum
Benjamin Gruenbaum

🖋
Ezequiel
Ezequiel

🌍
Juan José Rodríguez
Juan José Rodríguez

🌍
Or Bin
Or Bin

🖋
Andreo Vieira
Andreo Vieira

🖋
Michael Solomon
Michael Solomon

🖋
Jimmy Callin
Jimmy Callin

🖋
Siddharth
Siddharth

🖋
Ryan Smith
Ryan Smith

🖋
Tom Boettger
Tom Boettger

🖋
Joaquín Ormaechea
Joaquín Ormaechea

🌍
dfrzuz
dfrzuz

🌍
Victor Homyakov
Victor Homyakov

🖋
Josh
Josh

🖋 🛡️
Alec Francis
Alec Francis

🖋
arjun6610
arjun6610

🖋
Jan Osch
Jan Osch

🖋
Thiago Rotondo Sampaio
Thiago Rotondo Sampaio

🌍
Alexsey
Alexsey

🖋
Luis A. Acurero
Luis A. Acurero

🌍
Lucas Romano
Lucas Romano

🌍
Denise Case
Denise Case

🖋
Nick Ribal
Nick Ribal

🖋 👀
0xflotus
0xflotus

🖋
Jonathan Chen
Jonathan Chen

🖋
Dilan Srilal
Dilan Srilal

🖋
vladthelittleone
vladthelittleone

🌍
Nik Osvalds
Nik Osvalds

🖋
Daniel Kiss
Daniel Kiss

📖
Forresst
Forresst

🖋
Jonathan Svenheden
Jonathan Svenheden

🖋
AustrisC
AustrisC

🖋
kyeongtae kim
kyeongtae kim

🌍
007
007

🖋
Ane Diaz de Tuesta
Ane Diaz de Tuesta

🌍 🖋
YukiOta
YukiOta

🌍
Frazer Smith
Frazer Smith

🖋
Raz Luvaton
Raz Luvaton

🖋
Yuta Azumi
Yuta Azumi

🖋
andrewjbarbour
andrewjbarbour

🖋
mr
mr

🖋
Aleksandar
Aleksandar

🖋
Owl
Owl

🖋
Yedidya Schwartz
Yedidya Schwartz

🖋 💡
ari
ari

🖋
Thomas König
Thomas König

🖋
Kalle Lämsä
Kalle Lämsä

🖋
Wyatt
Wyatt

🖋
KHADIR Tayeb
KHADIR Tayeb

🖋
Shankar Regmi
Shankar Regmi

🖋
Shubham
Shubham

🖋
Lucas Alves
Lucas Alves

🖋
Benjamin
Benjamin

🖋
Yeoh Joer
Yeoh Joer

🖋
Miigon
Miigon

🖋
Rostislav Bogorad
Rostislav Bogorad

🖋
Flouse
Flouse

🖋
Tarantini Pereira
Tarantini Pereira

🖋
Kazuki Matsuo
Kazuki Matsuo

🖋
Adam Smith
Adam Smith

🖋
Dohyeon Ko
Dohyeon Ko

🖋
Vladislav Legkov
Vladislav Legkov

🖋
Kerollos Magdy
Kerollos Magdy

🖋
Erez Lieberman
Erez Lieberman

🖋
Breno Macedo
Breno Macedo

🖋
Fernando Flores
Fernando Flores

🌍
Rafael Brito
Rafael Brito

🌍
Emiliano Peralta
Emiliano Peralta

🌍
Shin, SJ
Shin, SJ

🖋
Benjamin Forster
Benjamin Forster

🖋
Daniele Fedeli
Daniele Fedeli

🖋
djob195
djob195

🖋
antspk
antspk

🖋
정진영
정진영

🖋
kkk-cashwalk
kkk-cashwalk

🖋
apainintheneck
apainintheneck

🖋
Fajar Budhi Iswanda
Fajar Budhi Iswanda

🖋
이주호
이주호

🖋
Singh
Singh

🖋
Alex Dumitru
Alex Dumitru

🖋
Anton Lykhatskyi
Anton Lykhatskyi

🖋
sangwonlee
sangwonlee

🖋
Eugenio Berretta
Eugenio Berretta

🖋
soranakk
soranakk

🖋
고준영
고준영

🖋 💻
Guilherme Portella
Guilherme Portella

🖋
André Esser
André Esser

🖋
Scc
Scc

🌍
Mauro Accornero
Mauro Accornero

🖋
no-yan
no-yan

🖋
-[Sagir Khan](https://github.com/sagirk) - - - + + -Especialista en JavaScript y su ecosistema: React, Node.js, MongoDB, prácticamente cualquier cosa que implique el uso de JavaScript / JSON en cualquier capa del sistema: la creación de productos utilizando la plataforma web para las marcas más reconocidas del mundo. Miembro individual de la Fundación Node.js, colaborando en la Iniciativa de rediseño del sitio web del Comité de la Comunidad. + -
+### Comité Directivo Emérito -## Colaboradores +[Bruno Scheufler](https://github.com/BrunoScheufler) + -Gracias a todos nuestros colaboradores! 🙏 +💻 Ingeniero web de pila completa, entusiasta de Node.js y GraphQL. -Nuestros colaboradores son miembros que contribuyen regularmente al repositorio, sugiriendo nuevas mejores prácticas, problemas de evaluación, revisión de solicitudes de extracción y más. Si está interesado en ayudarnos a guiar a miles de personas para crear mejores aplicaciones de Node.js, lea nuestras [pautas para contribuyentes](/.operations/CONTRIBUTING.spanish.md) 🎉 +
-| | | -| :--: | :--: | -| [Ido Richter (Fundador)](https://github.com/idori) | [Keith Holliday](https://github.com/TheHollidayInn) | + -### Colaboradores anteriores +[Kyle Martin](https://github.com/js-kyle) + + -| | -| :--: | -| [Refael Ackermann](https://github.com/refack) | +Desarrollador Full Stack y Site Reliability Engineer con sede en Nueva Zelanda, interesado en la seguridad de aplicaciones web y en la arquitectura y construcción de aplicaciones Node.js que funcionen a escala global.
-## Agradecimientos + + +[Kevyn Bruyere](https://github.com/kevynb) + -Agradecemos cualquier contribución, desde una simple palabra hasta una nueva práctica en nuestra guía. Mira nuestros colaboradores y [documentación para contribuir aquí!](CONTRIBUTORS.md) +Desarrollador full-stack independiente con gusto por la Operación y la automatización. -## Contribuidores ✨ +
-¡Gracias a estas maravillosas personas que han contribuido a este repositorio! + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

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

🖋

Luis Acurero

🌍
+[Sagir Khan](https://github.com/sagirk) + + + - - - \ No newline at end of file +Especialista experto en JavaScript y su ecosistema (React, Node.js, TypeScript, GraphQL, MongoDB, prácticamente cualquier cosa que involucre JS/JSON en cualquier capa del sistema), creando productos utilizando la plataforma web para las marcas más reconocidas del mundo. Miembro Individual de la Fundación Node.js. diff --git a/assets/flags/BR.jpg b/assets/flags/BR.jpg index 1f295edff..387b7e983 100644 Binary files a/assets/flags/BR.jpg and b/assets/flags/BR.jpg differ diff --git a/assets/flags/JA.png b/assets/flags/JA.png index cbd5f3c5e..964d5b059 100644 Binary files a/assets/flags/JA.png and b/assets/flags/JA.png differ diff --git a/assets/images/6-parts-in-test.jpg b/assets/images/6-parts-in-test.jpg index 46ce51992..4a7065c53 100644 Binary files a/assets/images/6-parts-in-test.jpg and b/assets/images/6-parts-in-test.jpg differ diff --git a/assets/images/Privatenpm.png b/assets/images/Privatenpm.png index ce3fe3e68..d14466f78 100644 Binary files a/assets/images/Privatenpm.png and b/assets/images/Privatenpm.png differ diff --git a/assets/images/Sketch (8).png b/assets/images/Sketch (8).png index 47c1662b8..4b8860bb6 100644 Binary files a/assets/images/Sketch (8).png and b/assets/images/Sketch (8).png differ diff --git a/assets/images/The backend testing checklist.png b/assets/images/The backend testing checklist.png new file mode 100644 index 000000000..0b867d9cf Binary files /dev/null and b/assets/images/The backend testing checklist.png differ diff --git a/assets/images/anchore-report.png b/assets/images/anchore-report.png index d733c438e..5dccb932d 100644 Binary files a/assets/images/anchore-report.png and b/assets/images/anchore-report.png differ diff --git a/assets/images/apm1.png b/assets/images/apm1.png index 30dfea2db..1ec43cae4 100644 Binary files a/assets/images/apm1.png and b/assets/images/apm1.png differ diff --git a/assets/images/apm3.png b/assets/images/apm3.png index a6894ea31..835ebc0db 100644 Binary files a/assets/images/apm3.png and b/assets/images/apm3.png differ diff --git a/assets/images/app-dynamics-dashboard.png b/assets/images/app-dynamics-dashboard.png index e9f600c27..622a24e62 100644 Binary files a/assets/images/app-dynamics-dashboard.png and b/assets/images/app-dynamics-dashboard.png differ diff --git a/assets/images/banner-1.png b/assets/images/banner-1.png index e288c0720..8c531375f 100644 Binary files a/assets/images/banner-1.png and b/assets/images/banner-1.png differ diff --git a/assets/images/banner-2.jpg b/assets/images/banner-2.jpg index 41df36ded..5d18c73b3 100644 Binary files a/assets/images/banner-2.jpg and b/assets/images/banner-2.jpg differ diff --git a/assets/images/banner-3.jpg b/assets/images/banner-3.jpg index 18c69f9be..ded0ded3c 100644 Binary files a/assets/images/banner-3.jpg and b/assets/images/banner-3.jpg differ diff --git a/assets/images/banner-4.jpg b/assets/images/banner-4.jpg index 86b93d8a2..2379a7e08 100644 Binary files a/assets/images/banner-4.jpg and b/assets/images/banner-4.jpg differ diff --git a/assets/images/circleci.png b/assets/images/circleci.png index 949414556..3667d5b5b 100644 Binary files a/assets/images/circleci.png and b/assets/images/circleci.png differ diff --git a/assets/images/concat-benchmark.png b/assets/images/concat-benchmark.png index 62412363b..425318bcc 100644 Binary files a/assets/images/concat-benchmark.png and b/assets/images/concat-benchmark.png differ diff --git a/assets/images/createmaintenanceendpoint1.png b/assets/images/createmaintenanceendpoint1.png index a155bf246..b79509a25 100644 Binary files a/assets/images/createmaintenanceendpoint1.png and b/assets/images/createmaintenanceendpoint1.png differ diff --git a/assets/images/error-handling-flow.png b/assets/images/error-handling-flow.png index a1b3ca6b8..33ee988e7 100644 Binary files a/assets/images/error-handling-flow.png and b/assets/images/error-handling-flow.png differ diff --git a/assets/images/eslint-plugin-security.png b/assets/images/eslint-plugin-security.png index e43270f53..dd57f2ca7 100644 Binary files a/assets/images/eslint-plugin-security.png and b/assets/images/eslint-plugin-security.png differ diff --git a/assets/images/event-loop.png b/assets/images/event-loop.png index f806b6f86..3b0dd75c6 100644 Binary files a/assets/images/event-loop.png and b/assets/images/event-loop.png differ diff --git a/assets/images/jenkins_dashboard.png b/assets/images/jenkins_dashboard.png index 79409f75f..bbf0f9158 100644 Binary files a/assets/images/jenkins_dashboard.png and b/assets/images/jenkins_dashboard.png differ diff --git a/assets/images/keepexpressinweb.gif b/assets/images/keepexpressinweb.gif index 2e55d1761..d4d863ba0 100644 Binary files a/assets/images/keepexpressinweb.gif and b/assets/images/keepexpressinweb.gif differ diff --git a/assets/images/kibana-graph-1024x550.jpg b/assets/images/kibana-graph-1024x550.jpg index ebfb22366..d93da6505 100644 Binary files a/assets/images/kibana-graph-1024x550.jpg and b/assets/images/kibana-graph-1024x550.jpg differ diff --git a/assets/images/kibana-raw-1024x637.png b/assets/images/kibana-raw-1024x637.png index 36ea84802..a127cc8db 100644 Binary files a/assets/images/kibana-raw-1024x637.png and b/assets/images/kibana-raw-1024x637.png differ diff --git a/assets/images/linkedin.svg b/assets/images/linkedin.svg new file mode 100644 index 000000000..949c44529 --- /dev/null +++ b/assets/images/linkedin.svg @@ -0,0 +1 @@ +> \ No newline at end of file diff --git a/assets/images/logging-overview.png b/assets/images/logging-overview.png index 96ffe500b..8897c825e 100644 Binary files a/assets/images/logging-overview.png and b/assets/images/logging-overview.png differ diff --git a/assets/images/logs-with-transaction-id.jpg b/assets/images/logs-with-transaction-id.jpg index 8e9ec3d10..83a1e12b3 100644 Binary files a/assets/images/logs-with-transaction-id.jpg and b/assets/images/logs-with-transaction-id.jpg differ diff --git a/assets/images/logs-withtout-transaction-id.jpg b/assets/images/logs-withtout-transaction-id.jpg index 94bec6c77..09bf71ab9 100644 Binary files a/assets/images/logs-withtout-transaction-id.jpg and b/assets/images/logs-withtout-transaction-id.jpg differ diff --git a/assets/images/members/bruno.png b/assets/images/members/bruno.png index 045a905e8..cc0519f3e 100644 Binary files a/assets/images/members/bruno.png and b/assets/images/members/bruno.png differ diff --git a/assets/images/members/create-member-icon.md b/assets/images/members/create-member-icon.md new file mode 100644 index 000000000..b20cf1198 --- /dev/null +++ b/assets/images/members/create-member-icon.md @@ -0,0 +1,44 @@ +## How to create a new color coded icon image + +To create a new image for yourself in either the collaborators or committee +sections follow the directions and template below. + +1. Replace `[USERNAME]` in the template with your username. +2. Replace `[BORDER_COLOR]` according to this: + - Committee: `#33cd32` + - Collaborators: `#0efeff` +3. Paste the text into a text file with `.svg` extension. +4. Open in an image editor of your choice that supports SVG and then export as + PNG (Enable transparency if it's optional) + +
+ +```svg + + + + + + + + +``` + +#### Tested Image Editors + +- [Inkscape](https://inkscape.org/) +- [GIMP](https://www.gimp.org/) diff --git a/assets/images/members/ido.png b/assets/images/members/ido.png index 5cb6c4687..627a514ef 100644 Binary files a/assets/images/members/ido.png and b/assets/images/members/ido.png differ diff --git a/assets/images/members/jhemphill.jpg b/assets/images/members/jhemphill.jpg deleted file mode 100644 index 534793f45..000000000 Binary files a/assets/images/members/jhemphill.jpg and /dev/null differ diff --git a/assets/images/members/josh-hemphill.png b/assets/images/members/josh-hemphill.png new file mode 100644 index 000000000..021048234 Binary files /dev/null and b/assets/images/members/josh-hemphill.png differ diff --git a/assets/images/members/keith.png b/assets/images/members/keith.png index fcf4c32bc..839670b08 100644 Binary files a/assets/images/members/keith.png and b/assets/images/members/keith.png differ diff --git a/assets/images/members/kevyn.png b/assets/images/members/kevyn.png index a99f56e15..8f49da4e6 100644 Binary files a/assets/images/members/kevyn.png and b/assets/images/members/kevyn.png differ diff --git a/assets/images/members/kyle.png b/assets/images/members/kyle.png index 805956f23..055894550 100644 Binary files a/assets/images/members/kyle.png and b/assets/images/members/kyle.png differ diff --git a/assets/images/members/raz-luvaton.jpg b/assets/images/members/raz-luvaton.jpg index afb6fcb5f..33a5070b5 100644 Binary files a/assets/images/members/raz-luvaton.jpg and b/assets/images/members/raz-luvaton.jpg differ diff --git a/assets/images/members/refael.png b/assets/images/members/refael.png index fe57d04a2..937c1f6b1 100644 Binary files a/assets/images/members/refael.png and b/assets/images/members/refael.png differ diff --git a/assets/images/members/sagir.png b/assets/images/members/sagir.png index 7fe4732aa..608cb0995 100644 Binary files a/assets/images/members/sagir.png and b/assets/images/members/sagir.png differ diff --git a/assets/images/members/yoni.png b/assets/images/members/yoni.png index 34c4680ad..e1b53d143 100644 Binary files a/assets/images/members/yoni.png and b/assets/images/members/yoni.png differ diff --git a/assets/images/monitoring1.png b/assets/images/monitoring1.png index ddf126270..61d0c7331 100644 Binary files a/assets/images/monitoring1.png and b/assets/images/monitoring1.png differ diff --git a/assets/images/monitoring2.jpg b/assets/images/monitoring2.jpg index ed53a8a06..85e96c7e5 100644 Binary files a/assets/images/monitoring2.jpg and b/assets/images/monitoring2.jpg differ diff --git a/assets/images/monitoring3.png b/assets/images/monitoring3.png index 27253a0ae..7f86541aa 100644 Binary files a/assets/images/monitoring3.png and b/assets/images/monitoring3.png differ diff --git a/assets/images/npm-audit.png b/assets/images/npm-audit.png index 37a5ec072..75f729d2f 100644 Binary files a/assets/images/npm-audit.png and b/assets/images/npm-audit.png differ diff --git a/assets/images/sampleMeanDiag.png b/assets/images/sampleMeanDiag.png index ecf4a9fa4..2d10444c3 100644 Binary files a/assets/images/sampleMeanDiag.png and b/assets/images/sampleMeanDiag.png differ diff --git a/assets/images/setnodeenv1.png b/assets/images/setnodeenv1.png index 185800627..53701125d 100644 Binary files a/assets/images/setnodeenv1.png and b/assets/images/setnodeenv1.png differ diff --git a/assets/images/smartlogging1.png b/assets/images/smartlogging1.png index 36ea84802..c49a7db73 100644 Binary files a/assets/images/smartlogging1.png and b/assets/images/smartlogging1.png differ diff --git a/assets/images/smartlogging2.jpg b/assets/images/smartlogging2.jpg index ebfb22366..d93da6505 100644 Binary files a/assets/images/smartlogging2.jpg and b/assets/images/smartlogging2.jpg differ diff --git a/assets/images/swaggerDoc.png b/assets/images/swaggerDoc.png index 17eae6b44..9d05a9ce0 100644 Binary files a/assets/images/swaggerDoc.png and b/assets/images/swaggerDoc.png differ diff --git a/assets/images/swaggerMarkup.png b/assets/images/swaggerMarkup.png index ddc935017..26944fdba 100644 Binary files a/assets/images/swaggerMarkup.png and b/assets/images/swaggerMarkup.png differ diff --git a/assets/images/test-report-like-requirements.jpeg b/assets/images/test-report-like-requirements.jpeg index 58eb26d3d..d8691bf92 100644 Binary files a/assets/images/test-report-like-requirements.jpeg and b/assets/images/test-report-like-requirements.jpeg differ diff --git a/assets/images/testingpyramid.png b/assets/images/testingpyramid.png index 9243b7d4d..259da5682 100644 Binary files a/assets/images/testingpyramid.png and b/assets/images/testingpyramid.png differ diff --git a/assets/images/twitter.svg b/assets/images/twitter.svg new file mode 100644 index 000000000..8cac4f029 --- /dev/null +++ b/assets/images/twitter.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/uptimerobot.jpg b/assets/images/uptimerobot.jpg index bfde3fa68..ee45d3d4d 100644 Binary files a/assets/images/uptimerobot.jpg and b/assets/images/uptimerobot.jpg differ diff --git a/assets/images/web.svg b/assets/images/web.svg new file mode 100644 index 000000000..7c3b5254f --- /dev/null +++ b/assets/images/web.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/www.png b/assets/images/www.png index 2934df0d7..ef0b291c3 100644 Binary files a/assets/images/www.png and b/assets/images/www.png differ diff --git a/assets/images/ydnlu.png b/assets/images/ydnlu.png index 871a391be..0882c32ba 100644 Binary files a/assets/images/ydnlu.png and b/assets/images/ydnlu.png differ diff --git a/.operations/package.json b/package.json similarity index 52% rename from .operations/package.json rename to package.json index 3db88347c..66bf9d9a0 100644 --- a/.operations/package.json +++ b/package.json @@ -4,9 +4,7 @@ "description": "[✔]: assets/images/checkbox-small-blue.png", "main": "gen-html.js", "scripts": { - "build": "cd .. && node .operations/gen-html.js", - "test": "echo \"Error: no test specified\" && exit 1", - "lint": "markdownlint ../README.md" + "lint": "markdownlint ./README*.md" }, "repository": { "type": "git", @@ -19,15 +17,6 @@ }, "homepage": "https://github.com/goldbergyoni/nodebestpractices#readme", "dependencies": { - "cheerio": "^1.0.0-rc.2", - "ci-info": "^3.1.1", - "github-api": "^3.0.0", - "graceful-fs": "^4.1.15", - "imagemin": "^6.0.0", - "imagemin-jpegtran": "^6.0.0", - "imagemin-pngquant": "^6.0.0", - "is-ci": "^3.0.0", - "markdownlint-cli": "^0.18.0", - "showdown": "^1.9.0" + "markdownlint-cli": "^0.18.0" } } diff --git a/sections/docker/bootstrap-using-node.md b/sections/docker/bootstrap-using-node.md index aaf4f0b18..7be2aa900 100644 --- a/sections/docker/bootstrap-using-node.md +++ b/sections/docker/bootstrap-using-node.md @@ -2,9 +2,9 @@ ## One paragraph explainer -We are used to see code examples where folks start their app using `CMD 'npm start'`. This is a bad practice. The `npm` binary will not forward signals to your app which prevents graceful shutdown (see [/sections/docker/graceful-shutdown.md]). If you are using child-processes they won’t be cleaned up correctly in case of unexpected shutdown, leaving zombie processes on your host. `npm start` also results in having an extra process for no benefit. To start you app use `CMD ['node','server.js']`. If your app spawns child-processes also use `TINI` as an entrypoint. +We are used to see code examples where folks start their app using `CMD 'npm start'`. This is a bad practice. The `npm` binary will not forward signals to your app which prevents graceful shutdown [see](/sections/docker/graceful-shutdown.md). If you are using child-processes they won’t be cleaned up correctly in case of unexpected shutdown, leaving zombie processes on your host. `npm start` also results in having an extra process for no benefit. To start you app use `CMD ['node','server.js']`. If your app spawns child-processes also use `TINI` as an entrypoint. -### Code example - Bootsraping using Node +### Code example - Bootstrapping using Node ```dockerfile FROM node:12-slim AS build diff --git a/sections/docker/clean-cache.chinese.md b/sections/docker/clean-cache.chinese.md new file mode 100644 index 000000000..5e2c09918 --- /dev/null +++ b/sections/docker/clean-cache.chinese.md @@ -0,0 +1,27 @@ +# 清除NODE_MODULE缓存 + +

+ +### 一段解释 + +node包管理器,npm和Yarn,会本地缓存安装过的包,以便在未来的项目中,如果需要同样的包,就不需要从远程仓库重新获取。尽管这会导致包的重复,消耗更多的存储 - 作为回报,它维持了一个安装相同包的本地开发环境。而在Docker容器中,这种存储是没什么价值的,因为它仅仅安装依赖一次。通过移除这类缓存,只需要使用一行代码,上十MB的存储会从image中移除。当这样做的时候,确保它不会通过非零(non-zero)码退出,因而由于缓存问题导致CI构建失败 - 这可以通过添加一个force标志位来避免。 + +*请注意如果您使用multi-stage构建,只要您在最后阶段不安装新的包,清除缓存是没意义的* + +

+ +### 代码示例 - 清除缓存 + +
+Dockerfile + +```dockerfile +FROM node:12-slim AS build +WORKDIR /usr/src/app +COPY package.json package-lock.json ./ +RUN npm ci --production && npm cache clean --force + +# 剩余部分 +``` + +
\ No newline at end of file diff --git a/sections/docker/clean-cache.french.md b/sections/docker/clean-cache.french.md index 4fcecc0fe..1c4bad560 100644 --- a/sections/docker/clean-cache.french.md +++ b/sections/docker/clean-cache.french.md @@ -6,7 +6,7 @@ Node package managers, npm & Yarn, cache the installed packages locally so that future projects which need the same libraries won't need to fetch from a remote repository. Although this duplicates the packages and consumes more storage - it pays off in a local development environment that typically keeps installing the same packages. In a Docker container this storage increase is worthless since it installs the dependency only once. By removing this cache, using a single line of code, tens of MB are shaved from the image. While doing so, ensure that it doesn't exit with non-zero code and fail the CI build because of caching issues - This can be avoided by including the --force flag. -*Please not that this is not relevant if you are using a multi-stage build as long as you don't install new packages in the last stage* +*Please note that this is not relevant if you are using a multi-stage build as long as you don't install new packages in the last stage*

diff --git a/sections/docker/clean-cache.md b/sections/docker/clean-cache.md index 481f35e19..c5ab40ec6 100644 --- a/sections/docker/clean-cache.md +++ b/sections/docker/clean-cache.md @@ -6,7 +6,7 @@ Node package managers, npm & Yarn, cache the installed packages locally so that future projects which need the same libraries won't need to fetch from a remote repository. Although this duplicates the packages and consumes more storage - it pays off in a local development environment that typically keeps installing the same packages. In a Docker container this storage increase is worthless since it installs the dependency only once. By removing this cache, using a single line of code, tens of MB are shaved from the image. While doing so, ensure that it doesn't exit with non-zero code and fail the CI build because of caching issues - This can be avoided by including the --force flag. -*Please not that this is not relevant if you are using a multi-stage build as long as you don't install new packages in the last stage* +*Please note that this is not relevant if you are using a multi-stage build as long as you don't install new packages in the last stage*

diff --git a/sections/docker/docker-ignore.chinese.md b/sections/docker/docker-ignore.chinese.md new file mode 100644 index 000000000..4743e5c8f --- /dev/null +++ b/sections/docker/docker-ignore.chinese.md @@ -0,0 +1,50 @@ +# 使用.dockerignore防止泄漏机密 + +

+ +### 一段解释 + +Docker的build命令会通过一个虚拟网络(virtual network)拷贝本地文件到构建的上下文环境。注意 - 开发和CI文件夹会包含机密文件,比如.npmrc,.aws,.env,以及其他一些敏感文件。最终,Docker镜像可能会包含机密信息,并在不安全的区域暴露它们(例如,Docker repository,partners servers)。一个更好的方式是,Dockerfile应该明确地描述哪些文件需要被复制。除此之外,包含一个.dockerginore文件,还充当最后一个安全网,过滤掉不必要的文件夹和潜在的机密文件。这样做还可以加快构建速度 - 通过排除在生产环境并不会用到的通用开发文件夹(例如.git,测试结果,IDE配置),整个构建过程可以更好的使用缓存,并取得一个更佳的性能。 + +

+ +### 代码示例 – 对于Node.js,一个好的默认.dockerignore示例 + +
+.dockerignore + +``` +**/node_modules/ +**/.git +**/README.md +**/LICENSE +**/.vscode +**/npm-debug.log +**/coverage +**/.env +**/.editorconfig +**/.aws +**/dist +``` + +
+ +

+ +### 代码示例 反模式 - 遍历拷贝所有文件 + +
+Dockerfile + +```dockerfile +FROM node:12-slim AS build + +WORKDIR /usr/src/app +# 下一行拷贝所有文件 +COPY . . + +# 剩余部分 + +``` + +
diff --git a/sections/docker/generic-tips.chinese.md b/sections/docker/generic-tips.chinese.md new file mode 100644 index 000000000..ad6f322fd --- /dev/null +++ b/sections/docker/generic-tips.chinese.md @@ -0,0 +1,29 @@ +[✔]: ../../assets/images/checkbox-small-blue.png + +# 通用的Node.js Docker最佳实践 + +此通用Docker指南部分包含所有编程语言中标准化的最佳实践,并没有针对Node.js的特殊解释 + +## ![✔] 使用命令COPY优于ADD + +**TL;DR:** COPY更安全,因为它只复制本地文件,而ADD支持更高级的获取,比如从远程站点下载二进制文件 + +## ![✔] 避免更新基础OS + +**TL;DR:** 在构建期间更新本地二进制文件(例如apt get update)会在每次运行时创建不一致的映像,并且还需要提升权限。取而代之,使用经常更新的基础镜像 + +## ![✔] 使用标签对镜像分类 + +**TL;DR:** 为每个镜像提供元数据(metadata)可能有助于Ops专业人员充分处理它。例如,包括维护人员姓名、构建日期和其他信息,当有人需要对映像进行推理时,这些信息可能会被证明是有用的 + +## ![✔] 使用非特权容器 + +**TL;DR:** 特权容器具有与主机上的根用户相同的权限和功能。这是很少需要的,作为一个经验法则,应该使用在官方Node镜像中创建的'node'用户 + +## ![✔] 检查并验证最终结果 + +**TL;DR:** 有时很容易忽略构建过程中的副作用,如泄露的秘密或不必要的文件。使用[Dive](https://github.com/wagoodman/dive)等工具检查生成的镜像可以很容易地帮助识别此类问题 + +## ![✔] 执行完整性检查 + +**TL;DR:** 在拉取基本镜像或最终镜像时,网络可能会被误导并重定向到下载恶意镜像。除非对内容进行签名和验证,否则标准Docker协议中没有任何内容可以防止这种情况。[Docker Notary](https://docs.docker.com/notary/getting_started/)是一个可以执行此类检查的工具 diff --git a/sections/docker/lint-dockerfile.japanese.md b/sections/docker/lint-dockerfile.japanese.md index 31b5b1c4a..6b0a41e99 100644 --- a/sections/docker/lint-dockerfile.japanese.md +++ b/sections/docker/lint-dockerfile.japanese.md @@ -2,7 +2,7 @@ ### 一段落説明 -コアアプリケーションのコードをベストプラクティスに従わせ、問題になる前にイシューやバグを取り除くために lint を利用するように、Dockerfile も同様に linting されるべきです。Dockerfile を linting することは、非常に軽い労力でプロダクションの問題をオンタイムで捕らえることができる可能性を高めることを意味します。例えば、存在しないステージからコピーを試みたり、不明なオンラインリポジトリからコピーしてきたり、パワーユーザー(SUDO)でアプリケーションを実行したりなど、DOckerfile に記述されたロジックや命令に構造的な問題が無いことを確認することができます。オープンソースの Dockerfile linter である [Hadolint](https://github.com/hadolint/hadolint) は、手動または CI プロセスの一部として利用することができます。Hadolint は、[Docker ベストプラクティス](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/) に従うことを目的とした Dockerfile 専用の linter です。 +コアアプリケーションのコードをベストプラクティスに従わせ、問題になる前にイシューやバグを取り除くために lint を利用するように、Dockerfile も同様に linting されるべきです。Dockerfile を linting することは、非常に軽い労力でプロダクションの問題をオンタイムで捕らえることができる可能性を高めることを意味します。例えば、存在しないステージからコピーを試みたり、不明なオンラインリポジトリからコピーしてきたり、パワーユーザー(SUDO)でアプリケーションを実行したりなど、Dockerfile に記述されたロジックや命令に構造的な問題が無いことを確認することができます。オープンソースの Dockerfile linter である [Hadolint](https://github.com/hadolint/hadolint) は、手動または CI プロセスの一部として利用することができます。Hadolint は、[Docker ベストプラクティス](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/) に従うことを目的とした Dockerfile 専用の linter です。
diff --git a/sections/docker/restart-and-replicate-processes.md b/sections/docker/restart-and-replicate-processes.md index 824e26fd2..1fa50bdff 100644 --- a/sections/docker/restart-and-replicate-processes.md +++ b/sections/docker/restart-and-replicate-processes.md @@ -37,7 +37,7 @@ FROM node:12-slim # The build logic comes here -CMD ["pm2-runtime", "indes.js"] +CMD ["pm2-runtime", "index.js"] ``` diff --git a/sections/drafts/readme-general-toc-1.md b/sections/drafts/readme-general-toc-1.md index 4f5c789f8..3d13f35a9 100644 --- a/sections/drafts/readme-general-toc-1.md +++ b/sections/drafts/readme-general-toc-1.md @@ -1,12 +1,12 @@ - +

Node.js Best Practices

53 items Last update: 7 days ago Updated for Node v.8.4 - + # Welcome to Node.js Best Practices diff --git a/sections/drafts/readme-general-toc-3.md b/sections/drafts/readme-general-toc-3.md index 10551ac26..1a11e5745 100644 --- a/sections/drafts/readme-general-toc-3.md +++ b/sections/drafts/readme-general-toc-3.md @@ -1,12 +1,12 @@ - +

Node.js Best Practices

53 items Last update: 7 days ago Updated for Node v.8.4 - + # Welcome to Node.js Best Practices diff --git a/sections/drafts/readme-general-toc-4.md b/sections/drafts/readme-general-toc-4.md index 84362302a..3db7b68a7 100644 --- a/sections/drafts/readme-general-toc-4.md +++ b/sections/drafts/readme-general-toc-4.md @@ -1,12 +1,12 @@ - +

Node.js Best Practices

53 items Last update: 7 days ago Updated for Node v.8.4 - + # Welcome to Node.js Best Practices @@ -25,7 +25,7 @@ Welcome to the biggest compilation of Node.js best practices, based on our check ## ![](../../assets/images/checkbox-sm.png) 1. Structure your solution by feature ('microservices') -**TL&DR:** The worst large applications pitfal is a huge code base where hundreds of dependencies slow down developers as try to incorporate new features. Partioning into small units ensures that each unit is kept simple and very easy to maintain. This strategy pushes the complexity to the higher level - designing the cross-component interactions. +**TL&DR:** The worst large applications pitfal is a huge code base where hundreds of dependencies slow down developers as try to incorporate new features. Partitioning into small units ensures that each unit is kept simple and very easy to maintain. This strategy pushes the complexity to the higher level - designing the cross-component interactions. **Otherwise:** Developing a new feature with a change to few objects demands to evaluate how this changes might affect dozends of dependants and ach deployment becomes a fear. diff --git a/sections/errorhandling/apmproducts.basque.md b/sections/errorhandling/apmproducts.basque.md index 11e7158c9..0ea3a2126 100644 --- a/sections/errorhandling/apmproducts.basque.md +++ b/sections/errorhandling/apmproducts.basque.md @@ -20,8 +20,8 @@ APM produktuek 3 segmentu nagusi dituzte: ### Adibidea: UpTimeRobot.Com: webguneak monitorizatzeko panela -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/uptimerobot.jpg "Webgune monitorizazio aurreko panela") +![alt text](../../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") +![alt text](../../assets/images/app-dynamics-dashboard.png "kode instrumentazioarekin konbinatutako hasieratik amaierarainoko monitorizazioa") diff --git a/sections/errorhandling/apmproducts.brazilian-portuguese.md b/sections/errorhandling/apmproducts.brazilian-portuguese.md index 1e7b824cb..459e50f10 100644 --- a/sections/errorhandling/apmproducts.brazilian-portuguese.md +++ b/sections/errorhandling/apmproducts.brazilian-portuguese.md @@ -22,7 +22,7 @@ Os produtos APM constituem 3 segmentos principais: ### Exemplo: UpTimeRobot.Com - Painel de monitoramento de site -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/uptimerobot.jpg "Painel de monitoramento de sites") +![alt text](../../assets/images/uptimerobot.jpg "Painel de monitoramento de sites") ### Example: AppDynamics.Com – monitoramento de ponta a ponta combinado com instrumentação de código -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/app-dynamics-dashboard.png "monitoramento de ponta a ponta combinado com instrumentação de código") +![alt text](../../assets/images/app-dynamics-dashboard.png "monitoramento de ponta a ponta combinado com instrumentação de código") diff --git a/sections/errorhandling/apmproducts.chinese.md b/sections/errorhandling/apmproducts.chinese.md index 8803f2791..0777b7359 100644 --- a/sections/errorhandling/apmproducts.chinese.md +++ b/sections/errorhandling/apmproducts.chinese.md @@ -21,7 +21,7 @@ APM 产品由3个主要部分构成: ### 示例: UpTimeRobot.Com – 网站监控仪表板 -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/uptimerobot.jpg "Website monitoring dashboard") +![alt text](../../assets/images/uptimerobot.jpg "Website monitoring dashboard") ### 示例: AppDynamics.Com – 与代码检测结合的端到端监视 -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/app-dynamics-dashboard.png "end to end monitoring combined with code instrumentation") +![alt text](../../assets/images/app-dynamics-dashboard.png "end to end monitoring combined with code instrumentation") diff --git a/sections/errorhandling/apmproducts.french.md b/sections/errorhandling/apmproducts.french.md index 1d4f206fd..bfe5f5916 100644 --- a/sections/errorhandling/apmproducts.french.md +++ b/sections/errorhandling/apmproducts.french.md @@ -22,7 +22,7 @@ Les produits APM regroupent 3 pôles principaux : ### Exemple : UpTimeRobot.Com - Tableau de bord de surveillance de site Web -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/uptimerobot.jpg "Tableau de bord de surveillance de site Web") +![alt text](../../assets/images/uptimerobot.jpg "Tableau de bord de surveillance de site Web") ### Exemple : AppDynamics.Com - Surveillance de bout en bout combinée à une instrumentation de code -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/app-dynamics-dashboard.png "Surveillance de bout en bout combinée à une instrumentation de code") +![alt text](../../assets/images/app-dynamics-dashboard.png "Surveillance de bout en bout combinée à une instrumentation de code") diff --git a/sections/errorhandling/apmproducts.japanese.md b/sections/errorhandling/apmproducts.japanese.md index 34370867c..5e8b56f80 100644 --- a/sections/errorhandling/apmproducts.japanese.md +++ b/sections/errorhandling/apmproducts.japanese.md @@ -22,7 +22,7 @@ APM 製品は 3 つの主要なセグメントを構成しています: ### 例: UpTimeRobot.Com – ウェブサイトモニタリングダッシュボード -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/uptimerobot.jpg "ウェブサイトモニタリングダッシュボード") +![alt text](../../assets/images/uptimerobot.jpg "ウェブサイトモニタリングダッシュボード") ### 例: AppDynamics.Com – コード計測が統合されたエンドツーエンドモニタリング -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/app-dynamics-dashboard.png "コード計測が統合されたエンドツーエンドモニタリング") +![alt text](../../assets/images/app-dynamics-dashboard.png "コード計測が統合されたエンドツーエンドモニタリング") diff --git a/sections/errorhandling/apmproducts.korean.md b/sections/errorhandling/apmproducts.korean.md index ad5081797..fd4ae438e 100644 --- a/sections/errorhandling/apmproducts.korean.md +++ b/sections/errorhandling/apmproducts.korean.md @@ -22,7 +22,7 @@ APM products constitute 3 major segments: ### Example: UpTimeRobot.Com – Website monitoring dashboard -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/uptimerobot.jpg "Website monitoring dashboard") +![alt text](../../assets/images/uptimerobot.jpg "Website monitoring dashboard") ### Example: AppDynamics.Com – end to end monitoring combined with code instrumentation -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/app-dynamics-dashboard.png "end to end monitoring combined with code instrumentation") +![alt text](../../assets/images/app-dynamics-dashboard.png "end to end monitoring combined with code instrumentation") diff --git a/sections/errorhandling/apmproducts.md b/sections/errorhandling/apmproducts.md index 5f302168d..ae6fc82ec 100644 --- a/sections/errorhandling/apmproducts.md +++ b/sections/errorhandling/apmproducts.md @@ -22,7 +22,7 @@ APM products constitute 3 major segments: ### Example: UpTimeRobot.Com – Website monitoring dashboard -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/uptimerobot.jpg "Website monitoring dashboard") +![alt text](../../assets/images/uptimerobot.jpg "Website monitoring dashboard") ### Example: AppDynamics.Com – end to end monitoring combined with code instrumentation -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/app-dynamics-dashboard.png "end to end monitoring combined with code instrumentation") +![alt text](../../assets/images/app-dynamics-dashboard.png "end to end monitoring combined with code instrumentation") diff --git a/sections/errorhandling/apmproducts.polish.md b/sections/errorhandling/apmproducts.polish.md index a53a4b176..2a10799a8 100644 --- a/sections/errorhandling/apmproducts.polish.md +++ b/sections/errorhandling/apmproducts.polish.md @@ -22,7 +22,7 @@ Produkty APM stanowią 3 główne segmenty: ### Przykład: UpTimeRobot.Com – Website monitoring dashboard -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/uptimerobot.jpg "Website monitoring dashboard") +![alt text](../../assets/images/uptimerobot.jpg "Website monitoring dashboard") ### Przykład: AppDynamics.Com – end to end monitoring combined with code instrumentation -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/app-dynamics-dashboard.png "end to end monitoring combined with code instrumentation") +![alt text](../../assets/images/app-dynamics-dashboard.png "end to end monitoring combined with code instrumentation") diff --git a/sections/errorhandling/apmproducts.russian.md b/sections/errorhandling/apmproducts.russian.md index 242b6786c..e4c23d814 100644 --- a/sections/errorhandling/apmproducts.russian.md +++ b/sections/errorhandling/apmproducts.russian.md @@ -22,7 +22,7 @@ ### Пример: UpTimeRobot.Com - панель мониторинга сайта -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/uptimerobot.jpg "Панель мониторинга сайта") +![alt text](../../assets/images/uptimerobot.jpg "Панель мониторинга сайта") ### Пример: AppDynamics.Com – сквозной мониторинг в сочетании с инструментарием кода -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/app-dynamics-dashboard.png "Сквозной мониторинг в сочетании с инструментарием кода") +![alt text](../../assets/images/app-dynamics-dashboard.png "Сквозной мониторинг в сочетании с инструментарием кода") diff --git a/sections/errorhandling/asyncerrorhandling.chinese.md b/sections/errorhandling/asyncerrorhandling.chinese.md index ef2f12e51..24725eabd 100644 --- a/sections/errorhandling/asyncerrorhandling.chinese.md +++ b/sections/errorhandling/asyncerrorhandling.chinese.md @@ -1,25 +1,43 @@ -# 对于异步的错误处理,请使用Async-Await或者promise - +# 对于异步的错误处理,请使用 Async-Await 或者 promises ### 一段解释 +由于大多数的程序员不熟悉回调,不能很好的掌控回调函数,导致被迫到处检测错误,处理让人不快的代码嵌套和难以理解的代码流程。Promise 的库,比如 BlueBird,async,和 Q 封装了一些代码,使用者可以使用 RETURN 和 THROW 的方式来控制程序的流程。具体来说,就是它们支持最受欢迎的 try-catch 错误处理风格,这使得主流程代码从在每一个方法中处理错误的方式中解放出来。 -由于回调对于大多数的程序员来说不熟悉,被迫随处检测错误,让人不快的代码内嵌和难以理解的代码流程,它没有形成一定规模。promise的库,比如BlueBird,async,和Q封装了一种标准的代码风格, 它通过使用return和throw来控制程序流程。具体来说,它们支持最受欢迎的try-catch错误处理风格,这使得主流程代码从在每一个方法中处理错误的方式中解放出来。 - +### 代码示例 – 使用 promises 捕获错误 -### 代码示例 – 使用promise捕获错误 +```javascript +doWork() + .then(doWork) + .then(doOtherWork) + .then((result) => doWork) + .catch((error) => { + throw error; + }) + .then(verify); +``` +### 代码示例 - 使用 async/await 捕获错误 ```javascript -doWork() - .then(doWork) - .then(doOtherWork) - .then((result) => doWork) - .catch((error) => {throw error;}) - .then(verify); +async function executeAsyncTask() { + try { + const valueA = await functionA(); + const valueB = await functionB(valueA); + const valueC = await functionC(valueB); + return await functionD(valueC); + } catch (err) { + logger.error(err); + } finally { + await alwaysExecuteThisFunction(); + } +} ``` ### 代码示例 反模式 – 回调方式的错误处理 +
+Javascript + ```javascript getData(someParameter, function(err, result){ if(err != null) @@ -27,30 +45,61 @@ getData(someParameter, function(err, result){ getMoreData(a, function(err, result){ if(err != null) //做一些事情类似于调用给定的回调函数并传递错误 - getMoreData(b, function(c){ - getMoreData(d, function(e){ + getMoreData(b, function(c){ + getMoreData(d, function(e){ if(err != null) - //你有什么想法?  + //你有什么想法? + }); +}); +``` + +
+ +
+Typescript + +```typescript +getData(someParameter, function (err: Error | null, resultA: ResultA) { + if (err !== null) { + //做一些事情类似于调用给定的回调函数并传递错误 + getMoreData(resultA, function (err: Error | null, resultB: ResultB) { + if (err !== null) { + //做一些事情类似于调用给定的回调函数并传递错误 + getMoreData(resultB, function (resultC: ResultC) { + getMoreData(resultC, function (err: Error | null, d: ResultD) { + if (err !== null) { + // 你有什么想法? + } + }); + }); + } }); + } }); ``` -### 博客引用: "我们使用promise有一个问题" - 摘自博客pouchdb.com - - > ……实际上, 回调会做一些更险恶的事情: 他们剥夺了我们的stack, 这是我们通常在编程语言中想当然的事情。编写没有堆栈的代码很像驾驶一辆没有刹车踏板的汽车: 你没有意识到你有多么需要它, 直到你伸手去找它, 而它不在那里。promise的全部目的是让我们回到我们在异步时丢失的语言基础: return,throw和stack。但你必须知道如何正确使用promise, 以便利用他们。 +
+ +### 博客引用: "我们使用 promise 有一个问题" + +摘自博客 pouchdb.com + +> ……实际上, 回调会做一些更险恶的事情: 他们剥夺了我们的 stack, 这是我们通常在编程语言中想当然的事情。编写没有堆栈的代码很像驾驶一辆没有刹车踏板的汽车: 你没有意识到你有多么需要它, 直到你伸手去找它, 而它不在那里。promise 的全部目的是让我们回到我们在异步时丢失的语言基础: return,throw 和 stack。但你必须知道如何正确使用 promise, 以便利用他们。 + +### 博客引用: "promise 方法更加紧凑" -### 博客引用: "promise方法更加紧凑" - 摘自博客gosquared.com - - > ………promise的方法更紧凑, 更清晰, 写起来更快速。如果在任何ops中发生错误或异常,则由单个.catch()处理程序处理。有这个单一的地方来处理所有的错误意味着你不需要为每个阶段的工作写错误检查。 +摘自博客 gosquared.com -### 博客引用: "原生ES6支持promise,可以和generator一起使用" - 摘自博客StrongLoop - - > ….回调有一个糟糕的错误处理的报道。promise更好。将express内置的错误处理与promise结合起来, 大大降低了uncaught exception的几率。原生ES6支持promise, 通过编译器babel,它可以与generator,ES7提议的技术(比如async/await)一起使用。 +> ………promise 的方法更紧凑, 更清晰, 写起来更快速。如果在任何 ops 中发生错误或异常,则由单个.catch()处理程序处理。有这个单一的地方来处理所有的错误意味着你不需要为每个阶段的工作写错误检查。 + +### 博客引用: "原生 ES6 支持 promise,可以和 generator 一起使用" + +摘自博客 StrongLoop + +> ….回调有一个糟糕的错误处理的报道。promise 更好。将 express 内置的错误处理与 promise 结合起来, 大大降低了 uncaught exception 的几率。原生 ES6 支持 promise, 通过编译器 babel,它可以与 generator,ES7 提议的技术(比如 async/await)一起使用。 ### 博客引用: "所有那些您所习惯的常规的流量控制结构, 完全被打破" - 摘自博客Benno’s - - > ……关于基于异步、回调编程的最好的事情之一是, 基本上所有那些您习惯的常规流量控制结构, 完全被打破。然而, 我发现最易打破的是处理异常。Javascript提供了一个相当熟悉的try...catch结构来处理异常。异常的问题是, 它们提供了在一个调用堆栈上 short-cutting错误的很好的方法, 但最终由于不同堆栈上发生的错误导致完全无用… + +摘自博客 Benno’s + +> ……关于基于异步、回调编程的最好的事情之一是, 基本上所有那些您习惯的常规流量控制结构, 完全被打破。然而, 我发现最易打破的是处理异常。Javascript 提供了一个相当熟悉的 try...catch 结构来处理异常。异常的问题是, 它们提供了在一个调用堆栈上 short-cutting 错误的很好的方法, 但最终由于不同堆栈上发生的错误导致完全无用… diff --git a/sections/errorhandling/centralizedhandling.french.md b/sections/errorhandling/centralizedhandling.french.md index 4dfbb73da..ca1f2849a 100644 --- a/sections/errorhandling/centralizedhandling.french.md +++ b/sections/errorhandling/centralizedhandling.french.md @@ -154,7 +154,7 @@ app.use((err: Error, req: Request, res: Response, next: NextFunction) => { ### Illustration : Les acteurs et le flux du traitement des erreurs -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/error-handling-flow.png "Flux de traitement des erreurs") +![alt text](../../assets/images/error-handling-flow.png "Flux de traitement des erreurs") ### Citation de blog : « Parfois, les niveaux inférieurs ne peuvent rien faire d'utile, sauf propager l'erreur à leur appelant » diff --git a/sections/errorhandling/centralizedhandling.md b/sections/errorhandling/centralizedhandling.md index b463e7a9f..7a8f7a6d6 100644 --- a/sections/errorhandling/centralizedhandling.md +++ b/sections/errorhandling/centralizedhandling.md @@ -154,7 +154,7 @@ 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") +![alt text](../../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" diff --git a/sections/errorhandling/documentingusingswagger.basque.md b/sections/errorhandling/documentingusingswagger.basque.md index 8a2bce81a..e88ba2e41 100644 --- a/sections/errorhandling/documentingusingswagger.basque.md +++ b/sections/errorhandling/documentingusingswagger.basque.md @@ -47,4 +47,4 @@ Joyent blogeko “Node.js erregistratzea“ hitz gako bati esker sailkatua ### Tresna erabilgarria: Swagger Online Dokumentazio Sortzailea -![Swagger API Eskema](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/swaggerDoc.png "APIen errore kudeaketa") +![Swagger API Eskema](../../assets/images/swaggerDoc.png "APIen errore kudeaketa") diff --git a/sections/errorhandling/documentingusingswagger.brazilian-portuguese.md b/sections/errorhandling/documentingusingswagger.brazilian-portuguese.md index 4af6a9890..781337b42 100644 --- a/sections/errorhandling/documentingusingswagger.brazilian-portuguese.md +++ b/sections/errorhandling/documentingusingswagger.brazilian-portuguese.md @@ -49,4 +49,4 @@ Do blog Joyent, classificado como 1 para as palavras-chave “Node.js logging” ### Ferramenta Útil: Swagger Criação de Documentação Online -![Swagger API Scheme](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/swaggerDoc.png "lidando com erros API") +![Swagger API Scheme](../../assets/images/swaggerDoc.png "lidando com erros API") diff --git a/sections/errorhandling/documentingusingswagger.chinese.md b/sections/errorhandling/documentingusingswagger.chinese.md index 5d3998ac1..3cf8cc0e3 100644 --- a/sections/errorhandling/documentingusingswagger.chinese.md +++ b/sections/errorhandling/documentingusingswagger.chinese.md @@ -13,4 +13,4 @@ REST API使用HTTP代码返回结果, API用户不仅绝对需要了解API schem ### 有用的工具: Swagger 在线文档创建工具 -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/swaggerDoc.png "API error handling") \ No newline at end of file +![alt text](../../assets/images/swaggerDoc.png "API error handling") diff --git a/sections/errorhandling/documentingusingswagger.french.md b/sections/errorhandling/documentingusingswagger.french.md index 13f407951..0b57ce6d3 100644 --- a/sections/errorhandling/documentingusingswagger.french.md +++ b/sections/errorhandling/documentingusingswagger.french.md @@ -49,4 +49,4 @@ Extrait du blog de Joyent classé en 1ere position pour les mots clés “Node.j ### Outil utile : créateur de documentation en ligne Swagger -![Schéma d'API Swagger](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/swaggerDoc.png "Gestion des erreurs de l'API") +![Schéma d'API Swagger](../../assets/images/swaggerDoc.png "Gestion des erreurs de l'API") diff --git a/sections/errorhandling/documentingusingswagger.japanese.md b/sections/errorhandling/documentingusingswagger.japanese.md index 861add999..10882d198 100644 --- a/sections/errorhandling/documentingusingswagger.japanese.md +++ b/sections/errorhandling/documentingusingswagger.japanese.md @@ -49,4 +49,4 @@ REST API は HTTP ステータスコードを利用して結果を返します ### 便利ツール: Swagger Online Documentation Creator -![Swagger API スキーマ](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/swaggerDoc.png "API エラー処理") +![Swagger API スキーマ](../../assets/images/swaggerDoc.png "API エラー処理") diff --git a/sections/errorhandling/documentingusingswagger.korean.md b/sections/errorhandling/documentingusingswagger.korean.md index 3341b0c13..a101e668a 100644 --- a/sections/errorhandling/documentingusingswagger.korean.md +++ b/sections/errorhandling/documentingusingswagger.korean.md @@ -49,4 +49,4 @@ From the blog Joyent, ranked 1 for the keywords “Node.js logging” ### Useful Tool: Swagger Online Documentation Creator -![Swagger API Scheme](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/swaggerDoc.png "API error handling") +![Swagger API Scheme](../../assets/images/swaggerDoc.png "API error handling") diff --git a/sections/errorhandling/documentingusingswagger.md b/sections/errorhandling/documentingusingswagger.md index b91e7d05d..836f07364 100644 --- a/sections/errorhandling/documentingusingswagger.md +++ b/sections/errorhandling/documentingusingswagger.md @@ -49,4 +49,4 @@ From the blog Joyent, ranked 1 for the keywords “Node.js logging” ### Useful Tool: Swagger Online Documentation Creator -![Swagger API Scheme](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/swaggerDoc.png "API error handling") +![Swagger API Scheme](../../assets/images/swaggerDoc.png "API error handling") diff --git a/sections/errorhandling/documentingusingswagger.polish.md b/sections/errorhandling/documentingusingswagger.polish.md index e274fea45..b6f1dfcd8 100644 --- a/sections/errorhandling/documentingusingswagger.polish.md +++ b/sections/errorhandling/documentingusingswagger.polish.md @@ -49,4 +49,4 @@ Z bloga Joyent, w rankingu 1 dla słów kluczowych “Node.js logging” ### Przydatne narzędzie: Swagger Online Documentation Creator -![Swagger API Scheme](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/swaggerDoc.png "API error handling") +![Swagger API Scheme](../../assets/images/swaggerDoc.png "API error handling") diff --git a/sections/errorhandling/documentingusingswagger.russian.md b/sections/errorhandling/documentingusingswagger.russian.md index 2086e312f..f225e3ca8 100644 --- a/sections/errorhandling/documentingusingswagger.russian.md +++ b/sections/errorhandling/documentingusingswagger.russian.md @@ -49,4 +49,4 @@ API-интерфейсы REST возвращают результаты с ис ### Полезный инструмент: Swagger Online Documentation Creator -![Swagger API Scheme](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/swaggerDoc.png "API error handling") +![Swagger API Scheme](../../assets/images/swaggerDoc.png "API error handling") diff --git a/sections/errorhandling/operationalvsprogrammererror.md b/sections/errorhandling/operationalvsprogrammererror.md index 69ccee2c3..162e09495 100644 --- a/sections/errorhandling/operationalvsprogrammererror.md +++ b/sections/errorhandling/operationalvsprogrammererror.md @@ -80,6 +80,6 @@ From the blog, debugable.com ranked 3 for the keywords “Node.js uncaught excep From the blog: 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. Let the application crash and restart it. +>2. Handle all possible errors and never crash. +>3. A balanced approach between the two diff --git a/sections/errorhandling/returningpromises.md b/sections/errorhandling/returningpromises.md index 89460f466..11ebc5a67 100644 --- a/sections/errorhandling/returningpromises.md +++ b/sections/errorhandling/returningpromises.md @@ -4,7 +4,7 @@ ### 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 +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 v8 feature called "zero-cost async stacktraces" that allows stacktraces to not 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
@@ -87,7 +87,7 @@ async function asyncFn () { return await syncFn() } -// 👎 syncFn would be missing in the stacktrace because it returns a promise while been sync +// 👎 syncFn would be missing in the stacktrace because it returns a promise while being sync asyncFn().catch(console.log) ``` @@ -165,7 +165,7 @@ Error: stacktrace is missing the place where getUser has been called 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, +*Side-note*: it may look 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 @@ -177,9 +177,9 @@ a line from internals of v8
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 1*: 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 its 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 @@ -210,8 +210,8 @@ Error: with all frames present 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: +*Side-note*: if async function that wrap `getUser` lacks `await` before return (anti-pattern #1 + anti-pattern #3) +then only one frame would be left in the stacktrace: ```javascript [...] @@ -235,12 +235,12 @@ Error: [...] ## 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** +sync stacktrace is based on **stack** provided by the operating system Node.js is running on (just like in most programming +languages). When an async function is executing, the **stack** of the operating system is popping it out as soon as the +function gets to its first `await`. So async stacktrace is a mix of operating system **stack** and a rejected +**promise resolution chain**. Zero-cost async stacktraces implementation extends 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 +sync function would always be missing from async stacktrace if any async operation has been performed after the function has been called [²](#2) ### The tradeoff @@ -256,13 +256,13 @@ 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 +There is a number of [excellent articles](https://jakearchibald.com/2017/await-vs-return-vs-return-await/) explaining 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 +is why resolving promises before returning them is the best practice for Node.js and not for ECMAScript in general ### Notes: @@ -270,7 +270,7 @@ is why resolving promises before returning them is the best practice for Node.js 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 +awaiting the function result. Common usage of promises includes 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 diff --git a/sections/errorhandling/shuttingtheprocess.md b/sections/errorhandling/shuttingtheprocess.md index e7f8b9ee3..69dd6ee0a 100644 --- a/sections/errorhandling/shuttingtheprocess.md +++ b/sections/errorhandling/shuttingtheprocess.md @@ -88,9 +88,9 @@ From the blog Joyent From the blog: 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. Let the application crash and restart it. +>2. Handle all possible errors and never crash. +>3. A balanced approach between the two ### Blog Quote: "No safe way to leave without creating some undefined brittle state" diff --git a/sections/errorhandling/testingerrorflows.md b/sections/errorhandling/testingerrorflows.md index 552ca1f53..ac03f4146 100644 --- a/sections/errorhandling/testingerrorflows.md +++ b/sections/errorhandling/testingerrorflows.md @@ -10,72 +10,69 @@ Testing ‘happy’ paths is no better than testing failures. Good testing code

Javascript ```javascript -describe('Facebook chat', () => { - it('Notifies on new chat message', () => { +describe("Facebook chat", () => { + it("Notifies on new chat message", () => { const chatService = new chatService(); chatService.participants = getDisconnectedParticipants(); - expect(chatService.sendMessage.bind({ message: 'Hi' })).to.throw(ConnectionError); + expect(chatService.sendMessage.bind({ message: "Hi" })).to.throw(ConnectionError); }); }); ``` +
+### Code example: ensuring API returns the right HTTP error code and log properly +
-Typescript +Javascript -```typescript -describe('Facebook chat', () => { - it('Notifies on new chat message', () => { - const chatService = new chatService(); - chatService.participants = getDisconnectedParticipants(); - expect(chatService.sendMessage.bind({ message: 'Hi' })).to.throw(ConnectionError); +```javascript +test("When exception is throw during request, Then logger reports the mandatory fields", async () => { + //Arrange + const orderToAdd = { + userId: 1, + productId: 2, + }; + + sinon + .stub(OrderRepository.prototype, "addOrder") + .rejects(new AppError("saving-failed", "Order could not be saved", 500)); + const loggerDouble = sinon.stub(logger, "error"); + + //Act + const receivedResponse = await axiosAPIClient.post("/order", orderToAdd); + + //Assert + expect(receivedResponse.status).toBe(500); + expect(loggerDouble.lastCall.firstArg).toMatchObject({ + name: "saving-failed", + status: 500, + stack: expect.any(String), + message: expect.any(String), }); }); ``` +
-### Code example: ensuring API returns the right HTTP error code +### Code example: ensuring that are uncaught exceptions are handled as well
Javascript ```javascript -it('Creates new Facebook group', () => { - const invalidGroupInfo = {}; - return httpRequest({ - method: 'POST', - uri: 'facebook.com/api/groups', - resolveWithFullResponse: true, - body: invalidGroupInfo, - json: true - }).then((response) => { - expect.fail('if we were to execute the code in this block, no error was thrown in the operation above') - }).catch((response) => { - expect(400).to.equal(response.statusCode); - }); -}); -``` -
+test("When unhandled exception is throw, Then the logger reports correctly", async () => { + //Arrange + await api.startWebServer(); + const loggerDouble = sinon.stub(logger, "error"); + const errorToThrow = new Error("An error that wont be caught 😳"); -
-Typescript - -```typescript -it('Creates new Facebook group', async () => { - let invalidGroupInfo = {}; - try { - const response = await httpRequest({ - method: 'POST', - uri: 'facebook.com/api/groups', - resolveWithFullResponse: true, - body: invalidGroupInfo, - json: true - }) - // if we were to execute the code in this block, no error was thrown in the operation above - expect.fail('The request should have failed') - } catch(response) { - expect(400).to.equal(response.statusCode); - } + //Act + process.emit("uncaughtException", errorToThrow); + + // Assert + expect(loggerDouble.calledWith(errorToThrow)); }); ``` -
\ No newline at end of file + + diff --git a/sections/production/LTSrelease.chinese.md b/sections/production/LTSrelease.chinese.md new file mode 100644 index 000000000..64f754ca3 --- /dev/null +++ b/sections/production/LTSrelease.chinese.md @@ -0,0 +1,20 @@ +# 使用 Node.js 的 LTS 版本 + +### 一段解释 + +确保您在正式环境中使用的是LTS(长期支持)版本的Node.js来获取关键错误的修复、安全更新和性能改进. + +LTS版本的Node.js至少支持18个月,并由偶数版本号(例如 4、6、8)表示。它们最适合生产环境,因为LTS的发行线专注于稳定性和安全性,而“Current”版本发布寿命较短,代码更新更加频繁。LTS版本的更改仅限于稳定性错误修复、安全更新、合理的npm更新、文档更新和某些可以证明不会破坏现有应用程序的性能改进。 + +

+ +### 继续读下去 + +🔗 [ Node.js版本定义 ](https://nodejs.org/en/about/releases/) + +🔗 [ Node.js发布时间表 ](https://github.com/nodejs/Release) + +🔗 [必要步骤:Long Term Support for Node.js by Rod Vagg(Node.js的长期支持by Rod Vagg)](https://medium.com/@nodesource/essential-steps-long-term-support-for-node-js-8ecf7514dbd) +> ...每个增量发布计划将由错误修复、安全修复和其他小但重要的更改的可用性来驱动。重点将放在稳定性上,但稳定性还包括最大程度地减少已知错误的数量,和持续关注重大的安全问题。 + +

diff --git a/sections/production/guardprocess.md b/sections/production/guardprocess.md index 719e85a73..29447cc30 100644 --- a/sections/production/guardprocess.md +++ b/sections/production/guardprocess.md @@ -4,7 +4,7 @@ ### One Paragraph Explainer -At the base level, Node processes must be guarded and restarted upon failures. Simply put, for small apps and those who don’t use containers – tools like [PM2](https://www.npmjs.com/package/pm2-docker) are perfect as they bring simplicity, restarting capabilities and also rich integration with Node. Others with strong Linux skills might use systemd and run Node as a service. Things get more interesting for apps that use Docker or any container technology since those are usually accompanied by cluster management and orchestration tools (e.g. [AWS ECS](http://docs.aws.amazon.com/AmazonECS/latest/developerguide/Welcome.html), [Kubernetes](https://kubernetes.io/), etc) that deploy, monitor and heal containers. Having all those rich cluster management features including container restart, why mess up with other tools like PM2? There’s no bulletproof answer. There are good reasons to keep PM2 within containers (mostly its containers specific version [pm2-docker](https://www.npmjs.com/package/pm2-docker)) as the first guarding tier – it’s much faster to restart a process and provide Node-specific features like flagging to the code when the hosting container asks to gracefully restart. Other might choose to avoid unnecessary layers. To conclude this write-up, no solution suits them all and getting to know the options is the important thing +At the base level, Node processes must be guarded and restarted upon failures. Simply put, for small apps and those who don’t use containers – tools like [PM2](https://www.npmjs.com/package/pm2) are perfect as they bring simplicity, restarting capabilities and also rich integration with Node. Others with strong Linux skills might use systemd and run Node as a service. Things get more interesting for apps that use Docker or any container technology since those are usually accompanied by cluster management and orchestration tools (e.g. [AWS ECS](http://docs.aws.amazon.com/AmazonECS/latest/developerguide/Welcome.html), [Kubernetes](https://kubernetes.io/), etc) that deploy, monitor and heal containers. Having all those rich cluster management features including container restart, why mess up with other tools like PM2? There’s no bulletproof answer. There are good reasons to keep PM2 within containers (mostly its containers specific version [pm2-docker](https://www.npmjs.com/package/pm2-docker)) as the first guarding tier – it’s much faster to restart a process and provide Node-specific features like flagging to the code when the hosting container asks to gracefully restart. Other might choose to avoid unnecessary layers. To conclude this write-up, no solution suits them all and getting to know the options is the important thing

diff --git a/sections/production/lockdependencies.md b/sections/production/lockdependencies.md index 1698c9bbb..61800062f 100644 --- a/sections/production/lockdependencies.md +++ b/sections/production/lockdependencies.md @@ -4,9 +4,7 @@ ### One Paragraph Explainer -Your code depends on many external packages, let’s say it ‘requires’ and use momentjs-2.1.4, then by default when you deploy to production npm might fetch momentjs 2.1.5 which unfortunately brings some new bugs to the table. Using npm config files and the argument ```–save-exact=true``` instructs npm to refer to the *exact* same version that was installed so the next time you run ```npm install``` (in production or within a Docker container you plan to ship forward for testing) the same dependent version will be fetched. An alternative and popular approach is using a `.shrinkwrap` file (easily generated using npm) that states exactly which packages and versions should be installed so no environment can get tempted to fetch newer versions than expected. - -* **Update:** as of npm 5, dependencies are locked automatically using .shrinkwrap. Yarn, an emerging package manager, also locks down dependencies by default. +Your code depends on many external packages, let’s say it ‘requires’ and use momentjs-2.1.4, then by default when you deploy to production npm might fetch momentjs 2.1.5 which unfortunately brings some new bugs to the table. Using npm config files and the argument `–save-exact=true` instructs npm to refer to the _exact_ same version that was installed so the next time you run `npm install` (in production or within a Docker container you plan to ship forward for testing) the same dependent version will be fetched. Due to this, starting from npm version 5 a package-lock.json file is generated in every install. This lock file pins all the dependencies and child dependencies versions. When the file is committed, any future install the gets a copy of the app will install the same dependencies version

@@ -19,51 +17,31 @@ save-exact:true

-### Code example: shrinkwrap.json file that distills the exact dependency tree - -```json -{ - "name": "A", - "dependencies": { - "B": { - "version": "0.0.1", - "dependencies": { - "C": { - "version": "0.1.0" - } - } - } - } -} -``` - -

- ### Code example: npm 5 dependencies lock file – package-lock.json ```json { - "name": "package-name", - "version": "1.0.0", - "lockfileVersion": 1, - "dependencies": { - "cacache": { - "version": "9.2.6", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-9.2.6.tgz", - "integrity": "sha512-YK0Z5Np5t755edPL6gfdCeGxtU0rcW/DBhYhYVDckT+7AFkCCtedf2zru5NRbBLFk6e7Agi/RaqTOAfiaipUfg==" - }, - "duplexify": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.5.0.tgz", - "integrity": "sha1-GqdzAC4VeEV+nZ1KULDMquvL1gQ=", - "dependencies": { - "end-of-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz", - "integrity": "sha1-1FlucCc0qT5A6a+GQxnqvZn/Lw4=" - } - } + "name": "package-name", + "version": "1.0.0", + "lockfileVersion": 1, + "dependencies": { + "cacache": { + "version": "9.2.6", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-9.2.6.tgz", + "integrity": "sha512-YK0Z5Np5t755edPL6gfdCeGxtU0rcW/DBhYhYVDckT+7AFkCCtedf2zru5NRbBLFk6e7Agi/RaqTOAfiaipUfg==" + }, + "duplexify": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.5.0.tgz", + "integrity": "sha1-GqdzAC4VeEV+nZ1KULDMquvL1gQ=", + "dependencies": { + "end-of-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz", + "integrity": "sha1-1FlucCc0qT5A6a+GQxnqvZn/Lw4=" } + } } + } } ``` diff --git a/sections/production/productioncode.md b/sections/production/productioncode.md index a86047312..6fb624a6c 100644 --- a/sections/production/productioncode.md +++ b/sections/production/productioncode.md @@ -6,11 +6,12 @@ Following is a list of development tips that greatly affect the production maintenance and stability: -* The twelve-factor guide – Get familiar with the [Twelve factors](https://12factor.net/) guide -* Be stateless – Save no data locally on a specific web server (see separate bullet – ‘Be Stateless’) -* Cache – Utilize cache heavily, yet never fail because of cache mismatch -* Test memory – gauge memory usage and leaks as part your development flow, tools such as ‘memwatch’ can greatly facilitate this task -* Name functions – Minimize the usage of anonymous functions (i.e. inline callback) as a typical memory profiler will provide memory usage per method name -* Use CI tools – Use CI tool to detect failures before sending to production. For example, use ESLint to detect reference errors and undefined variables. Use –trace-sync-io to identify code that uses synchronous APIs (instead of the async version) -* Log wisely – Include in each log statement contextual information, hopefully in JSON format so log aggregators tools such as Elastic can search upon those properties (see separate bullet – ‘Increase visibility using smart logs’). Also, include transaction-id that identifies each request and allows to correlate lines that describe the same transaction (see separate bullet – ‘Include Transaction-ID’) -* Error management – Error handling is the Achilles’ heel of Node.js production sites – many Node processes are crashing because of minor errors while others hang on alive in a faulty state instead of crashing. Setting your error handling strategy is absolutely critical, read here my [error handling best practices](http://goldbergyoni.com/checklist-best-practices-of-node-js-error-handling/) +- The twelve-factor guide – Get familiar with the [Twelve factors](https://12factor.net/) guide +- Be stateless – Save no data locally on a specific web server (see separate bullet – ‘Be Stateless’) +- Cache – Utilize cache heavily, yet never fail because of cache mismatch +- Test memory – gauge memory usage and leaks as part your development flow, tools such as ‘memwatch’ can greatly facilitate this task +- Name functions – Minimize the usage of anonymous functions (i.e. inline callback) as a typical memory profiler will provide memory usage per method name +- Use CI tools – Use CI tool to detect failures before sending to production. For example, use ESLint to detect reference errors and undefined variables. Use –trace-sync-io to identify code that uses synchronous APIs (instead of the async version) +- Log wisely – Include in each log statement contextual information, hopefully in JSON format so log aggregators tools such as Elastic can search upon those properties (see separate bullet – ‘Increase visibility using smart logs’). Also, include transaction-id that identifies each request and allows to correlate lines that describe the same transaction (see separate bullet – ‘Include Transaction-ID’) +- Test like production - Make developers machine quite close to the production infrastructure (e.g., with Docker-Compose). Avoid if/else clauses in testing that check if we're in testing environment but rather run the same code always +- Error management – Error handling is the Achilles’ heel of Node.js production sites – many Node processes are crashing because of minor errors while others hang on alive in a faulty state instead of crashing. Setting your error handling strategy is absolutely critical, read here my [error handling best practices](http://goldbergyoni.com/checklist-best-practices-of-node-js-error-handling/) diff --git a/sections/production/setnodeenv.md b/sections/production/setnodeenv.md index 49c957d37..59337b215 100644 --- a/sections/production/setnodeenv.md +++ b/sections/production/setnodeenv.md @@ -32,3 +32,9 @@ From the blog [dynatrace](https://www.dynatrace.com/blog/the-drastic-effects-of- ![NODE_ENV=production](../../assets/images/setnodeenv1.png "NODE_ENV=production")

+ + +From the Synk blog [10 best practices to containerize Node.js web applications with Docker](https://snyk.io/blog/10-best-practices-to-containerize-nodejs-web-applications-with-docker/#:~:text=Some%20frameworks%20and,As%20an%20example): +> ...Some frameworks and libraries may only turn on the optimized configuration that is suited to production if that NODE_ENV environment variable is set to production. Putting aside our opinion on whether this is a good or bad practice for frameworks to take, it is important to know this. + +

diff --git a/sections/projectstructre/breakintcomponents.basque.md b/sections/projectstructre/breakintcomponents.basque.md index 1e2b02c01..a5483d82d 100644 --- a/sections/projectstructre/breakintcomponents.basque.md +++ b/sections/projectstructre/breakintcomponents.basque.md @@ -9,14 +9,14 @@ Tamaina ertaineko nahiz handiko aplikazioetarako, monolitoak benetan kaltegarria ### Blog aipua: "Eskalatzeak aplikazio osoaren eskalatzea eskatzen du" -MartinFowler.com bloga +[MartinFowler.com](https://martinfowler.com/articles/microservices.html) bloga > 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 birsortzea 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

### Blog aipua: "Zergatik egiten du garrasi zure aplikazioaren egiturak?" -[uncle-bob](https://8thlight.com/blog/uncle-bob/2011/09/30/Screaming-Architecture.html) bloga +[uncle-bob](https://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html) bloga > ...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.
@@ -26,10 +26,10 @@ Beraz, zer oihukatzen du zure aplikazioaren egiturak? Zure direktorioko egiturar ### Zuzena: antolatu zure proiektua aparteko osagaietan -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebycomponents.PNG "Antolatu proiektua osagaietan") +![alt text](../../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") +![alt text](../../assets/images/structurebyroles.PNG "Antolatu proiektua rol teknikoen arabera") diff --git a/sections/projectstructre/breakintcomponents.brazilian-portuguese.md b/sections/projectstructre/breakintcomponents.brazilian-portuguese.md index 660b0be9d..f208f3b2c 100644 --- a/sections/projectstructre/breakintcomponents.brazilian-portuguese.md +++ b/sections/projectstructre/breakintcomponents.brazilian-portuguese.md @@ -9,7 +9,7 @@ Para aplicações de tamanho médio e acima, os monólitos são muito ruins - te ### Citação de Blog: "O escalonamento requer escalonamento de todo o aplicativo" - Do blog MartinFowler.com + Do blog [MartinFowler.com](https://martinfowler.com/articles/microservices.html) > Aplicações monolíticas podem ser bem-sucedidas, mas cada vez mais as pessoas estão sentindo frustrações com elas - especialmente à medida que mais aplicativos são implantados na nuvem. Os ciclos de mudança estão interligados - uma alteração feita em uma pequena parte do aplicativo requer que todo o monólito seja reconstruído e implantado. Ao longo do tempo, muitas vezes é difícil manter uma boa estrutura modular, tornando mais difícil manter as alterações que devem afetar apenas um módulo dentro desse módulo. O escalonamento requer escalonamento de todo o aplicativo, em vez de partes dele que exigem maior recurso. @@ -17,7 +17,7 @@ Para aplicações de tamanho médio e acima, os monólitos são muito ruins - te ### Citação de Blog: "Então, o que a arquitetura do seu aplicativo grita?" - Do blog [uncle-bob](https://8thlight.com/blog/uncle-bob/2011/09/30/Screaming-Architecture.html) + Do blog [uncle-bob](https://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html) > ...se você estivesse olhando para a arquitetura de uma biblioteca, provavelmente veria uma grande entrada, uma área para funcionários de check-in-out, áreas de leitura, pequenas salas de conferência e galeria após galeria, capaz de guardar estantes de livros para todos os livros. a biblioteca. Essa arquitetura iria gritar: Biblioteca.
@@ -27,10 +27,10 @@ Então, o que a arquitetura da sua aplicação grita? Quando você olha para a e ### Bom: estruture sua solução por componentes independentes -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebycomponents.PNG "Solução de estruturação por componentes") +![alt text](../../assets/images/structurebycomponents.PNG "Solução de estruturação por componentes")

### Ruim: Agrupe seus arquivos por papel técnico -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebyroles.PNG "Solução de estruturação por funções técnicas") +![alt text](../../assets/images/structurebyroles.PNG "Solução de estruturação por funções técnicas") diff --git a/sections/projectstructre/breakintcomponents.chinese.md b/sections/projectstructre/breakintcomponents.chinese.md index d4ae21dff..7c43b787b 100644 --- a/sections/projectstructre/breakintcomponents.chinese.md +++ b/sections/projectstructre/breakintcomponents.chinese.md @@ -11,14 +11,14 @@ ### 博客引用: "伸缩需要对整个应用程序进行伸缩设计" - 摘自博客 MartinFowler.com - + 摘自博客 [MartinFowler.com](https://martinfowler.com/articles/microservices.html) + > 单个应用程序可以成功, 但越来越多的人对它们感到失望 - 尤其是随着更多的应用程序被部署到云中。更改周期被捆绑在一起 - 对应用程序的一小部分进行更改, 需要重建和部署整个整体。随着时间的推移, 通常很难保持一个良好的模块化结构, 这使得更改哪怕只会影响该模块中的一个模块变得更加困难。伸缩设计需要扩展整个应用程序, 而不是它的部分,这往往需要更多资源。

### 博客引用: "那么, 你的应用程序的架构声明了什么?" - 摘自博客 [uncle-bob](https://8thlight.com/blog/uncle-bob/2011/09/30/Screaming-Architecture.html) + 摘自博客 [uncle-bob](https://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html) > ...如果你正在寻找一个图书馆的建筑架构, 你可能会看到一个盛大的入口, 一个 check-in-out 的文员, 阅读区, 小会议室, 画廊, 画廊后面容纳了装载所有图书馆书籍的书架。建筑会声明: 图书馆.
那么, 应用程序的体系架构会声明什么呢? 当您查看顶级目录结构和最高级别包中的源文件时; 他们声明: 医疗保健系统, 或会计系统, 或库存管理系统? 或者他们声明: Rails, 或Spring/Hibernate, 或 ASP?. @@ -27,10 +27,10 @@

### 推荐: 通过独立组件构建解决方案 -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebycomponents.PNG "Structuring solution by components") +![alt text](../../assets/images/structurebycomponents.PNG "Structuring solution by components")

### 避免: 按技术角色对文件进行分组 -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebyroles.PNG "Structuring solution by technical roles") +![alt text](../../assets/images/structurebyroles.PNG "Structuring solution by technical roles") diff --git a/sections/projectstructre/breakintcomponents.french.md b/sections/projectstructre/breakintcomponents.french.md index 77e6ab0cf..2fa18c5e9 100644 --- a/sections/projectstructre/breakintcomponents.french.md +++ b/sections/projectstructre/breakintcomponents.french.md @@ -10,7 +10,7 @@ Pour les applications de taille moyenne et supérieure, les monolithes sont vrai ### Citation de blog : « La mise à l'échelle nécessite la mise à l'échelle de l'application entière » - Extrait du blog de MartinFowler.com + Extrait du blog de [MartinFowler.com](https://martinfowler.com/articles/microservices.html) > Les applications monolithiques peuvent réussir, mais de plus en plus de personnes ressentent des frustrations à leur égard, d'autant plus que davantage d'applications sont déployées dans le cloud. Les cycles de changement sont liés les uns aux autres - une modification apportée à une petite partie de l'application nécessite la reconstruction et le déploiement du monolithe entier. Au fil du temps, il est souvent difficile de conserver une bonne structure modulaire, ce qui rend plus difficile la conservation des modifications qui ne devraient affecter qu'un module au sein de ce module. La mise à l'échelle nécessite la mise à l'échelle de l'application entière plutôt que les parties concernées, cela nécessitent donc plus de ressources. @@ -18,7 +18,7 @@ Pour les applications de taille moyenne et supérieure, les monolithes sont vrai ### Citation de blog : « Alors, est-ce que est l'architecture de votre application parle d'elle-même ? » - Extrait du blog de [uncle-bob](https://8thlight.com/blog/uncle-bob/2011/09/30/Screaming-Architecture.html) + Extrait du blog de [uncle-bob](https://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html) > ...si vous regardiez l'architecture d'une bibliothèque, vous verriez probablement une grande entrée, un espace pour les préposés à l'enregistrement, des salles de lecture, de petites salles de conférence et des galeries pouvant accueillir tous les livres de la bibliothèque. Cette architecture parle d'elle-même : c'est une Bibliothèque.
> @@ -28,10 +28,10 @@ Alors, est-ce que est l'architecture de votre application parle d'elle-même ? Q ### Bon : Organisez votre solution avec des composants autonomes -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebycomponents.PNG "Solution d'organisation par composants") +![alt text](../../assets/images/structurebycomponents.PNG "Solution d'organisation par composants")

### Mauvais : Regroupez vos fichiers selon leur rôle technique -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebyroles.PNG "Solution d'organisation par rôles techniques") +![alt text](../../assets/images/structurebyroles.PNG "Solution d'organisation par rôles techniques") diff --git a/sections/projectstructre/breakintcomponents.japanese.md b/sections/projectstructre/breakintcomponents.japanese.md index 43615342e..4d5e1f32e 100644 --- a/sections/projectstructre/breakintcomponents.japanese.md +++ b/sections/projectstructre/breakintcomponents.japanese.md @@ -10,7 +10,7 @@ ### ブログ引用: "Scaling requires scaling of the entire application" (スケーリングにはアプリケーション全体のスケーリングが必要) - ブログ MartinFowler.com より + ブログ [MartinFowler.com](https://martinfowler.com/articles/microservices.html) より > モノリシック・アプリケーションは成功を収めることができますが、人々はモノリシック・アプリケーションに不満を感じるようになってきています - 特に多くのアプリケーションがクラウドにデプロイされるようになってきているためです。変更サイクル同士は連動しています - アプリケーションのごく一部に変更を加えると、モノリス全体を再構築してデプロイする必要があります。時間が経つにつれて、良いモジュール構造を維持することが難しくなり、そのモジュール内の1つのモジュールだけに影響するように変更を維持することが難しくなります。スケーリングでは、アプリケーションの一部だけでなく、アプリケーション全体を拡張する必要があり、多くの場合、より多くのリソースを必要とします。 @@ -18,7 +18,7 @@ ### ブログ引用: "So what does the architecture of your application scream?" (では、アプリケーションのアーキテクチャは何を叫んでいるのでしょうか?) - ブログ [uncle-bob](https://8thlight.com/blog/uncle-bob/2011/09/30/Screaming-Architecture.html) より + ブログ [uncle-bob](https://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html) より > ...図書館の建築を眺めていると、あなたはおそらく壮大な入り口、図書館員のためのエリア、読書エリア、小さな会議室、そしてギャラリーの奥には図書館の本をすべて収納した棚があるのが見えるだろう。その建築は悲鳴を上げるだろう。図書館と。
@@ -28,10 +28,10 @@ ### 良い: 自己完結型のコンポーネントでソリューションを構築する -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebycomponents.PNG "コンポーネントによるソリューションの構築") +![alt text](../../assets/images/structurebycomponents.PNG "コンポーネントによるソリューションの構築")

### 悪い: 技術的な役割ごとにファイルをグループ化 -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebyroles.PNG "技術的な役割によるソリューションの構築") +![alt text](../../assets/images/structurebyroles.PNG "技術的な役割によるソリューションの構築") diff --git a/sections/projectstructre/breakintcomponents.korean.md b/sections/projectstructre/breakintcomponents.korean.md index a35f23509..95072145a 100644 --- a/sections/projectstructre/breakintcomponents.korean.md +++ b/sections/projectstructre/breakintcomponents.korean.md @@ -10,7 +10,7 @@ ### 블로그 인용: "확장하려면 애플리케이션 전체를 확장해야한다" -MartinFowler.com 블로그로부터 +[MartinFowler.com](https://martinfowler.com/articles/microservices.html) 블로그로부터 > 단일암체 애플리케이션도 성공적일 수 있지만, 점점 더 많은 사람들이 불만을 느끼고 있다 - 특히 더 많은 애플리케이션들이 클라우드로 전개될수록. 변화 주기는 다 같이 묶여 있다 - 애플리케이션의 조그마한 부분을 바꾸면 단일암체 전체를 재건하고 재배치하여야 한다. 시간이 흐를수록 좋은 모듈식의 구조를 유지하는것이 힘들어지고, 모듈 하나에만 작용해야 할 변화가 그 모듈 이내에서만 작용하도록 하는것이 힘들어진다. 더 많은 자원을 필요로 하는 부분만 확장하는 것이 아니라, 확장하려면 애플리케이션 전체를 확장해야한다. @@ -18,7 +18,7 @@ MartinFowler.com 블로그로부터 ### 블로그 인용: "그러니 당신의 어플리케이션의 설계를 보면 어떤 감이 오는가?" -[uncle-bob](https://8thlight.com/blog/uncle-bob/2011/09/30/Screaming-Architecture.html)블로그로부터 +[uncle-bob](https://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html) 블로그로부터 > ...도서관 설계도를 보면, 아마도 커다란 입구, 체크인/체크아웃 구역, 독서실, 소규모 회의실들, 도서관의 모든 책을 수용할 수 있게 책꽂이들을 놓을 만한 공간들이 보일 것이다. 설계도를 보면 도서관이라고 바로 감이 올 것이다.
@@ -28,10 +28,10 @@ MartinFowler.com 블로그로부터 ### 좋은예: 자족적인 컴포넌트 기반으로 설계하라 -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebycomponents.PNG "Structuring solution by components") +![alt text](../../assets/images/structurebycomponents.PNG "Structuring solution by components")

### 나쁜예: 파일을 기술적인 역할별로 모아라 -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebyroles.PNG "Structuring solution by technical roles") +![alt text](../../assets/images/structurebyroles.PNG "Structuring solution by technical roles") diff --git a/sections/projectstructre/breakintcomponents.md b/sections/projectstructre/breakintcomponents.md index 1e1bcf087..91df46d17 100644 --- a/sections/projectstructre/breakintcomponents.md +++ b/sections/projectstructre/breakintcomponents.md @@ -4,7 +4,7 @@ ### One Paragraph Explainer -For medium sized apps and above, monoliths are really bad - having one big software with many dependencies is just hard to reason about and often leads to spaghetti code. Even smart architects — those who are skilled enough to tame the beast and 'modularize' it — spend great mental effort on design, and each change requires carefully evaluating the impact on other dependent objects. The ultimate solution is to develop small software: divide the whole stack into self-contained components that don't share files with others, each constitutes very few files (e.g. API, service, data access, test, etc.) so that it's very easy to reason about it. Some may call this 'microservices' architecture — it's important to understand that microservices are not a spec which you must follow, but rather a set of principles. You may adopt many principles into a full-blown microservices architecture or adopt only a few. Both are good as long as you keep the software complexity low. The very least you should do is create basic borders between components, assign a folder in your project root for each business component and make it self-contained - other components are allowed to consume its functionality only through its public interface or API. This is the foundation for keeping your components simple, avoid dependency hell and pave the way to full-blown microservices in the future once your app grows. +For medium sized apps and above, *non-modular* monoliths are really bad - having one big software with 'spaghetti' of dependencies is just hard to reason about. The ultimate solution is to develop smaller software: divide the whole stack into self-contained components that don't share files with others, each is a standalone logical app (e.g. has its own API, service, data access, test, etc.) so that onboarding into it and changing the code is much easier than dealing with the whole system. Some may call this 'microservices' architecture — it's important to understand that microservices are not a spec which you must follow, but rather a set of principles. You may adopt many principles into a full-blown microservices architecture or adopt only a few. The very least you should do is create basic borders between components, assign a folder or repository in your system root for each business component and make it self-contained. Other components are allowed to consume its functionality only through its public interface or API. This is the foundation for keeping your components simple, avoid dependency hell and pave the way to full-blown microservices in the future once your app grows

@@ -18,7 +18,7 @@ For medium sized apps and above, monoliths are really bad - having one big softw ### Blog Quote: "So what does the architecture of your application scream?" - From the blog [uncle-bob](https://8thlight.com/blog/uncle-bob/2011/09/30/Screaming-Architecture.html) + From the blog [uncle-bob](https://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html) > ...if you were looking at the architecture of a library, you’d likely see a grand entrance, an area for check-in-out clerks, reading areas, small conference rooms, and gallery after gallery capable of holding bookshelves for all the books in the library. That architecture would scream: Library.
@@ -28,10 +28,38 @@ So what does the architecture of your application scream? When you look at the t ### Good: Structure your solution by self-contained components -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebycomponents.PNG "Structuring solution by components") +```bash +my-system +├─ apps (components) +│ ├─ orders +│ │ ├─ package.json +│ │ ├─ api +│ │ ├─ domain +│ │ ├─ data-access +│ ├─ users +│ ├─ payments +├─ libraries (generic cross-component functionality) +│ ├─ logger +│ ├─ authenticator +``` +

### Bad: Group your files by technical role -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebyroles.PNG "Structuring solution by technical roles") +```bash +my-system +├─ controllers +│ ├─ user-controller.js +│ ├─ order-controller.js +│ ├─ payment-controller.js +├─ services +│ ├─ user-service.js +│ ├─ order-service.js +│ ├─ payment-service.js +├─ models +│ ├─ user-model.js +│ ├─ order-model.js +│ ├─ payment-model.js +``` \ No newline at end of file diff --git a/sections/projectstructre/breakintcomponents.polish.md b/sections/projectstructre/breakintcomponents.polish.md index 62098e97b..17a7ea2ed 100644 --- a/sections/projectstructre/breakintcomponents.polish.md +++ b/sections/projectstructre/breakintcomponents.polish.md @@ -9,7 +9,7 @@ W przypadku średnich aplikacji i wyższych monolity są naprawdę złe - posiad ### Cytat z Bloga: "Skalowanie wymaga skalowania całej aplikacji" - Z bloga MartinFowler.com + Z bloga [MartinFowler.com](https://martinfowler.com/articles/microservices.html) > Monolithic applications can be successful, but increasingly people are feeling frustrations with them - especially as more applications are being deployed to the cloud. Change cycles are tied together - a change made to a small part of the application requires the entire monolith to be rebuilt and deployed. Over time it's often hard to keep a good modular structure, making it harder to keep changes that ought to only affect one module within that module. Scaling requires scaling of the entire application rather than parts of it that require greater resource. @@ -17,7 +17,7 @@ W przypadku średnich aplikacji i wyższych monolity są naprawdę złe - posiad ### Cytat z Bloga: "Więc co krzyczy architektura Twojej aplikacji?" - Z bloga [uncle-bob](https://8thlight.com/blog/uncle-bob/2011/09/30/Screaming-Architecture.html) + Z bloga [uncle-bob](https://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html) > ...if you were looking at the architecture of a library, you’d likely see a grand entrance, an area for check-in-out clerks, reading areas, small conference rooms, and gallery after gallery capable of holding bookshelves for all the books in the library. That architecture would scream: Library.
@@ -27,10 +27,10 @@ Więc co krzyczy architektura twojej aplikacji? Gdy spojrzysz na strukturę kata ### Dobre: Skonstruuj swoje rozwiązanie według samodzielnych komponentów -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebycomponents.PNG "Structuring solution by components") +![alt text](../../assets/images/structurebycomponents.PNG "Structuring solution by components")

### Złe: Pogrupuj pliki według roli technicznej -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebyroles.PNG "Structuring solution by technical roles") +![alt text](../../assets/images/structurebyroles.PNG "Structuring solution by technical roles") diff --git a/sections/projectstructre/breakintcomponents.russian.md b/sections/projectstructre/breakintcomponents.russian.md index 7e5c36706..cd7647b4f 100644 --- a/sections/projectstructre/breakintcomponents.russian.md +++ b/sections/projectstructre/breakintcomponents.russian.md @@ -10,7 +10,7 @@ ### Цитата из блога: "Масштабирование требует масштабирования всего приложения" -Из блога MartinFowler.com +Из блога [MartinFowler.com](https://martinfowler.com/articles/microservices.html) > Монолитные приложения могут быть успешными, но люди все чаще испытывают разочарование в связи с ними, особенно когда в облаке развертывается все бо̀льшие приложений. Циклы изменений связаны друг с другом - изменение, внесенное в небольшую часть приложения, требует перестройки и развертывания всего монолита. Со временем зачастую трудно сохранить хорошую модульную структуру, что усложняет сохранение изменений, которые должны затрагивать только один модуль в этом модуле. Масштабирование требует масштабирования всего приложения, а не его частей, которые требуют больших ресурсов. @@ -18,7 +18,7 @@ ### Цитата из блога: "Так что же кричит в архитектуре вашего приложения?" -Из блога [uncle-bob](https://8thlight.com/blog/uncle-bob/2011/09/30/Screaming-Architecture.html) +Из блога [uncle-bob](https://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html) > ... если бы вы смотрели на архитектуру библиотеки, вы бы, скорее всего, увидели парадный вход, зону для клерков, места для чтения, небольшие конференц-залы и галерею за галереей, способную вместить книжные полки для все книги в библиотеке. Эта архитектура будет кричать: "Библиотека!".
@@ -28,10 +28,10 @@ ### Хорошо: структурируйте свое решение по отдельным компонентам -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebycomponents.PNG "Structuring solution by components") +![alt text](../../assets/images/structurebycomponents.PNG "Structuring solution by components")

### Плохо: сгруппируйте файлы по техническим ролям -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebyroles.PNG "Structuring solution by technical roles") +![alt text](../../assets/images/structurebyroles.PNG "Structuring solution by technical roles") diff --git a/sections/projectstructre/choose-framework.md b/sections/projectstructre/choose-framework.md new file mode 100644 index 000000000..6af330a0f --- /dev/null +++ b/sections/projectstructre/choose-framework.md @@ -0,0 +1,39 @@ +# Consider all the consequences when choosing the main framework + +

+ +### Recommended frameworks: Pros and cons + +Unlike other choices, choosing the core framework determines strategic factors like the development style and how likely the team is to hit a wall. We believe that framework popularity is a supreme consideration and put our focus on the top 4 most popular frameworks in terms of downloads and GitHub stars. The text below outlines the pros and cons of each framework and how to match a framework to the right application type + +**express.js** + +Pros: Unmatched popularity; gigantic eco-system of extensions and middleware; simple to learn and use; familiar to almost every Node.js developer; tons of community articles and videos are based on express + +Cons: Covers a small subset of a typical application needs - merely a web server that invokes the app function per URL. Choosing express means leaving a handful of app concerns uncovered; outdated mechanics - no native support for async-await; barely maintained and updated; Slower than others + +**Nest.js** + +Pros: More batteries than any other option - covers many application concern including message queues, scheduled jobs and more; OOP-style is an advantage for teams who appreciate this design style; awesome docs; well-maintained; high popularity with a vibrant community + +Cons: High-level abstractions that cloud built-in Node.js conventions; The inclusion of many features, heavy usage of TypeScript and reference to sophisticated patterns might push teams for increased complexity; Steeper learning curve due to a handful of unique narratives (e.g., interceptors, guards, modules, and more); Highly opinionated + +**Fastify** + +Pros: Relatively simple and lean; mostly based on Node.js/JavaScript standards; relatively shallow learning curve; with its official plugins cover many application concerns though not as rich as Nest.js; + +Cons: Younger than others and not as popular yet; smaller eco-system compared to express and Nest.js + +**Koa** + +Pros: When compared with express: it's Simpler and nimbler; modern API with async/await support; better performance + +Cons: Covers a small subset of a typical application needs - leaves a handful of app concerns uncovered; Not as popular as express and Nest.js + +### A brief choosing guide + +**Prefer express.js when** - having an experienced architect onboard _and_ in a need to control the fine-grained pieces of the puzzle. In this circumstances, Koa is also a solid option with a more modern API than express but a much smaller eco-system + +**Prefer Fastify when -** The app consists of reasonably-sized components/Microservices (i.e., not a huge monolith); for teams who have solid JavaScript & Node.js knowledge; when sticking to Node.js narratives and spirit is desirable + +**Prefer Nest.js when** - It's desirable to design and code in OOP style; when the team is highly experienced with Java/Spring/Angular or similar; for large size app that can't be broken down (i.e. monolith) to autonomous component; for a team that lacks fundamental JavaScript/Node.js skills (not exclusively, this yet another consideration); when the decision-making overhead should be minimized; when the time to the first delivery is a critical factor diff --git a/sections/projectstructre/createlayers.basque.md b/sections/projectstructre/createlayers.basque.md index c8f5aa631..6c13bc0ee 100644 --- a/sections/projectstructre/createlayers.basque.md +++ b/sections/projectstructre/createlayers.basque.md @@ -4,10 +4,10 @@ ### 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") +![alt text](../../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") +![alt text](../../assets/images/keepexpressinweb.gif "Geruzak nahastearen eragozpena") diff --git a/sections/projectstructre/createlayers.brazilian-portuguese.md b/sections/projectstructre/createlayers.brazilian-portuguese.md index 8990640f5..8d015ce45 100644 --- a/sections/projectstructre/createlayers.brazilian-portuguese.md +++ b/sections/projectstructre/createlayers.brazilian-portuguese.md @@ -4,10 +4,10 @@ ### Separe o código do componente em camadas: web, serviços e DAL -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebycomponents.PNG "Separe o código do componente em camadas") +![alt text](../../assets/images/structurebycomponents.PNG "Separe o código do componente em camadas")

### Explicação em 1 minuto: A desvantagem de misturar camadas -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/keepexpressinweb.gif "A desvantagem de misturar camadas") +![alt text](../../assets/images/keepexpressinweb.gif "A desvantagem de misturar camadas") diff --git a/sections/projectstructre/createlayers.chinese.md b/sections/projectstructre/createlayers.chinese.md index 0ab1cc1e9..4d431f0f9 100644 --- a/sections/projectstructre/createlayers.chinese.md +++ b/sections/projectstructre/createlayers.chinese.md @@ -3,9 +3,9 @@

### 将组件代码分成web, services, DAL层 -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebycomponents.PNG "Separate component code into layers") +![alt text](../../assets/images/structurebycomponents.PNG "Separate component code into layers")

### 1分钟说明:混合层的缺点 -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/keepexpressinweb.gif "The downside of mixing layers") +![alt text](../../assets/images/keepexpressinweb.gif "The downside of mixing layers") diff --git a/sections/projectstructre/createlayers.french.md b/sections/projectstructre/createlayers.french.md index f514e4405..a6d4d4d7e 100644 --- a/sections/projectstructre/createlayers.french.md +++ b/sections/projectstructre/createlayers.french.md @@ -4,10 +4,10 @@ ### Séparez le code des composants en strates : web, services et couche d'accès aux données (DAL) -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebycomponents.PNG "Séparez le code des composants en strates") +![alt text](../../assets/images/structurebycomponents.PNG "Séparez le code des composants en strates")

### Explication en 1 min : l'inconvénient de mélanger les strates -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/keepexpressinweb.gif "L'inconvénient de mélanger les strates") +![alt text](../../assets/images/keepexpressinweb.gif "L'inconvénient de mélanger les strates") diff --git a/sections/projectstructre/createlayers.japanese.md b/sections/projectstructre/createlayers.japanese.md index e6c1356cf..dda7fb23c 100644 --- a/sections/projectstructre/createlayers.japanese.md +++ b/sections/projectstructre/createlayers.japanese.md @@ -4,10 +4,10 @@ ### コンポーネントコードをウェブ、サービス、DAL のレイヤーに分ける -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebycomponents.PNG "コンポーネントコードを階層化する") +![alt text](../../assets/images/structurebycomponents.PNG "コンポーネントコードを階層化する")

### 1分解説: レイヤーを混ぜることのデメリット -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/keepexpressinweb.gif "レイヤーを混ぜることのデメリット") +![alt text](../../assets/images/keepexpressinweb.gif "レイヤーを混ぜることのデメリット") diff --git a/sections/projectstructre/createlayers.korean.md b/sections/projectstructre/createlayers.korean.md index c1d89a628..0278b8f20 100644 --- a/sections/projectstructre/createlayers.korean.md +++ b/sections/projectstructre/createlayers.korean.md @@ -4,10 +4,10 @@ ### 컴포넌트 코드를 웹, 서비스, 데이터 접근 언어(DAL) 계층으로 나누어라 -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebycomponents.PNG "Separate component code into layers") +![alt text](../../assets/images/structurebycomponents.PNG "Separate component code into layers")

### 1분 설명: 계층을 섞으면 불리한 점 -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/keepexpressinweb.gif "The downside of mixing layers") +![alt text](../../assets/images/keepexpressinweb.gif "The downside of mixing layers") diff --git a/sections/projectstructre/createlayers.md b/sections/projectstructre/createlayers.md index 802452b28..f67f88cec 100644 --- a/sections/projectstructre/createlayers.md +++ b/sections/projectstructre/createlayers.md @@ -2,12 +2,27 @@

- ### Separate component code into layers: web, services, and Data Access Layer (DAL) +### Separate component code into 3 layers -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebycomponents.PNG "Separate component code into layers") +The root of every component should hold 3 folders that represent common concerns and stages of every transaction: -

+```bash +my-system +├─ apps (components) +│ ├─ component-a + │ ├─ entry-points + │ │ ├─ api # controller comes here + │ │ ├─ message-queue # message consumer comes here + │ ├─ domain # features and flows: DTO, services, logic + │ ├─ data-access # DB calls w/o ORM +``` -### 1 min explainer: The downside of mixing layers +**- Entry-points -** This is where requests and flows start, whether it's REST API, Graph, message queue, scheduled jobs or any other _door_ to the application. This layer's responsibility is quite minimal - adapt the payload (e.g., JSON) to the app format, including first validation, call the logic/domain layer and return a response. This is typically achieved with a few lines of code. Many use the term "controller" for this type of code also technically, its just an adapter -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/keepexpressinweb.gif "The downside of mixing layers") +**- Domain -** This is where the app flows, logic and data live. This layer accepts protocol-agnostic payload, plain JavaScript object and returns one as well. Technically it contains common code objects like services, dto/entities, and clients that call external services. It also typically calls the data-access layer to retrieve or persist information + +**- Data-access -** This is where the app holds code that interacts with DB. Ideally, it should externalize an interface that returns/gets plain JavaScript object that is DB agnostic (also known as the repository-pattern). This layer involves DB helper utilities like query builders, ORMs, DB drivers and other implementation libraries + +**What is the merit? -** When having flexible infrastructure that allows adding more API calls and DB queries promptly, a developer can code a feature faster by focusing on the domain folder. In other words, less time is spent on technical activities and more on activities with added value. This is a ubiquitous trait that is at the heart of most software architectures like DDD, hexagonal, clean-architecture and others. On top of this, when the domain layer is not aware of any edge protocol, it can serve any client and not only HTTP calls + +**Why not MVC or clean architecture? -** The 3-tier pattern strikes a great balance between achieving the separation goal while still keeping the structure simple. It also lacks abstractions - each tier represents real-world physical tier where every request will visit. On the other hand, MVC is a simplistic pattern where the letters VC represent a few lines of a code only and the letter M means anything else. Clean architecture is architecture with high level of abstractions that can achieve even greater separation but the price tag is unproportionally higher due to the increased complexity \ No newline at end of file diff --git a/sections/projectstructre/createlayers.polish.md b/sections/projectstructre/createlayers.polish.md index 6c068cd8e..a9d30263c 100644 --- a/sections/projectstructre/createlayers.polish.md +++ b/sections/projectstructre/createlayers.polish.md @@ -4,10 +4,10 @@ ### Rozdziel kod komponentu na warstwy: sieć, usługi i DAL -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebycomponents.PNG "Separate component code into layers") +![alt text](../../assets/images/structurebycomponents.PNG "Separate component code into layers")

### 1 minuta wyjaśniania: Minusem mieszanie warstw -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/keepexpressinweb.gif "The downside of mixing layers") +![alt text](../../assets/images/keepexpressinweb.gif "The downside of mixing layers") diff --git a/sections/projectstructre/createlayers.russian.md b/sections/projectstructre/createlayers.russian.md index 00d5e69ba..b7c2865b0 100644 --- a/sections/projectstructre/createlayers.russian.md +++ b/sections/projectstructre/createlayers.russian.md @@ -4,10 +4,10 @@ ### Разделить код компонента на слои: веб, сервисы и DAL -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebycomponents.PNG "Separate component code into layers") +![alt text](../../assets/images/structurebycomponents.PNG "Separate component code into layers")

### 1 минутное объяснение: обратная сторона смешения слоев -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/keepexpressinweb.gif "The downside of mixing layers") +![alt text](../../assets/images/keepexpressinweb.gif "The downside of mixing layers") diff --git a/sections/projectstructre/separateexpress.md b/sections/projectstructre/separateexpress.md deleted file mode 100644 index e35c67d24..000000000 --- a/sections/projectstructre/separateexpress.md +++ /dev/null @@ -1,100 +0,0 @@ -# Separate Express 'app' and 'server' - -

- -### One Paragraph Explainer - -The latest Express generator comes with a great practice that is worth to keep - the API declaration is separated from the network related configuration (port, protocol, etc). This allows testing the API in-process, without performing network calls, with all the benefits that it brings to the table: fast testing execution and getting coverage metrics of the code. It also allows deploying the same API under flexible and different network conditions. Bonus: better separation of concerns and cleaner code - -

- -### Code example: API declaration, should reside in app.js/app.ts - -```javascript -const app = express(); -app.use(bodyParser.json()); -app.use('/api/events', events.API); -app.use('/api/forms', forms); -``` - -### Code example: Server network declaration, should reside in /bin/www - -
-Javascript - -```javascript -const app = require('../app'); -const http = require('http'); - -// Get port from environment and store in Express. -const port = normalizePort(process.env.PORT || '3000'); -app.set('port', port); - -// Create HTTP server. -const server = http.createServer(app); -``` -
- -
-Typescript - -```typescript -import app from '../app'; -import http from 'http'; - -// Get port from environment and store in Express. -const port = normalizePort(process.env.PORT || '3000'); -app.set('port', port); - -// Create HTTP server. -const server = http.createServer(app); -``` -
- -### Example: test your API in-process using supertest (popular testing package) - -
-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/thincomponents.chinese.md b/sections/projectstructre/thincomponents.chinese.md index 6fc193ed3..5b036ddb4 100644 --- a/sections/projectstructre/thincomponents.chinese.md +++ b/sections/projectstructre/thincomponents.chinese.md @@ -18,9 +18,9 @@

### 推荐: 通过自包含的组件来构造解决方案 -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebycomponents.PNG "Structuring solution by components") +![alt text](../../assets/images/structurebycomponents.PNG "Structuring solution by components")

### 避免: 通过技术角色对文件进行分组 -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebyroles.PNG "Structuring solution by technical roles") +![alt text](../../assets/images/structurebyroles.PNG "Structuring solution by technical roles") diff --git a/sections/projectstructre/thincomponents.french.md b/sections/projectstructre/thincomponents.french.md index eb3abde05..91c5e05c0 100644 --- a/sections/projectstructre/thincomponents.french.md +++ b/sections/projectstructre/thincomponents.french.md @@ -18,10 +18,10 @@ Pour les applications de taille moyenne et supérieure, les monolithes sont vrai ### Bon : Organisez votre solution avec des composants autonomes -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebycomponents.PNG "Solution d'organisation par composants") +![alt text](../../assets/images/structurebycomponents.PNG "Solution d'organisation par composants")

### Mauvais : Regroupez vos fichiers selon leur rôle technique -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebyroles.PNG "Solution d'organisation par rôles techniques") +![alt text](../../assets/images/structurebyroles.PNG "Solution d'organisation par rôles techniques") diff --git a/sections/projectstructre/thincomponents.japanese.md b/sections/projectstructre/thincomponents.japanese.md index 7d5535b6e..e586d6884 100644 --- a/sections/projectstructre/thincomponents.japanese.md +++ b/sections/projectstructre/thincomponents.japanese.md @@ -18,10 +18,10 @@ For medium sized apps and above, monoliths are really bad - one big software wit ### Good: Structure your solution by self-contained components -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebycomponents.PNG "Structuring solution by components") +![alt text](../../assets/images/structurebycomponents.PNG "Structuring solution by components")

### Bad: Group your files by technical role -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebyroles.PNG "Structuring solution by technical roles") +![alt text](../../assets/images/structurebyroles.PNG "Structuring solution by technical roles") diff --git a/sections/projectstructre/thincomponents.md b/sections/projectstructre/thincomponents.md index 7d5535b6e..e586d6884 100644 --- a/sections/projectstructre/thincomponents.md +++ b/sections/projectstructre/thincomponents.md @@ -18,10 +18,10 @@ For medium sized apps and above, monoliths are really bad - one big software wit ### Good: Structure your solution by self-contained components -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebycomponents.PNG "Structuring solution by components") +![alt text](../../assets/images/structurebycomponents.PNG "Structuring solution by components")

### Bad: Group your files by technical role -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebyroles.PNG "Structuring solution by technical roles") +![alt text](../../assets/images/structurebyroles.PNG "Structuring solution by technical roles") diff --git a/sections/projectstructre/thincomponents.russian.md b/sections/projectstructre/thincomponents.russian.md index 394f3dbe6..6f3c6a1be 100644 --- a/sections/projectstructre/thincomponents.russian.md +++ b/sections/projectstructre/thincomponents.russian.md @@ -18,10 +18,10 @@ ### Хорошо: структурируйте свое решение по отдельным компонентам -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebycomponents.PNG "Structuring solution by components") +![alt text](../../assets/images/structurebycomponents.PNG "Structuring solution by components")

### Плохо: сгруппируйте файлы по техническим ролям -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebyroles.PNG "Structuring solution by technical roles") +![alt text](../../assets/images/structurebyroles.PNG "Structuring solution by technical roles") diff --git a/sections/projectstructre/typescript-considerations.md b/sections/projectstructre/typescript-considerations.md new file mode 100644 index 000000000..fcf881111 --- /dev/null +++ b/sections/projectstructre/typescript-considerations.md @@ -0,0 +1,23 @@ +# Use TypeScript sparingly and thoughtfully + +

+ +### One Paragraph Explainer + +TypeScript has won the community's hearts and is almost a standard for modern JavaScript apps. Compared to plain JS, it brings much better coding ergonomics, facilitates editor code completions, even for historical libraries that were written with JavaScript and was proven to [prevent specific type of bugs](https://earlbarr.com/publications/typestudy.pdf). With that, if you look carefully under the hype, TypeScript actually brings two **mutually-exclusive** offerings to the table: type-safety and advanced design constructs like abstract classes, interfaces, namespaces and more. Many teams chose TypeScript for better type safety yet _unintentionally_, without any proper planning, use it for other purposes, such as OOP. These teams change their design style unintentionally due to the ['law of the instruments'](https://en.wikipedia.org/wiki/Law_of_the_instrument) — a cognitive bias that involves using the tooling in hand whether they are the right choice for the mission or not. In other words, if an 'abstract class' exists in the toolbox — developers will use it. If teams consciously opted for the coding techniques mentioned above — that's fair and legit. For others, positively consider coding with classic JavaScript, plain functions and objects, which are simply decorated with primitive types. The latter option is likely to result in lower complexity + +

+ +### Research Quote: "15% less bugs" + +From the research [To Type or Not to Type](https://earlbarr.com/publications/typestudy.pdf) + +> "our central finding is that both static type systems find an important percentage of public bugs: both Flow 0.30 and TypeScript 2.0 successfully detect 15%!" + +

+ +### Blog Quote: "TypeScript will always miss 80% of bugs" + +From the post [The TypeScript tax](https://medium.com/javascript-scene/the-typescript-tax-132ff4cb175b) + +> "Some will argue that TypeScript provides realtime bug feedback, so you can catch the bugs earlier, but so do type inference, lint, and testing... You may argue that these other measures have a cost, but because TypeScript will always miss 80% of bugs, you can’t safely skip them either way, so their cost applies to both sides of the ROI math, and is already factored in" diff --git a/sections/projectstructre/wraputilities.basque.md b/sections/projectstructre/wraputilities.basque.md index cb4d64067..18efeeb0f 100644 --- a/sections/projectstructre/wraputilities.basque.md +++ b/sections/projectstructre/wraputilities.basque.md @@ -12,4 +12,4 @@ Hazten hasi eta zerbitzari ezberdinetan antzeko baliabideak erabiltzen dituzten ### Partekatu zure baliabide propioak ingurune eta osagaietan -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/Privatenpm.png "Antolatu proiektua osagaietan") +![alt text](../../assets/images/Privatenpm.png "Antolatu proiektua osagaietan") diff --git a/sections/projectstructre/wraputilities.brazilian-portuguese.md b/sections/projectstructre/wraputilities.brazilian-portuguese.md index c054b4d04..13d54d763 100644 --- a/sections/projectstructre/wraputilities.brazilian-portuguese.md +++ b/sections/projectstructre/wraputilities.brazilian-portuguese.md @@ -10,4 +10,4 @@ Quando você começa a crescer e tem componentes diferentes em servidores difere ### Compartilhando seus próprios utilitários comuns em ambientes e componentes -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/Privatenpm.png "Solução de estruturação por componentes") +![alt text](../../assets/images/Privatenpm.png "Solução de estruturação por componentes") diff --git a/sections/projectstructre/wraputilities.chinese.md b/sections/projectstructre/wraputilities.chinese.md index 15511bf97..aa9e1a96b 100644 --- a/sections/projectstructre/wraputilities.chinese.md +++ b/sections/projectstructre/wraputilities.chinese.md @@ -11,4 +11,4 @@ ### 在环境和组件中共享你自己的公用实用工具 -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/Privatenpm.png "构建解决方案的组件") +![alt text](../../assets/images/Privatenpm.png "构建解决方案的组件") diff --git a/sections/projectstructre/wraputilities.french.md b/sections/projectstructre/wraputilities.french.md index 661d1b84a..523c5fc52 100644 --- a/sections/projectstructre/wraputilities.french.md +++ b/sections/projectstructre/wraputilities.french.md @@ -10,4 +10,4 @@ Une fois que vous commencez à vous développer et que vous avez différents com ### Partage de vos propres utilitaires communs entre les environnements et les composants -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/Privatenpm.png "Solution d'organisation par composants") +![alt text](../../assets/images/Privatenpm.png "Solution d'organisation par composants") diff --git a/sections/projectstructre/wraputilities.japanese.md b/sections/projectstructre/wraputilities.japanese.md index b9a703d05..52060026e 100644 --- a/sections/projectstructre/wraputilities.japanese.md +++ b/sections/projectstructre/wraputilities.japanese.md @@ -10,4 +10,4 @@ ### 環境やコンポーネント横断で独自の共通ユーティリティを共有する -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/Privatenpm.png "コンポーネントでソリューションを構築する") +![alt text](../../assets/images/Privatenpm.png "コンポーネントでソリューションを構築する") diff --git a/sections/projectstructre/wraputilities.korean.md b/sections/projectstructre/wraputilities.korean.md index 9265ea317..8bfaf69a8 100644 --- a/sections/projectstructre/wraputilities.korean.md +++ b/sections/projectstructre/wraputilities.korean.md @@ -10,4 +10,4 @@ ### 당신만의 공유 유틸리티들을 환경과 컴포넌츠에 공유하기 -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/Privatenpm.png "Structuring solution by components") +![alt text](../../assets/images/Privatenpm.png "Structuring solution by components") diff --git a/sections/projectstructre/wraputilities.md b/sections/projectstructre/wraputilities.md index ed3639007..4d9e3da62 100644 --- a/sections/projectstructre/wraputilities.md +++ b/sections/projectstructre/wraputilities.md @@ -10,4 +10,4 @@ Once you start growing and have different components on different servers which ### Sharing your own common utilities across environments and components -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/Privatenpm.png "Structuring solution by components") +![alt text](../../assets/images/Privatenpm.png "Structuring solution by components") diff --git a/sections/projectstructre/wraputilities.polish.md b/sections/projectstructre/wraputilities.polish.md index e823509de..bbd4432a1 100644 --- a/sections/projectstructre/wraputilities.polish.md +++ b/sections/projectstructre/wraputilities.polish.md @@ -10,4 +10,4 @@ Kiedy zaczniesz się rozwijać i będziesz mieć różne komponenty na różnych ### Udostępnianie własnych wspólnych narzędzi w różnych środowiskach i komponentach -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/Privatenpm.png "Structuring solution by components") +![alt text](../../assets/images/Privatenpm.png "Structuring solution by components") diff --git a/sections/projectstructre/wraputilities.russian.md b/sections/projectstructre/wraputilities.russian.md index 02a1fac70..3520ef383 100644 --- a/sections/projectstructre/wraputilities.russian.md +++ b/sections/projectstructre/wraputilities.russian.md @@ -10,4 +10,4 @@ ### Совместное использование собственных общих утилит в средах и компонентах -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/Privatenpm.png "Structuring solution by components") +![alt text](../../assets/images/Privatenpm.png "Structuring solution by components") diff --git a/sections/security/limitrequests.md b/sections/security/limitrequests.md index 21482d050..0763a3b57 100644 --- a/sections/security/limitrequests.md +++ b/sections/security/limitrequests.md @@ -8,12 +8,10 @@ Rate limiting should be implemented in your application to protect a Node.js app ```javascript const http = require('http'); - const redis = require('redis'); + const IoRedis = require('ioredis'); const { RateLimiterRedis } = require('rate-limiter-flexible'); - const redisClient = redis.createClient({ - enable_offline_queue: false, - }); + const redisClient = new IoRedis({ enableOfflineQueue: false }); // Maximum 20 requests per second const rateLimiter = new RateLimiterRedis({ diff --git a/sections/security/limitrequests.spanish.md b/sections/security/limitrequests.spanish.md index f8ec9349f..3943279bc 100644 --- a/sections/security/limitrequests.spanish.md +++ b/sections/security/limitrequests.spanish.md @@ -8,13 +8,11 @@ Rate limiting should be implemented in your application to protect a Node.js app ```javascript const http = require('http'); - const redis = require('redis'); + const IoRedis = require('ioredis'); const { RateLimiterRedis } = require('rate-limiter-flexible'); - const redisClient = redis.createClient({ - enable_offline_queue: false, - }); + const redisClient = new IoRedis({ enableOfflineQueue: false }); // Maximum 20 requests per second const rateLimiter = new RateLimiterRedis({ diff --git a/sections/security/requestpayloadsizelimit.japanese.md b/sections/security/requestpayloadsizelimit.japanese.md index 8dc1017f8..cd0deb041 100644 --- a/sections/security/requestpayloadsizelimit.japanese.md +++ b/sections/security/requestpayloadsizelimit.japanese.md @@ -1,4 +1,4 @@ -# Limit payload size using a reverse-proxy or a middleware +# リバースプロキシまたはミドルウェアを使用してペイロードのサイズを制限する ### 一段落説明 diff --git a/sections/security/secretmanagement.japanese.md b/sections/security/secretmanagement.japanese.md index 739385f89..4d1cd5c4e 100644 --- a/sections/security/secretmanagement.japanese.md +++ b/sections/security/secretmanagement.japanese.md @@ -20,7 +20,7 @@ Node.js アプリケーションにキーやシークレットを渡すための const blobService = azure.createBlobService(apiKey); ``` -`cryptr` を死傷して暗号化されたシークレットを保存する: +`cryptr` を使用して暗号化されたシークレットを保存する: ```javascript const Cryptr = require('cryptr'); diff --git a/sections/template.basque.md b/sections/template.basque.md index 0c3fb0375..684837ecc 100644 --- a/sections/template.basque.md +++ b/sections/template.basque.md @@ -34,14 +34,14 @@ Blogean, pouchdb.comek “Node Promesak hitz gakoarentzat 11.posizioa du ### 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") +![alt text](../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") +![alt text](../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") +![alt text](../assets/images/codeanalysis-sonarqube-dashboard.PNG "Kode analisiaren historia")

diff --git a/sections/template.md b/sections/template.md index d4c154f29..9ff2cc381 100644 --- a/sections/template.md +++ b/sections/template.md @@ -34,15 +34,15 @@ code here ### Example: Complex methods analysis with CodeClimate (commercial) -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/codeanalysis-climate-complex-methods.PNG "Complex methods analysis") +![alt text](../assets/images/codeanalysis-climate-complex-methods.PNG "Complex methods analysis") ### Example: Code analysis trends and history with CodeClimate (commercial) -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/codeanalysis-climate-history.PNG "Code analysis history") +![alt text](../assets/images/codeanalysis-climate-history.PNG "Code analysis history") ### Example: Code analysis summary and trends with SonarQube (commercial) -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/codeanalysis-sonarqube-dashboard.PNG "Code analysis history") +![alt text](../assets/images/codeanalysis-sonarqube-dashboard.PNG "Code analysis history")

diff --git a/sections/testingandquality/3-parts-in-name.basque.md b/sections/testingandquality/3-parts-in-name.basque.md index 61d030ea9..0fc762eb0 100644 --- a/sections/testingandquality/3-parts-in-name.basque.md +++ b/sections/testingandquality/3-parts-in-name.basque.md @@ -50,6 +50,6 @@ describe('Produktu Zerbitzua', () => { ["30 Node.jsren proba jarraibide 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") +![Proba txostenaren adibidea](../../assets/images/test-report-like-requirements.jpeg "Proba txostenaren adibidea")

diff --git a/sections/testingandquality/3-parts-in-name.brazilian-portuguese.md b/sections/testingandquality/3-parts-in-name.brazilian-portuguese.md index 97ddc0479..497dc6dfd 100644 --- a/sections/testingandquality/3-parts-in-name.brazilian-portuguese.md +++ b/sections/testingandquality/3-parts-in-name.brazilian-portuguese.md @@ -49,6 +49,6 @@ describe('Serviço de Produtos', function() { [Do blog "30 Node.js testing best practices" por Yoni Goldberg](https://medium.com/@me_37286/yoni-goldberg-javascript-nodejs-testing-best-practices-2b98924c9347) - ![Um exemplo de relatório de teste](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/test-report-like-requirements.jpeg "Um exemplo de relatório de teste") + ![Um exemplo de relatório de teste](../../assets/images/test-report-like-requirements.jpeg "Um exemplo de relatório de teste") -

\ No newline at end of file +

diff --git a/sections/testingandquality/3-parts-in-name.french.md b/sections/testingandquality/3-parts-in-name.french.md index b3365a54a..083dd76eb 100644 --- a/sections/testingandquality/3-parts-in-name.french.md +++ b/sections/testingandquality/3-parts-in-name.french.md @@ -49,6 +49,6 @@ describe('Service Produits', () => { [Extrait du blog de « 30 bonnes pratiques de test avec Node.js » par Yoni Goldberg](https://medium.com/@me_37286/yoni-goldberg-javascript-nodejs-testing-best-practices-2b98924c9347) - ![Un exemple de rapport de test](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/test-report-like-requirements.jpeg "Un exemple de rapport de test") + ![Un exemple de rapport de test](../../assets/images/test-report-like-requirements.jpeg "Un exemple de rapport de test") -

\ No newline at end of file +

diff --git a/sections/testingandquality/3-parts-in-name.japanese.md b/sections/testingandquality/3-parts-in-name.japanese.md index 4227662e3..4766a57f8 100644 --- a/sections/testingandquality/3-parts-in-name.japanese.md +++ b/sections/testingandquality/3-parts-in-name.japanese.md @@ -49,6 +49,6 @@ describe('Products Service', () => { [Yoni Goldberg によるブログ記事 "30 Node.js testing best practices"](https://medium.com/@me_37286/yoni-goldberg-javascript-nodejs-testing-best-practices-2b98924c9347) - ![テストレポートの例](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/test-report-like-requirements.jpeg "テストレポートの例") + ![テストレポートの例](../../assets/images/test-report-like-requirements.jpeg "テストレポートの例") -

\ No newline at end of file +

diff --git a/sections/testingandquality/3-parts-in-name.md b/sections/testingandquality/3-parts-in-name.md index 0568937c5..4319b4341 100644 --- a/sections/testingandquality/3-parts-in-name.md +++ b/sections/testingandquality/3-parts-in-name.md @@ -14,7 +14,7 @@ A test report should tell whether the current application revision satisfies the

-### Code example: a test name that incluces 3 parts +### Code example: a test name that includes 3 parts ```javascript //1. unit under test describe('Products Service', () => { @@ -49,6 +49,6 @@ describe('Products Service', () => { [From the blog "30 Node.js testing best practices" by Yoni Goldberg](https://medium.com/@me_37286/yoni-goldberg-javascript-nodejs-testing-best-practices-2b98924c9347) - ![A test report example](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/test-report-like-requirements.jpeg "A test report example") + ![A test report example](../../assets/images/test-report-like-requirements.jpeg "A test report example")

diff --git a/sections/testingandquality/3-parts-in-name.polish.md b/sections/testingandquality/3-parts-in-name.polish.md index ca6beff51..1f2821c1d 100644 --- a/sections/testingandquality/3-parts-in-name.polish.md +++ b/sections/testingandquality/3-parts-in-name.polish.md @@ -49,6 +49,6 @@ describe('Products Service', () => { [Z bloga "30 Node.js testing best practices" od Yoni Goldberg](https://medium.com/@me_37286/yoni-goldberg-javascript-nodejs-testing-best-practices-2b98924c9347) - ![Przykład raportu testu](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/test-report-like-requirements.jpeg "A test report example") + ![Przykład raportu testu](../../assets/images/test-report-like-requirements.jpeg "A test report example")

diff --git a/sections/testingandquality/3-parts-in-name.russian.md b/sections/testingandquality/3-parts-in-name.russian.md index 17c4131c0..ddf7f9ace 100644 --- a/sections/testingandquality/3-parts-in-name.russian.md +++ b/sections/testingandquality/3-parts-in-name.russian.md @@ -49,6 +49,6 @@ describe('Products Service', () => { [From the blog "30 Node.js testing best practices" by Yoni Goldberg](https://medium.com/@me_37286/yoni-goldberg-javascript-nodejs-testing-best-practices-2b98924c9347) - ![A test report example](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/test-report-like-requirements.jpeg "A test report example") + ![A test report example](../../assets/images/test-report-like-requirements.jpeg "A test report example") -

\ No newline at end of file +

diff --git a/sections/testingandquality/bumpversion.japanese.md b/sections/testingandquality/bumpversion.japanese.md index 56e66ff1d..8e5714058 100644 --- a/sections/testingandquality/bumpversion.japanese.md +++ b/sections/testingandquality/bumpversion.japanese.md @@ -24,4 +24,4 @@ code here ### Image title -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/swaggerDoc.png "API error handling") +![alt text](../../assets/images/swaggerDoc.png "API error handling") diff --git a/sections/testingandquality/bumpversion.md b/sections/testingandquality/bumpversion.md index 56e66ff1d..8e5714058 100644 --- a/sections/testingandquality/bumpversion.md +++ b/sections/testingandquality/bumpversion.md @@ -24,4 +24,4 @@ code here ### Image title -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/swaggerDoc.png "API error handling") +![alt text](../../assets/images/swaggerDoc.png "API error handling") diff --git a/sections/testingandquality/citools.basque.md b/sections/testingandquality/citools.basque.md index 29fe6cdc7..78059d822 100644 --- a/sections/testingandquality/citools.basque.md +++ b/sections/testingandquality/citools.basque.md @@ -42,10 +42,10 @@ jobs: ### Circle CI: ia zero prestakuntzadun hodeieko IEa -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/circleci.png "API erroreen kudeaketa") +![alt text](../../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") +![alt text](../../assets/images/jenkins_dashboard.png "API erroreen kudeaketa")

diff --git a/sections/testingandquality/citools.brazilian-portuguese.md b/sections/testingandquality/citools.brazilian-portuguese.md index 741a5cb80..fff68be52 100644 --- a/sections/testingandquality/citools.brazilian-portuguese.md +++ b/sections/testingandquality/citools.brazilian-portuguese.md @@ -42,10 +42,10 @@ jobs: ### Circle CI - CI com quase zero configuração em nuvem -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/circleci.png "manipulador de erros do API") +![alt text](../../assets/images/circleci.png "manipulador de erros do API") ### Jenkins - CI sofisticado e robusto -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/jenkins_dashboard.png "manipulador de erros do API") +![alt text](../../assets/images/jenkins_dashboard.png "manipulador de erros do API")

diff --git a/sections/testingandquality/citools.chinese.md b/sections/testingandquality/citools.chinese.md index 21495796d..0817c59b6 100644 --- a/sections/testingandquality/citools.chinese.md +++ b/sections/testingandquality/citools.chinese.md @@ -44,10 +44,10 @@ jobs: ### Circle CI - 几乎零设置的云CI -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/circleci.png "API error handling") +![alt text](../../assets/images/circleci.png "API error handling") ### Jenkins - 完善和强大的CI -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/jenkins_dashboard.png "API error handling") +![alt text](../../assets/images/jenkins_dashboard.png "API error handling")

diff --git a/sections/testingandquality/citools.french.md b/sections/testingandquality/citools.french.md index 9e27ea763..8b33bc1d7 100644 --- a/sections/testingandquality/citools.french.md +++ b/sections/testingandquality/citools.french.md @@ -42,10 +42,10 @@ jobs: ### Circle CI - CI du cloud avec une configuration presque nul -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/circleci.png "Gestion des erreurs API") +![alt text](../../assets/images/circleci.png "Gestion des erreurs API") ### Jenkins - CI sophistiqué et robuste -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/jenkins_dashboard.png "Gestion des erreurs API") +![alt text](../../assets/images/jenkins_dashboard.png "Gestion des erreurs API")

diff --git a/sections/testingandquality/citools.japanese.md b/sections/testingandquality/citools.japanese.md index 3b1d22120..787cfa333 100644 --- a/sections/testingandquality/citools.japanese.md +++ b/sections/testingandquality/citools.japanese.md @@ -42,10 +42,10 @@ jobs: ### Circle CI - ほぼ設定の必要ないクラウド CI -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/circleci.png "Circle CI") +![alt text](../../assets/images/circleci.png "Circle CI") ### Jenkins - 洗練された、堅牢な CI -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/jenkins_dashboard.png "Jenkins") +![alt text](../../assets/images/jenkins_dashboard.png "Jenkins")

diff --git a/sections/testingandquality/citools.korean.md b/sections/testingandquality/citools.korean.md index 96eb69110..30ea58f2d 100644 --- a/sections/testingandquality/citools.korean.md +++ b/sections/testingandquality/citools.korean.md @@ -4,7 +4,7 @@ ### One Paragraph Explainer -The CI world used to be the flexibility of [Jenkins](https://jenkins.io/) vs the simplicity of SaaS vendors. The game is now changing as SaaS providers like [CircleCI](https://circleci.com/) and [Travis](https://travis-ci.org/) offer robust solutions including Docker containers with minimum setup time while Jenkins tries to compete on 'simplicity' segment as well. Though one can setup rich CI solution in the cloud, should it required to control the finest details Jenkins is still the platform of choice. The choice eventually boils down to which extent the CI process should be customized: free and setup free cloud vendors allow to run custom shell commands, custom docker images, adjust the workflow, run matrix builds and other rich features. However, if controlling the infrastructure or programming the CI logic using a formal programming language like Java is desired - Jenkins might still be the choice. Otherwise, consider opting for the simple and setup free cloud option +CI 환경은 [Jenkins](https://jenkins.io/)의 유연성과 SaaS 공급업체의 단순성을 비교한 결과였습니다. 현재 [CircleCI](https://circleci.com/) 및 [Travis](https://travis-ci.org/))와 같은 SaaS 제공업체가 최소 설정 시간을 가진 도커 컨테이너를 포함한 강력한 솔루션을 제공하는 반면 Jenkins는 '유효성' 부문에서도 경쟁하려고 노력함에 따라 판도가 바뀌고 있다. 클라우드에서 풍부한 CI 솔루션을 설정할 수 있지만, 세부 정보를 제어해야 하는 경우 Jenkins가 여전히 선택하는 플랫폼입니다. 선택은 결국 CI 프로세스를 어느 정도까지 커스터마이징해야 하는지로 귀결됩니다. 무료 및 설치 클라우드 공급업체는 맞춤형 셸 명령, 사용자 지정 도커 이미지 실행, 워크플로우 조정, 매트릭스 빌드 실행 및 기타 다양한 기능을 사용할 수 있습니다. 그러나 인프라를 제어하거나 Java와 같은 공식 프로그래밍 언어를 사용하여 CI 로직을 프로그래밍하려는 경우에는 Jenkins를 선택할 수 있습니다. 그렇지 않으면 간편하고 무료 클라우드 설정 옵션을 선택하는 것이 좋습니다.

@@ -33,7 +33,7 @@ jobs: command: npm test - run: name: Generate code coverage - command: './node_modules/.bin/nyc report --reporter=text-lcov' + command: './node_modules/.bin/nyc report --reporter=text-lcov' - store_artifacts: path: coverage prefix: coverage @@ -42,10 +42,10 @@ jobs: ### Circle CI - almost zero setup cloud CI -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/circleci.png "API error handling") +![alt text](../../assets/images/circleci.png "API error handling") -### Jenkins - sophisticated and robust CI +### Jenkins - sophisticated and robust CI -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/jenkins_dashboard.png "API error handling") +![alt text](../../assets/images/jenkins_dashboard.png "API error handling")

diff --git a/sections/testingandquality/citools.md b/sections/testingandquality/citools.md deleted file mode 100644 index 16c6c16ae..000000000 --- a/sections/testingandquality/citools.md +++ /dev/null @@ -1,51 +0,0 @@ -# Carefully choose your CI platform - -

- -### One Paragraph Explainer - -The CI world used to be the flexibility of [Jenkins](https://jenkins.io/) vs the simplicity of SaaS vendors. The game is now changing as SaaS providers like [CircleCI](https://circleci.com/) and [Travis](https://travis-ci.org/) offer robust solutions including Docker containers with minimum setup time while Jenkins tries to compete on 'simplicity' segment as well. Though one can setup rich CI solution in the cloud, should it required to control the finest details Jenkins is still the platform of choice. The choice eventually boils down to which extent the CI process should be customized: free and setup free cloud vendors allow to run custom shell commands, custom docker images, adjust the workflow, run matrix builds and other rich features. However, if controlling the infrastructure or programming the CI logic using a formal programming language like Java is desired - Jenkins might still be the choice. Otherwise, consider opting for the simple and setup free cloud option - -

- -### Code Example – a typical cloud CI configuration. Single .yml file and that's it - -```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 - almost zero setup cloud CI - -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/circleci.png "API error handling") - -### Jenkins - sophisticated and robust CI - -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/jenkins_dashboard.png "API error handling") - -

diff --git a/sections/testingandquality/citools.polish.md b/sections/testingandquality/citools.polish.md index ae98f0a69..060bdd561 100644 --- a/sections/testingandquality/citools.polish.md +++ b/sections/testingandquality/citools.polish.md @@ -42,10 +42,10 @@ jobs: ### Circle CI - prawie zerowa konfiguracja CI w chmurze -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/circleci.png "API error handling") +![alt text](../../assets/images/circleci.png "API error handling") ### Jenkins - wyrafinowany i solidny CI -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/jenkins_dashboard.png "API error handling") +![alt text](../../assets/images/jenkins_dashboard.png "API error handling")

diff --git a/sections/testingandquality/citools.russian.md b/sections/testingandquality/citools.russian.md index f46905269..e3c69b509 100644 --- a/sections/testingandquality/citools.russian.md +++ b/sections/testingandquality/citools.russian.md @@ -42,10 +42,10 @@ jobs: ### Circle CI - почти нулевая настройка облака CI -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/circleci.png "API error handling") +![alt text](../../assets/images/circleci.png "API error handling") ### Дженкинс - сложный и надежный CI -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/jenkins_dashboard.png "API error handling") +![alt text](../../assets/images/jenkins_dashboard.png "API error handling")

diff --git a/sections/testingandquality/mock-external-services.md b/sections/testingandquality/mock-external-services.md new file mode 100644 index 000000000..6def85708 --- /dev/null +++ b/sections/testingandquality/mock-external-services.md @@ -0,0 +1,88 @@ +# Mock responses of external HTTP services + +

+ +### One Paragraph Explainer + +Isolate the component under test by intercepting any outgoing HTTP request and providing the desired response so the collaborator HTTP API won't get hit. Nock is a great tool for this mission as it provides a convenient syntax for defining external services behavior. Isolation is a must to prevent noise and slow performance but mostly to simulate various scenarios and responses - A good flight simulator is not about painting clear blue sky rather bringing safe storms and chaos. This is reinforced in a Microservice architecture where the focus should always be on a single component without involving the rest of the world. Though it's possible to simulate external service behavior using test doubles (mocking), it's preferable not to touch the deployed code and act on the network level to keep the tests pure black-box. The downside of isolation is not detecting when the collaborator component changes and not realizing misunderstandings between the two services - Make sure to compensate for this using a few contract or E2E tests. + + +

+ +### Code Example – a simple mock using nock + +```javascript +// Intercept requests for internal or 3rd party APIs and return a predefined response +beforeEach(() => { + nock("http://localhost/user/").get(`/1`).reply(200, { + id: 1, + name: "John", + }); +}); +``` + +### Code Example – simulating an important scenario inside the test + +```javascript +// Using an uncommon user id (7) and create a compatible interceptor +test("When the user does not exist, return http 404", async () => { + //Arrange + const orderToAdd = { + userId: 7, + productId: 2, + mode: "draft", + }; + + nock("http://localhost/user/").get(`/7`).reply(404, { + message: "User does not exist", + code: "nonExisting", + }); + + //Act + const orderAddResult = await axiosAPIClient.post("/order", orderToAdd); + + //Assert + expect(orderAddResult.status).toBe(404); +}); +``` + +### Code Example – preventing requests from going outside to the real-world + +```javascript +beforeAll(async () => { + // ... + // ️️️Ensure that this component is isolated by preventing unknown calls + nock.disableNetConnect(); + // Enable only requests for the API under test + nock.enableNetConnect("127.0.0.1"); +}); +``` + +### Code Example – ensuring that the outgoing request schema is correct + +```javascript +// ️️️Assert that the app called the mailer service appropriately with the right input +test("When order failed, send mail to admin", async () => { + //Arrange + // ... + let emailPayload; + nock("http://mailer.com") + .post("/send", (payload) => ((emailPayload = payload), true)) + .reply(202); + const orderToAdd = { + userId: 1, + productId: 2, + mode: "approved", + }; + + //Act + await axiosAPIClient.post("/order", orderToAdd); + + // ️️️Assert + expect(emailPayload).toMatchObject({ + subject: expect.any(String), + body: expect.any(String), + recipientAddress: expect.stringMatching(/^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/), + }); +}); +``` diff --git a/sections/testingandquality/randomize-port.md b/sections/testingandquality/randomize-port.md new file mode 100644 index 000000000..28af118df --- /dev/null +++ b/sections/testingandquality/randomize-port.md @@ -0,0 +1,31 @@ +# Specify a port in production, randomize in testing + +

+ +### One Paragraph Explainer + +When writing component/integration tests, the web server should be started by the tests in the same process - this opens the door for many desirable testing features like mocking, coverage, and more. In a multi-process test runner, multiple web server instances will be opened. If these instances try to open the same port, they will collide. In testing only, let the server randomize a port to prevent collisions. This can easily achieved by providing an [ephemeral port](https://en.wikipedia.org/wiki/Ephemeral_port), the number zero, so the operating system will allocate an available port + +

+ +### Code Example – starting the web server with testing in-mind + +```javascript +// api-under-test.js +const initializeWebServer = async () => { + return new Promise((resolve, reject) => { + // Fixed port in production, a zero port (ephemeral) for testing + const webServerPort = process.env.PORT ? process.env.PORT : 0; + expressApp = express(); + connection = expressApp.listen(webServerPort, () => { + // No port + resolve(expressApp); + }); + }); +}; + +// test.js +beforeAll(async () => { + expressApp = await initializeWebServer(); // No port +}); +``` diff --git a/sections/testingandquality/refactoring.basque.md b/sections/testingandquality/refactoring.basque.md index 0b58748b6..3ec63c028 100644 --- a/sections/testingandquality/refactoring.basque.md +++ b/sections/testingandquality/refactoring.basque.md @@ -29,15 +29,15 @@ Tresna horiek zure IE eraikuntzari gehitzeak kalitatea egiaztatzeko prozesua aut ### 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") +![alt text](../../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") +![alt text](../../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") +![alt text](../../assets/images/codeanalysis-sonarqube-dashboard.PNG "Kode analisiaren historia")

diff --git a/sections/testingandquality/refactoring.brazilian-portuguese.md b/sections/testingandquality/refactoring.brazilian-portuguese.md index 490266eda..52e2836f5 100644 --- a/sections/testingandquality/refactoring.brazilian-portuguese.md +++ b/sections/testingandquality/refactoring.brazilian-portuguese.md @@ -27,15 +27,15 @@ A refatoração é um processo importante no fluxo de desenvolvimento iterativo. ### Exemplo: Análise de métodos complexos com CodeClimate (comercial) -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/codeanalysis-climate-complex-methods.PNG "Análise de métodos complexos") +![alt text](../../assets/images/codeanalysis-climate-complex-methods.PNG "Análise de métodos complexos") ### Exemplo: tendências de análise de código e histórico com CodeClimate (comercial) -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/codeanalysis-climate-history.PNG "Histórico de análise de código") +![alt text](../../assets/images/codeanalysis-climate-history.PNG "Histórico de análise de código") ### Exemplo: Resumo de análise de código e tendências com o SonarQube (comercial) -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/codeanalysis-sonarqube-dashboard.PNG "Histórico de análise de código") +![alt text](../../assets/images/codeanalysis-sonarqube-dashboard.PNG "Histórico de análise de código")

diff --git a/sections/testingandquality/refactoring.french.md b/sections/testingandquality/refactoring.french.md index 985d39741..6bd7f37db 100644 --- a/sections/testingandquality/refactoring.french.md +++ b/sections/testingandquality/refactoring.french.md @@ -29,15 +29,15 @@ seront toujours un problème si la qualité implicite de votre JavaScript est ma ### Exemple : analyse de méthodes complexes avec CodeClimate (commercial) -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/codeanalysis-climate-complex-methods.PNG "Analyse de méthodes complexes") +![alt text](../../assets/images/codeanalysis-climate-complex-methods.PNG "Analyse de méthodes complexes") ### Exemple : tendances et historique de l'analyse de code avec CodeClimate (commercial) -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/codeanalysis-climate-history.PNG "Historique d'analyse de code") +![alt text](../../assets/images/codeanalysis-climate-history.PNG "Historique d'analyse de code") ### Exemple : résumé et tendances de l'analyse de code avec SonarQube (commercial) -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/codeanalysis-sonarqube-dashboard.PNG "Historique d'analyse de code") +![alt text](../../assets/images/codeanalysis-sonarqube-dashboard.PNG "Historique d'analyse de code")

diff --git a/sections/testingandquality/refactoring.japanese.md b/sections/testingandquality/refactoring.japanese.md index 3bb026fdb..0ee0d0702 100644 --- a/sections/testingandquality/refactoring.japanese.md +++ b/sections/testingandquality/refactoring.japanese.md @@ -27,15 +27,15 @@ ### 例: CodeClimate を使用した複雑なメソッドの解析(商用) -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/codeanalysis-climate-complex-methods.PNG "複雑なメソッドの解析") +![alt text](../../assets/images/codeanalysis-climate-complex-methods.PNG "複雑なメソッドの解析") ### 例: CodeClimate を使用したコード解析結果の傾向と履歴(商用) -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/codeanalysis-climate-history.PNG "コード解析の履歴") +![alt text](../../assets/images/codeanalysis-climate-history.PNG "コード解析の履歴") ### 例: コード解析結果のサマリーと傾向(商用) -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/codeanalysis-sonarqube-dashboard.PNG "コード解析結果のサマリーと傾向") +![alt text](../../assets/images/codeanalysis-sonarqube-dashboard.PNG "コード解析結果のサマリーと傾向")

diff --git a/sections/testingandquality/refactoring.korean.md b/sections/testingandquality/refactoring.korean.md new file mode 100644 index 000000000..379dccb0a --- /dev/null +++ b/sections/testingandquality/refactoring.korean.md @@ -0,0 +1,41 @@ +# Refactoring + +

+ +### One Paragraph Explainer + +리팩토링은 반복적인 개발 흐름에서 중요한 과정이다. 중복 코드, 긴 메서드, 긴 매개 변수 목록과 같은 "코드 스멜"(불량 코딩 관행)을 제거하면 코드가 향상되고 유지 관리가 더욱 용이해집니다. 정적 분석 도구를 사용하면 이러한 코드 스멜을 찾고 리팩토링에 대한 프로세스를 구축하는 데 도움이 됩니다. CI 빌드에 이러한 도구를 추가하면 품질 검사 프로세스를 자동화하는 데 도움이 됩니다. CI가 소나 또는 코드 기후와 같은 도구와 통합될 경우 코드 스멜을 감지하고 작성자에게 문제 해결 방법을 알려주면 빌드가 실패합니다. 이러한 정적 분석 도구는 ESLint와 같은 보풀 도구를 보완합니다. 대부분의 보풀 도구는 단일 파일에서 들여쓰기와 누락된 세미콜론과 같은 코드 스타일(일부는 긴 함수처럼 코드 냄새가 나기도 함)에 초점을 맞추고 정적 분석 도구는 단일 파일과 여러 파일에 있는 코드 냄새(중복 코드, 복잡성 분석 등)를 찾는 데 초점을 맞춥니다. + +

+ +### Martin Fowler - Chief Scientist at ThoughtWorks + +책, "JavaScript 수정: 불량 코드를 정상 코드로 변경" + +> 리팩토링은 기존 코드베이스의 설계를 개선하기 위한 통제된 기술이다. + +

+ +### Evan Burchard - Web Development Consultant and Author + +책, "JavaScript 수정: 불량 코드를 정상 코드로 변경" + +> 사용하는 프레임워크나 +> "컴파일-투-JS" 언어 또는 라이브러리가 무엇이든 +> 자바스크립트의 기본 품질이 낮으면 버그와 성능에 대한 우려는 항상 문제가 됩니다. + +

+ +### Example: Complex methods analysis with CodeClimate (commercial) + +![alt text](../../assets/images/codeanalysis-climate-complex-methods.PNG "Complex methods analysis") + +### Example: Code analysis trends and history with CodeClimate (commercial) + +![alt text](../../assets/images/codeanalysis-climate-history.PNG "Code analysis history") + +### Example: Code analysis summary and trends with SonarQube (commercial) + +![alt text](../../assets/images/codeanalysis-sonarqube-dashboard.PNG "Code analysis history") + +

diff --git a/sections/testingandquality/refactoring.md b/sections/testingandquality/refactoring.md index 99a506edc..804f9147b 100644 --- a/sections/testingandquality/refactoring.md +++ b/sections/testingandquality/refactoring.md @@ -29,15 +29,15 @@ will always be an issue if the underlying quality of your JavaScript is poor. ### Example: Complex methods analysis with CodeClimate (commercial) -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/codeanalysis-climate-complex-methods.PNG "Complex methods analysis") +![alt text](../../assets/images/codeanalysis-climate-complex-methods.PNG "Complex methods analysis") ### Example: Code analysis trends and history with CodeClimate (commercial) -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/codeanalysis-climate-history.PNG "Code analysis history") +![alt text](../../assets/images/codeanalysis-climate-history.PNG "Code analysis history") ### Example: Code analysis summary and trends with SonarQube (commercial) -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/codeanalysis-sonarqube-dashboard.PNG "Code analysis history") +![alt text](../../assets/images/codeanalysis-sonarqube-dashboard.PNG "Code analysis history")

diff --git a/sections/testingandquality/refactoring.polish.md b/sections/testingandquality/refactoring.polish.md index 6e2fce6f6..9af9e89dd 100644 --- a/sections/testingandquality/refactoring.polish.md +++ b/sections/testingandquality/refactoring.polish.md @@ -29,15 +29,15 @@ will always be an issue if the underlying quality of your JavaScript is poor. ### Przykład: Analiza złożonych metod za pomocą CodeClimate (komercyjna) -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/codeanalysis-climate-complex-methods.PNG "Complex methods analysis") +![alt text](../../assets/images/codeanalysis-climate-complex-methods.PNG "Complex methods analysis") ### Przykład: trendy i historia analizy kodu za pomocą CodeClimate (komercyjna) -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/codeanalysis-climate-history.PNG "Code analysis history") +![alt text](../../assets/images/codeanalysis-climate-history.PNG "Code analysis history") ### Przykład: Podsumowanie analizy kodu i trendy w SonarQube (komercyjna) -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/codeanalysis-sonarqube-dashboard.PNG "Code analysis history") +![alt text](../../assets/images/codeanalysis-sonarqube-dashboard.PNG "Code analysis history")

diff --git a/sections/testingandquality/refactoring.russian.md b/sections/testingandquality/refactoring.russian.md index 5693544c9..8a05fc8db 100644 --- a/sections/testingandquality/refactoring.russian.md +++ b/sections/testingandquality/refactoring.russian.md @@ -29,15 +29,15 @@ ### Пример: Анализ сложных методов с помощью CodeClimate (коммерческий) -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/codeanalysis-climate-complex-methods.PNG "Complex methods analysis") +![alt text](../../assets/images/codeanalysis-climate-complex-methods.PNG "Complex methods analysis") ### Пример: Тенденции и история анализа кода с CodeClimate (коммерческий) -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/codeanalysis-climate-history.PNG "Code analysis history") +![alt text](../../assets/images/codeanalysis-climate-history.PNG "Code analysis history") ### Пример: Сводка анализа кода и тенденции с SonarQube (коммерческий) -![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/codeanalysis-sonarqube-dashboard.PNG "Code analysis history") +![alt text](../../assets/images/codeanalysis-sonarqube-dashboard.PNG "Code analysis history")

diff --git a/sections/testingandquality/test-five-outcomes.md b/sections/testingandquality/test-five-outcomes.md new file mode 100644 index 000000000..450a11b72 --- /dev/null +++ b/sections/testingandquality/test-five-outcomes.md @@ -0,0 +1,23 @@ +# Test the five potential outcomes + +

+ +### One Paragraph Explainer + +When planning your tests, consider covering the five typical flow's outputs. When your test is triggering some action (e.g., API call), a reaction is happening, something meaningful occurs and calls for testing. Note that we don't care about how things work. Our focus is on outcomes, things that are noticeable from the outside and might affect the user. These outcomes/reactions can be put in 5 categories: + +• Response - the test invokes an action (e.g., via API) and gets a response. It's now concerned with checking the response data correctness, schema, and HTTP status. + +• A new state - after invoking an action, some data is probably modified. For example, when updating a user, it may be that the new data was not saved. Commonly and mistakenly, testers check only the response and not whether the data is updated correctly. Testing data and databases raises multiple interesting challenges that are greatly covered below in the 📗 section 'Dealing with data'. + +• External calls - after invoking an action, the app might call an external component via HTTP or any other transport. For example, a call to send SMS, email or charge a credit card. Anything that goes outside and might affect the user - should be tested. Testing integrations is a broad topic which is discussed in the 📗 section 'Testing integrations' below. + +• Message queues - the outcome of a flow might be a message in a queue. In our example application, once a new order was saved, the app puts a message in some MQ product. Now other components can consume this message and continue the flow. This is very similar to testing integrations, only working with message queues is different technically and tricky. The 📗 section 'Message Queues' below delve into this topic. + +• Observability - some things must be monitored, like errors or remarkable business events. When a transaction fails, not only do we expect the right response but also the correct error handling and proper logging/metrics. This information goes directly to a very important user - the ops user (i.e., production SRE/admin). Testing error handlers isn't very straightforward because many types of errors might get thrown, where some errors should lead to process crashing, and there are many other details to cover. We plan to write the 📗 section on 'Observability and errors' soon. + +

+ +### Example: The backend testing checklist + +![The backend testing checklist](../../assets/images/backend-testing-checklist.png "The backend testing checklist") diff --git a/sections/testingandquality/test-middlewares.korean.md b/sections/testingandquality/test-middlewares.korean.md new file mode 100644 index 000000000..b052b54fe --- /dev/null +++ b/sections/testingandquality/test-middlewares.korean.md @@ -0,0 +1,30 @@ +# Test your middlewares in isolation + +

+ +### One Paragraph Explainer + +미들웨어 테스트는 시스템의 작은 부분을 차지하며 라이브 Express 서버가 필요하기 때문에 대부분 미들웨어 테스트를 회피합니다. 두 가지 이유 모두 틀렸습니다. 미들웨어는 작지만 요청의 전부 또는 대부분에 영향을 미치며 '{req,res}' JS 개체를 가져오는 순수 함수로 쉽게 테스트할 수 있습니다. 미들웨어 함수를 테스트하려면 해당 함수를 호출하고 {req,res}개 개체와의 상호 작용에 대해 [예를 들어 Sinon 사용](https://www.npmjs.com/package/sinon)))을 스파이하여 함수가 올바른 동작을 수행했는지 확인해야 합니다. 라이브러리 [node-controls-products](https://www.npmjs.com/package/node-mocks-http)는 더 나아가서 {req,res}개의 객체의 동작에 대한 스파이 활동과 함께 인자를 분석합니다. 예를 들어 res 개체에 설정된 http 상태가 예상과 일치하는지 여부를 주장할 수 있습니다(아래 예 참조). + +

+ +### Code example: Testing middleware in isolation + +```javascript +//the middleware we want to test +const unitUnderTest = require("./middleware"); +const httpMocks = require("node-mocks-http"); +//Jest syntax, equivalent to describe() & it() in Mocha +test("A request without authentication header, should return http status 403", () => { + const request = httpMocks.createRequest({ + method: "GET", + url: "/user/42", + headers: { + authentication: "", + }, + }); + const response = httpMocks.createResponse(); + unitUnderTest(request, response); + expect(response.statusCode).toBe(403); +}); +``` diff --git a/sections/testingandquality/test-middlewares.md b/sections/testingandquality/test-middlewares.md index 613f4e85f..195acbecb 100644 --- a/sections/testingandquality/test-middlewares.md +++ b/sections/testingandquality/test-middlewares.md @@ -4,7 +4,7 @@ ### One Paragraph Explainer -Many avoid Middleware testing because they represent a small portion of the system and require a live Express server. Both reasons are wrong — Middlewares are small but affect all or most of the requests and can be tested easily as pure functions that get `{req,res}` JS objects. To test a middleware function one should just invoke it and spy ([using Sinon for example](https://www.npmjs.com/package/sinon)) on the interaction with the {req,res} objects to ensure the function performed the right action. The library [node-mock-http](https://www.npmjs.com/package/node-mocks-http) takes it even further and factors the {req,res} objects along with spying on their behavior. For example, it can assert whether the http status that was set on the res object matches the expectation (See example below) +Many avoid Middleware testing because they represent a small portion of the system and require a live Express server. Both reasons are wrong — Middlewares are small but affect all or most of the requests and can be tested easily as pure functions that get `{req,res}` JS objects. To test a middleware function one should just invoke it and spy ([using Sinon for example](https://www.npmjs.com/package/sinon)) on the interaction with the {req,res} objects to ensure the function performed the right action. The library [node-mock-http](https://www.npmjs.com/package/node-mocks-http) takes it even further and factors the {req,res} objects along with spying on their behavior. For example, it can assert whether the http status that was set on the res object matches the expectation (See example below)

@@ -27,4 +27,4 @@ test("A request without authentication header, should return http status 403", ( unitUnderTest(request, response); expect(response.statusCode).toBe(403); }); -``` +``` \ No newline at end of file