mirror of
				https://github.com/goldbergyoni/nodebestpractices.git
				synced 2025-11-01 01:56:06 +08:00 
			
		
		
		
	Merge pull request #443 from oshliaer/russian-translation-03step
Russian translation #3
This commit is contained in:
		| @ -60,31 +60,31 @@ | ||||
|  | ||||
| ## ![✔] 1.1 Структурируйте свое решение по компонентам | ||||
|  | ||||
| **TL;DR:** Наихудшая ловушка для больших приложений -- поддержка огромной базы кода с сотнями зависимостей -- такой монолит замедляет разработчиков, поскольку они пытаются внедрить новые функции. Вместо этого разделите ваш код на компоненты, каждый получает свою собственную папку или выделенную кодовую базу, и убедитесь, что каждый модуль остается маленьким и простым. Посетите «Подробнее» ниже, чтобы увидеть примеры правильной структуры проекта. | ||||
| **TL;DR:** Наихудшая ловушка для больших приложений -- поддержка огромной базы кода с сотнями зависимостей -- такой монолит замедляет разработчиков, поскольку они пытаются внедрить новые функции. Вместо этого разделите ваш код на компоненты, каждый получает свою собственную папку или выделенную кодовую базу, и убедитесь, что каждый модуль остается маленьким и простым. Посетите "Подробнее" ниже, чтобы увидеть примеры правильной структуры проекта. | ||||
|  | ||||
| **Иначе:** Когда разработчики, которые пишут новые функции, изо всех сил пытаются понять влияние своих изменений и боятся сломать другие зависимые компоненты, развертывания становятся медленнее и рискованнее. Также считается сложнее масштабировать, когда все бизнес-единицы не разделены. | ||||
|  | ||||
| 🔗 [**Подробнее: структура по компонентам**](/sections/projectstructre/breakintcomponents.md) | ||||
| 🔗 [**Подробнее: Структурируйте свое решение по компонентам**](/sections/projectstructre/breakintcomponents.russian.md) | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ## ![✔] 1.2 Выделяйте ваши компоненты в отдельный слой, держите Express в его границах | ||||
|  | ||||
| **TL;DR:** Каждый компонент должен содержать «слои» -- выделенный объект для сети, логики и кода доступа к данным. Это не только четко разделяет задачи, но и значительно облегчает проверку и тестирование системы. Хотя это очень распространенный шаблон, разработчики API, как правило, смешивают слои, передавая объекты веб-слоя (Express req, res) в бизнес-логику и уровни данных - это делает ваше приложение зависимым и доступным только для Express. | ||||
| **TL;DR:** Каждый компонент должен содержать "слои" -- выделенный объект для сети, логики и кода доступа к данным. Это не только четко разделяет задачи, но и значительно облегчает проверку и тестирование системы. Хотя это очень распространенный шаблон, разработчики API, как правило, смешивают слои, передавая объекты веб-слоя (Express req, res) в бизнес-логику и уровни данных - это делает ваше приложение зависимым и доступным только для Express. | ||||
|  | ||||
| **Иначе:** Приложение, которое смешивает веб-объекты с другими слоями, не может быть доступно для тестирования кода, заданий CRON и других вызовов в обход Express. | ||||
|  | ||||
| 🔗 [**Подробнее: создание слоев вашего приложения**](/sections/projectstructre/createlayers.md) | ||||
| 🔗 [**Подробнее: Выделяйте ваши компоненты в отдельный слой, держите Express в его границах**](/sections/projectstructre/createlayers.russian.md) | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ## ![✔] 1.3 Завернуть общие утилиты в пакеты npm | ||||
| ## ![✔] 1.3 Оборачивайте общие утилиты в пакеты npm | ||||
|  | ||||
| **TL;DR:** В большом приложении, которое составляет большую кодовую базу, универсальные утилиты, такие как регистратор, модуль шифрования и т.п., должны быть обернуты вашим собственным кодом и представлены как частные пакеты npm. Это позволяет делиться ими между несколькими кодовыми базами и проектами. | ||||
|  | ||||
| **Иначе:** Вам придется изобрести собственный велосипед для развертывания и поддержания зависимостей. | ||||
|  | ||||
| 🔗 [**Подробнее: Структура по функциям**](/section/projectstructre/wraputilities.md) | ||||
| 🔗 [**Подробнее: Оборачивайте общие утилиты в пакеты npm**](/sections/projectstructre/wraputilities.russian.md) | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| @ -94,7 +94,7 @@ | ||||
|  | ||||
| **Иначе:** Ваш API будет доступен для тестирования только через HTTP-вызовы (медленнее и намного сложнее создавать отчеты о покрытии). Скорее всего, не составит большого труда хранить сотни строк кода в одном файле. | ||||
|  | ||||
| 🔗 [**Подробнее: Разделяйте Express "приложение" и "сервер"**](/section/projectstructre/separateexpress.md) | ||||
| 🔗 [**Подробнее: Разделяйте Express "приложение" и "сервер"**](/sections/projectstructre/separateexpress.russian.md) | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| @ -104,7 +104,7 @@ | ||||
|  | ||||
| **Иначе:** Невыполнение каких-либо требований к конфигурации приведет к срывам в работе разработчиков или devops командой. Вероятно, и тех и других. | ||||
|  | ||||
| 🔗 [**Подробнее: лучшие рекомендации по настройке**](/section/projectstructre/configguide.md) | ||||
| 🔗 [**Подробнее: Используйте конфигурацию с учетом среды, безопасную и иерархическую конфигурацию**](/sections/projectstructre/configguide.russian.md) | ||||
|  | ||||
| <br/><br/><br/> | ||||
|  | ||||
| @ -118,7 +118,7 @@ | ||||
|  | ||||
| **Иначе:** Стиль обратного вызова Node.js, функция (err, response), является многообещающим способом создания непригодного для использования кода из-за сочетания обработки ошибок со случайным кодом, чрезмерных вложений и слабых шаблонов кодирования. | ||||
|  | ||||
| 🔗 [**Подробнее: Используйте Async-Await или обещания для асинхронной обработки ошибок**](/section/errorhandling/asyncerrorhandling.russian.md) | ||||
| 🔗 [**Подробнее: Используйте Async-Await или обещания для асинхронной обработки ошибок**](/sections/errorhandling/asyncerrorhandling.russian.md) | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| @ -128,7 +128,7 @@ | ||||
|  | ||||
| **Иначе:** При вызове какого-либо компонента нельзя быть уверенным, какой тип ошибок приходит в ответ -- это значительно затрудняет правильную обработку ошибок. Хуже того, использование пользовательских типов для описания ошибок может привести к потере информации о критических ошибках, таких как трассировка стека! | ||||
|  | ||||
| 🔗 [**Подробнее: Используйте только встроенный объект Error**](/section/errorhandling/useonlythebuiltinerror.russian.md) | ||||
| 🔗 [**Подробнее: Используйте только встроенный объект Error**](/sections/errorhandling/useonlythebuiltinerror.russian.md) | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| @ -188,7 +188,7 @@ | ||||
|  | ||||
| **Иначе:** Без тестирования, будь то автоматически или вручную, вы не сможете полагаться на свой код для возврата правильных ошибок. Без значения ошибок -- нет обработки ошибок. | ||||
|  | ||||
| 🔗 [**Подробнее: Тестируйте потоки ошибок с использованием вашей любимой тестовой среды**](/section/errorhandling/testingerrorflows.russian.md) | ||||
| 🔗 [**Подробнее: Тестируйте потоки ошибок с использованием вашей любимой тестовой среды**](/sections/errorhandling/testingerrorflows.russian.md) | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| @ -198,7 +198,7 @@ | ||||
|  | ||||
| **Иначе:** Вы можете потратить огромные усилия на измерение производительности и времени простоя API, возможно, вы никогда самостоятельно не узнаете, какие части кода в реально сценарии самые медленные, и как они влияют на UX. | ||||
|  | ||||
| 🔗 [**Подробнее: Обнаружение ошибок и простоев с использованием продуктов APM**](/section/errorhandling/apmproducts.russian.md) | ||||
| 🔗 [**Подробнее: Обнаружение ошибок и простоев с использованием продуктов APM**](/sections/errorhandling/apmproducts.russian.md) | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| @ -232,7 +232,7 @@ | ||||
|  | ||||
| **Иначе:** Разработчики сосредоточатся на утомительных проблемах с интервалами и шириной линии, и время может быть потрачено впустую на продумывание стиля кода проекта. | ||||
|  | ||||
| 🔗 [**Подробнее: Использование ESLint и Prettier**](/section/codestylepractices/eslint_prettier.russian.md) | ||||
| 🔗 [**Подробнее: Использование ESLint и Prettier**](/sections/codestylepractices/eslint_prettier.russian.md) | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| @ -448,7 +448,7 @@ null == undefined   // true | ||||
|  | ||||
| **Иначе:** Развертывание только что прошло, тест под названием "Добавить продукт" не прошел. Это говорит вам, что именно работает со сбоями? | ||||
|  | ||||
| 🔗 [**Подробнее: Include 3 parts in each test name**](/sections/testingandquality/3-parts-in-name.md) | ||||
| 🔗 [**Подробнее:  Включите 3 части в каждое название теста**](/sections/testingandquality/3-parts-in-name.russian.md) | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| @ -459,7 +459,7 @@ null == undefined   // true | ||||
|  | ||||
| **Иначе:** Не только вы тратите долгие ежедневные часы на понимание основного кода, теперь и то, что должно было быть простой частью дня (тестирование), напрягает ваш мозг. | ||||
|  | ||||
| 🔗 [**Read More: Structure tests by the AAA pattern**](/sections/testingandquality/aaa.md) | ||||
| 🔗 [**Read More: Structure tests by the AAA pattern**](/sections/testingandquality/aaa.russian.md) | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| @ -477,7 +477,7 @@ null == undefined   // true | ||||
|  | ||||
| **Иначе:** Рассмотрим сценарий, в котором развертывание прерывается из-за неудачных тестов, теперь команда собирается потратить драгоценное время на исследование, которое заканчивается печальным выводом: система работает хорошо, однако тесты мешают друг другу и нарушают сборку. | ||||
|  | ||||
| 🔗 [**Подробнее: Avoid global test fixtures**](/sections/testingandquality/avoid-global-test-fixture.md) | ||||
| 🔗 [**Подробнее: Избегайте глобальных тестовых приспособлений и параметров, добавляйте данные для каждого теста**](/sections/testingandquality/avoid-global-test-fixture.russian.md) | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| @ -529,7 +529,7 @@ null == undefined   // true | ||||
|  | ||||
| **Иначе:** При плохом качестве кода ошибки и производительность всегда будут проблемой, которую не может исправить ни одна блестящая новая библиотека или современные функции. | ||||
|  | ||||
| 🔗 [**Подробнее: Refactoring!**](/sections/testingandquality/refactoring.md) | ||||
| 🔗 [**Подробнее: Рефакторинг**](/sections/testingandquality/refactoring.russian.md) | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| @ -539,7 +539,7 @@ null == undefined   // true | ||||
|  | ||||
| **Иначе:** Выбор какого-либо нишевого поставщика может заблокировать вас, когда вам понадобится дополнительная настройка. С другой стороны, работа с Jenkins может потратить драгоценное время на настройку инфраструктуры. | ||||
|  | ||||
| 🔗 [**Подробнее: Choosing CI platform**](/sections/testingandquality/citools.md) | ||||
| 🔗 [**Подробнее: Тщательно выбирайте платформу CI**](/sections/testingandquality/citools.russian.md) | ||||
|  | ||||
| <br/><br/><br/> | ||||
|  | ||||
| @ -554,7 +554,7 @@ null == undefined   // true | ||||
|  | ||||
| **Иначе:** Отказ === разочарованные клиенты. Просто. | ||||
|  | ||||
| 🔗 [**Подробнее: Мониторинг**](/sections/production/monitoring.russian.md) | ||||
| 🔗 [**Подробнее: Мониторинг!**](/sections/production/monitoring.russian.md) | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| @ -564,7 +564,7 @@ null == undefined   // true | ||||
|  | ||||
| **Иначе:** Вы в конечном итоге получаете черный ящик, о котором трудно подумать, затем вы начинаете переписывать все операторы регистрации, чтобы добавить дополнительную информацию. | ||||
|  | ||||
| 🔗 [**Подробнее: Increase transparency using smart logging**](/sections/production/smartlogging.md) | ||||
| 🔗 [**Подробнее: Сделайте ваше приложение прозрачным, используя умные логи**](/sections/production/smartlogging.russian.md) | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| @ -578,13 +578,13 @@ null == undefined   // true | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ## ![✔] 5.4. Блокировка зависимостей | ||||
| ## ![✔] 5.4. Блокируйте зависимости | ||||
|  | ||||
| **TL;DR:** Ваш код должен быть одинаковым во всех средах, но удивительно, что npm по умолчанию позволяет смещать зависимости между средами -- при установке пакетов в различных средах он пытается получить последнюю версию пакета исправлений. Преодолеть это можно с помощью файлов конфигурации npm, .npmrc, которые сообщают каждой среде сохранять точную (не последнюю) версию каждого пакета. В качестве альтернативы, для более тонкого контроля используйте `npm shrinkwrap`. \* Обновление: начиная с NPM5, зависимости по умолчанию заблокированы. Новый менеджер пакетов Yarn также предоставил нам покрытие по умолчанию. | ||||
|  | ||||
| **Иначе:** QA тщательно протестирует код и утвердит версию, которая будет вести себя по-другому в производстве. Хуже того, на разных серверах в одном и том же производственном кластере может выполняться другой код. | ||||
|  | ||||
| 🔗 [**Подробнее: Lock dependencies**](/sections/production/lockdependencies.md) | ||||
| 🔗 [**Подробнее: Блокируйте зависимости**](/sections/production/lockdependencies.russian.md) | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| @ -594,7 +594,7 @@ null == undefined   // true | ||||
|  | ||||
| **Иначе:** Запуск десятков экземпляров без четкой стратегии и слишком большого количества инструментов (управление кластером, docker, PM2) может привести к хаосу DevOps. | ||||
|  | ||||
| 🔗 [**Подробнее: Guard process uptime using the right tool**](/sections/production/guardprocess.md) | ||||
| 🔗 [**Подробнее: Защищайте и перезапускайте свой процесс в случае неудачи (используя правильный инструмент)**](/sections/production/guardprocess.russian.md) | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| @ -604,7 +604,7 @@ null == undefined   // true | ||||
|  | ||||
| **Иначе:** Ваше приложение, скорее всего, будет использовать только 25% доступных ресурсов (!) Или даже меньше. Обратите внимание, что типичный сервер имеет 4 или более ядер ЦП, для простого развертывания Node.js используется только 1 (даже при использовании сервисов PaaS, таких как AWS beanstalk!) | ||||
|  | ||||
| 🔗 [**Подробнее: Utilize all CPU cores**](/sections/production/utilizecpu.md) | ||||
| 🔗 [**Подробнее: Используйте все ядра процессора**](/sections/production/utilizecpu.russian.md) | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| @ -634,7 +634,7 @@ null == undefined   // true | ||||
|  | ||||
| **Иначе:** Чемпион мира по IT/DevOps не спасет плохо написанную систему. | ||||
|  | ||||
| 🔗 [**Подробнее: Make your code production-ready**](/sections/production/productioncode.md) | ||||
| 🔗 [**Подробнее: Делайте ваш код готовым к работе**](/sections/production/productioncode.russian.md) | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| @ -644,7 +644,7 @@ null == undefined   // true | ||||
|  | ||||
| **Иначе:** Ваша память процесса может пропускать сотни мегабайт в день, как это было в [Walmart](https://www.joyent.com/blog/walmart-node-js-memory-leak). | ||||
|  | ||||
| 🔗 [**Подробнее: Measure and guard the memory usage**](/sections/production/measurememory.md) | ||||
| 🔗 [**Подробнее: Измеряйте и защищайте использование памяти**](/sections/production/measurememory.russian.md) | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| @ -654,7 +654,7 @@ null == undefined   // true | ||||
|  | ||||
| **Иначе:** Ваш единственный поток Node будет занят потоковой передачей сотен файлов html/images/angular/react вместо того, чтобы выделять все свои ресурсы на задачи, для которой он был создан -- обслуживание динамического контента. | ||||
|  | ||||
| 🔗 [**Подробнее: Get your frontend assets out of Node**](/sections/production/frontendout.md) | ||||
| 🔗 [**Подробнее: Получайте ваши внешние ресурсы вне Node**](/sections/production/frontendout.russian.md) | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| @ -674,7 +674,7 @@ null == undefined   // true | ||||
|  | ||||
| **Иначе:** Для обеспечения чистоты кода от уязвимостей без использования специальных инструментов вам потребуется постоянно следить за публикациями в Интернете о новых угрозах. Довольно утомительно. | ||||
|  | ||||
| 🔗 [**Подробнее: Use tools that automatically detect vulnerabilities**](/sections/production/detectvulnerabilities.md) | ||||
| 🔗 [**Подробнее: Используйте инструменты, которые автоматически обнаруживают уязвимые зависимости**](/sections/production/detectvulnerabilities.russian.md) | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| @ -693,7 +693,7 @@ null == undefined   // true | ||||
|  | ||||
| **Иначе:** Пропуск этого простого свойства может значительно снизить производительность. Например, при использовании Express для рендеринга на стороне сервера пропуск `NODE_ENV` замедляет его в три раза! | ||||
|  | ||||
| 🔗 [**Подробнее: Set NODE_ENV=production**](/sections/production/setnodeenv.md) | ||||
| 🔗 [**Подробнее: Устанавливайте NODE_ENV=production**](/sections/production/setnodeenv.russian.md) | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| @ -711,7 +711,7 @@ null == undefined   // true | ||||
|  | ||||
| **Иначе:** Недавно обнаруженные ошибки или уязвимости могут быть использованы для эксплуатации приложения, работающего в производственной среде, и ваше приложение может стать неподдерживаемым различными модулями и усложнить поддержку. | ||||
|  | ||||
| 🔗 [**Подробнее: Use an LTS release of Node.js**](/sections/production/LTSrelease.md) | ||||
| 🔗 [**Подробнее: Используйте LTS-релиз Node.js в производстве**](/sections/production/LTSrelease.russian.md) | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| @ -721,7 +721,7 @@ null == undefined   // true | ||||
|  | ||||
| **Иначе:** Маршрутизация журналов обработки приложения === трудности масштабирования, потеря журналов, плохое разделение задач | ||||
|  | ||||
| 🔗 [**Подробнее: Log Routing**](/sections/production/logrouting.md) | ||||
| 🔗 [**Подробнее: Код вашего приложения не должен обрабатывать журналы маршрутизации**](/sections/production/logrouting.russian.md) | ||||
|  | ||||
| <br/><br/><br/> | ||||
|  | ||||
| @ -872,7 +872,7 @@ null == undefined   // true | ||||
|  | ||||
| **Иначе:** Злоумышленник может выполнить неограниченное количество автоматических попыток ввода пароля для получения доступа к привилегированным учетным записям в приложении. | ||||
|  | ||||
| 🔗 [**Подробнее: Ограничение входа**](/section/security/login-rate-limit.md) | ||||
| 🔗 [**Подробнее: Ограничение входа**](/sections/security/login-rate-limit.md) | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
|  | ||||
							
								
								
									
										20
									
								
								sections/production/LTSrelease.russian.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								sections/production/LTSrelease.russian.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | ||||
| # Используйте LTS-релиз Node.js в производстве | ||||
|  | ||||
| ### Объяснение в один абзац | ||||
|  | ||||
| Убедитесь, что вы используете LTS (Long Term Support) версию Node.js в работе, чтобы получать критические исправления ошибок, обновления безопасности и улучшения производительности. | ||||
|  | ||||
| LTS-версии Node.js поддерживаются в течение не менее 18 месяцев и обозначаются четными номерами версий (например, 4, 6, 8). Они лучше всего подходят для производства, поскольку линия выпуска LTS ориентирована на стабильность и безопасность, тогда как линия выпуска "текущий" имеет более короткий срок службы и более частые обновления кода. Изменения в версиях LTS ограничены исправлениями ошибок для стабильности, обновлениями безопасности, возможными обновлениями npm, обновлениями документации и некоторыми улучшениями производительности, которые можно продемонстрировать, чтобы не сломать существующие приложения. | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Читать еще | ||||
|  | ||||
| 🔗 [Node.js release definitions](https://nodejs.org/en/about/releases/) | ||||
|  | ||||
| 🔗 [Node.js release schedule](https://github.com/nodejs/Release) | ||||
|  | ||||
| 🔗 [Essential Steps: Long Term Support for Node.js by Rod Vagg](https://medium.com/@nodesource/essential-steps-long-term-support-for-node-js-8ecf7514dbd) | ||||
| > ... график дополнительных выпусков в каждом из них будет зависеть от наличия исправлений ошибок, исправлений безопасности и других небольших, но важных изменений. Основное внимание будет уделяться стабильности, но стабильность также включает в себя минимизацию количества известных ошибок и устранение проблем безопасности по мере их возникновения. | ||||
|  | ||||
| <br/><br/> | ||||
							
								
								
									
										20
									
								
								sections/production/detectvulnerabilities.russian.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								sections/production/detectvulnerabilities.russian.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | ||||
| # Используйте инструменты, которые автоматически обнаруживают уязвимые зависимости | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Объяснение в один абзац | ||||
|  | ||||
| Современные Node-приложения имеют десятки, а иногда и сотни зависимостей. Если какая-либо из них в зависимостях | ||||
| у вас есть известная уязвимость в безопасности вашего приложения. | ||||
| Следующие инструменты автоматически проверяют наличие известных уязвимостей в ваших зависимостях: | ||||
|  | ||||
| - [npm audit](https://docs.npmjs.com/cli/audit) - аудит npm | ||||
| - [snyk](https://snyk.io/) - постоянно находите и исправляйте уязвимости в ваших зависимостях | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Что говорят другие блоггеры | ||||
|  | ||||
| Из блога [StrongLoop] (https://strongloop.com/strongblog/best-practices-for-express-in-production-part-one-security/): | ||||
|  | ||||
| > ... Использование для управления зависимостями вашего приложения является мощным и удобным. Но используемые вами пакеты могут содержать критические уязвимости безопасности, которые также могут повлиять на ваше приложение. Безопасность вашего приложения так же сильна, как "самая слабая ссылка" в ваших зависимостях. К счастью, есть два полезных инструмента, которые вы можете использовать для обеспечения сторонних пакетов, которые вы используете: nsp и requireSafe. Эти два инструмента в основном делают одно и то же, поэтому использование обоих может оказаться излишним, но "лучше, чем потом сожалеть" - это слова, которые нужно соблюдать, когда речь заходит о безопасности ... | ||||
							
								
								
									
										45
									
								
								sections/production/frontendout.russian.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								sections/production/frontendout.russian.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | ||||
| # Получайте ваши внешние ресурсы вне Node | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Объяснение в один абзац | ||||
|  | ||||
| В классическом веб-приложении серверная часть предоставляет интерфейс/графику браузеру. Очень распространенным подходом в мире Node является использование статического промежуточного программного обеспечения Express для оптимизации статических файлов для клиента. НО - Node не является типичным веб-приложением, поскольку использует один поток, который не оптимизирован для одновременного обслуживания нескольких файлов. Вместо этого рассмотрите возможность использования обратного прокси-сервера (например, nginx, HAProxy), облачного хранилища или CDN (например, AWS S3, хранилища BLOB-объектов Azure и т.д.), который использует множество оптимизаций для этой задачи и обеспечивает гораздо лучшую пропускную способность. Например, специализированное промежуточное программное обеспечение, такое как nginx, воплощает прямые перехватчики между файловой системой и сетевой картой и использует многопоточный подход, чтобы минимизировать вмешательство в множественные запросы. | ||||
|  | ||||
| Ваше оптимальное решение может носить одну из следующих форм: | ||||
|  | ||||
| 1. Используя обратный прокси-сервер - ваши статические файлы будут расположены прямо рядом с вашим приложением Node, только запросы к папке со статическими файлами будут обрабатываться прокси-сервером, который находится перед вашим приложением Node, таким как nginx. Используя этот подход, ваше Node-приложение отвечает за развертывание статических файлов, но не за их обслуживание. Коллеге вашего внешнего интерфейса понравится этот подход, поскольку он предотвращает запросы внешнего происхождения от внешнего интерфейса. | ||||
|  | ||||
| 2. Облачное хранилище - ваши статические файлы НЕ будут частью содержимого приложения Node, они будут загружены в такие сервисы, как AWS S3, Azure BlobStorage или другие подобные сервисы, созданные для этой миссии. Используя этот подход, ваше Node-приложение не несет ответственности за развертывание статических файлов и за их обслуживание, поэтому между Node и Frontend проводится полная развязка, которая в любом случае обрабатывается различными командами. | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Пример конфигурации: типичная конфигурация nginx для обслуживания статических файлов | ||||
|  | ||||
| ```nginx | ||||
| # configure gzip compression | ||||
| gzip on; | ||||
| keepalive 64; | ||||
|  | ||||
| # defining web server | ||||
| server { | ||||
| listen 80; | ||||
| listen 443 ssl; | ||||
|  | ||||
| # handle static content | ||||
| location ~ ^/(images/|img/|javascript/|js/|css/|stylesheets/|flash/|media/|static/|robots.txt|humans.txt|favicon.ico) { | ||||
| root /usr/local/silly_face_society/node/public; | ||||
| access_log off; | ||||
| expires max; | ||||
| } | ||||
| ``` | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Что говорят другие блоггеры | ||||
|  | ||||
| Из блога [StrongLoop](https://strongloop.com/strongblog/best-practices-for-express-in-production-part-two-performance-and-reliability/): | ||||
|  | ||||
| > … В процессе разработки вы можете использовать [res.sendFile()](http://expressjs.com/4x/api.html#res.sendFile) для обслуживания статических файлов. Но не делайте этого в производственном процессе, потому что эта функция должна считывать данные из файловой системы для каждого запроса файла, поэтому она сталкивается со значительной задержкой и влияет на общую производительность приложения. Обратите внимание, что res.sendFile() не реализован с системным вызовом sendfile, что сделает его гораздо более эффективным. Вместо этого используйте статическое промежуточное программное обеспечение (или что-то подобное), оптимизированное для обслуживания файлов для приложений Express. Еще лучшим вариантом является использование обратного прокси-сервера для обслуживания статических файлов; см. Использование обратного прокси-сервера для получения дополнительной информации ... | ||||
|  | ||||
| <br/><br/> | ||||
							
								
								
									
										17
									
								
								sections/production/guardprocess.russian.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								sections/production/guardprocess.russian.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | ||||
| # Защищайте и перезапускайте свой процесс в случае неудачи (используя правильный инструмент) | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Объяснение в один абзац | ||||
|  | ||||
| На базовом уровне процессы Node должны быть защищены и перезапущены при сбоях. Проще говоря, для небольших приложений и тех, кто не использует контейнеры, такие инструменты, как [PM2](https://www.npmjs.com/package/pm2-docker), являются идеальными, поскольку они обеспечивают простоту, перезапускающие возможности, а также богатую интеграцию с узлом. Другие с сильными навыками Linux могут использовать systemd и запускать Node в качестве службы. Вещи становятся более интересными для приложений, использующих Docker или любую контейнерную технологию, поскольку они обычно сопровождаются инструментами управления кластером и оркестровки (например, [AWS ECS](http://docs.aws.amazon.com/AmazonECS/latest/developerguide/Welcome.html), [Kubernetes](https://kubernetes.io/) и т.д.), которые разворачивают, контролируют и восстанавливают контейнеры. Имея все эти богатые функции управления кластером, включая перезапуск контейнера, зачем связываться с другими инструментами, такими как PM2? Там нет пуленепробиваемого ответа. Существуют веские причины держать PM2 в контейнерах (в основном это специфичная для контейнеров версия [pm2-docker](https://www.npmjs.com/package/pm2-docker)) в качестве первого уровня защиты - гораздо быстрее перезапустить обрабатывать и предоставлять специфичные для узла функции, такие как пометка кода, когда хост-контейнер запрашивает корректный перезапуск. Другие могут избежать ненужных слоев. В завершение этой статьи ни одно решение не подходит им всем, и важно знать варианты. | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Что говорят другие блоггеры | ||||
|  | ||||
| * Из [Express Production Best Practices](https://expressjs.com/en/advanced/best-practice-performance.html): | ||||
| > ... В процессе разработки вы запускали свое приложение просто из командной строки с помощью узла server.js или чего-то подобного. **Но делать это на производстве - это путь к катастрофе. В случае сбоя приложения оно будет отключено** до тех пор, пока вы его не перезапустите. Чтобы приложение перезагружалось в случае сбоя, используйте диспетчер процессов. Диспетчер процессов - это "контейнер" для приложений, который облегчает развертывание, обеспечивает высокую доступность и позволяет управлять приложением во время выполнения. | ||||
|  | ||||
| * Из сообщения в Medium [Understanding Node Clustering](https://medium.com/@CodeAndBiscuits/understanding-nodejs-clustering-in-docker-land-64ce2306afef#.cssigr5z3): | ||||
| > ... Понимание кластеризации Node.js в мире Docker: "Контейнеры Docker представляют собой упрощенные, легкие виртуальные среды, предназначенные для упрощения процессов до минимума. Процессы, которые управляют и координируют свои собственные ресурсы, уже не так ценны. **Вместо этого, стеки управления, такие как Kubernetes, Mesos и Cattle, популяризировали концепцию управления этими ресурсами во всей инфраструктуре**. Ресурсы ЦП и памяти распределяются "планировщиками", а сетевые ресурсы управляются балансировщиками нагрузки, предоставляемыми стеком". | ||||
							
								
								
									
										69
									
								
								sections/production/lockdependencies.russian.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								sections/production/lockdependencies.russian.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,69 @@ | ||||
| # Блокируйте зависимости | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Объяснение в один абзац | ||||
|  | ||||
| Ваш код зависит от многих внешних пакетов, допустим, что он "требует" и использует momentjs-2.1.4, тогда по умолчанию при развертывании в рабочей среде npm может получить momentjs-2.1.5, что, к сожалению, приводит к появлению новых ошибок. Использование файлов конфигурации npm и параметра ```-save-correct = true``` указывает npm ссылаться на *точную* версию, которая была установлена, поэтому при следующем запуске ```npm install``` (в работе или в контейнере Docker, который вы планируете отправить для тестирования) будет выбрана та же версия зависимости. Альтернативный и популярный подход заключается в использовании файла `.shrinkwrap` (легко генерируемого с помощью npm), в котором указывается, какие именно пакеты и версии следует установить, чтобы ни у одной среды не было соблазна получить более новые версии, чем ожидалось. | ||||
|  | ||||
| * **Обновление:** начиная с npm 5, зависимости блокируются автоматически с помощью .shrinkwrap. Yarn, еще один менеджер пакетов, также блокирует зависимости по умолчанию. | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Пример кода: файл .npmrc, который указывает npm использовать точные версии | ||||
|  | ||||
| ```npmrc | ||||
| // save this as .npmrc file on the project directory | ||||
| save-exact:true | ||||
| ``` | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Пример кода: файл shrinkwrap.json, в котором определяется точное дерево зависимостей | ||||
|  | ||||
| ```json | ||||
| { | ||||
|     "name": "A", | ||||
|     "dependencies": { | ||||
|         "B": { | ||||
|             "version": "0.0.1", | ||||
|             "dependencies": { | ||||
|                 "C": { | ||||
|                     "version": "0.1.0" | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Пример кода: файл блокировки зависимостей npm 5 - package.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=" | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| ``` | ||||
							
								
								
									
										84
									
								
								sections/production/logrouting.russian.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								sections/production/logrouting.russian.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,84 @@ | ||||
| # Код вашего приложения не должен обрабатывать журналы маршрутизации | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Объяснение в один абзац | ||||
|  | ||||
| Код приложения не должен обрабатывать маршрутизацию журналов, вместо этого должен использовать утилиту ведения журнала для записи в `stdout/stderr`. "Маршрутизация журналов" означает сбор и отправку журналов в другое место, отличное от вашего приложения или процесса приложения, например, запись журналов в файл, базу данных и т.д. Причина этого в основном двоякая: 1) разделение проблемы и 2) [12-фактор лучших методов для современных приложений](https://12factor.net/logs). | ||||
|  | ||||
| Мы часто думаем о "разделении интересов" в части кода между сервисами и между самими сервисами, но это относится и к более "инфраструктурным" компонентам. Код вашего приложения не должен обрабатывать то, что должно обрабатываться инфраструктурой/средой исполнения (чаще всего в наши дни, контейнерами). Что произойдет, если вы определите местоположения журналов в своем приложении, но позже вам нужно будет изменить это местоположение? Это приводит к изменению кода и развертыванию. При работе с контейнерными/облачными платформами контейнеры могут раскручиваться и закрываться при масштабировании в соответствии с требованиями к производительности, поэтому мы не можем быть уверены, где будет находиться файл журнала. Среда выполнения (контейнер) должна решить, куда вместо этого будут направлены файлы журнала. Приложение должно просто записывать то, что ему нужно, в `stdout`/`stderr`, а среда выполнения должна быть настроена так, чтобы он брал поток журналов оттуда и направлял его туда, куда он должен идти. Кроме того, те члены команды, которым необходимо указать и/или изменить места назначения журналов, часто не являются разработчиками приложений, но являются частью DevOps и могут не иметь представления о коде приложения. Это мешает им легко вносить изменения. | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Пример кода - антипаттерн: журнал маршрутизации тесно связан с приложением | ||||
|  | ||||
| ```javascript | ||||
| const { createLogger, transports, winston } = require('winston'); | ||||
| const winston-mongodb = require('winston-mongodb'); | ||||
|   | ||||
| // log to two different files, which the application now must be concerned with | ||||
| const logger = createLogger({ | ||||
|   transports: [ | ||||
|     new transports.File({ filename: 'combined.log' }), | ||||
|   | ||||
|   ], | ||||
|   exceptionHandlers: [ | ||||
|     new transports.File({ filename: 'exceptions.log' }) | ||||
|   ] | ||||
| }); | ||||
|   | ||||
| // log to MongoDB, which the application now must be concerned with | ||||
| winston.add(winston.transports.MongoDB, options); | ||||
| ``` | ||||
| Делая это таким образом, приложение теперь обрабатывает как логику приложения/бизнес, так и логику маршрутизации журнала! | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Пример кода - Улучшенная обработка журнала + пример Docker | ||||
| В приложении: | ||||
| ```javascript | ||||
| const logger = new winston.Logger({ | ||||
|   level: 'info', | ||||
|   transports: [ | ||||
|     new (winston.transports.Console)() | ||||
|   ] | ||||
| }); | ||||
|  | ||||
| logger.log('info', 'Test Log Message with some parameter %s', 'some parameter', { anything: 'This is metadata' }); | ||||
| ``` | ||||
| Затем в Docker-контейнере `daemon.json`: | ||||
| ```javascript | ||||
| { | ||||
|   "log-driver": "splunk", // just using Splunk as an example, it could be another storage type | ||||
|   "log-opts": { | ||||
|     "splunk-token": "", | ||||
|     "splunk-url": "", | ||||
|     ... | ||||
|   } | ||||
| } | ||||
| ``` | ||||
| Таким образом, этот пример выглядит как `log -> stdout -> Docker container -> Splunk` | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Блог "O'Reilly" | ||||
|  | ||||
| Из блога [O'Reilly](https://www.oreilly.com/ideas/a-cloud-native-approach-to-logs), | ||||
| > Когда у вас есть фиксированное количество экземпляров на фиксированном количестве серверов, кажется, что хранение журналов на диске имеет смысл. Однако, когда ваше приложение может динамически переходить от 1 запущенного экземпляра к 100, и вы не знаете, где запущены эти экземпляры, вам необходимо, чтобы ваш облачный провайдер занимался агрегированием этих журналов от вашего имени. | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Цитата из "12-Factor" | ||||
|  | ||||
| Из [12-Factor best practices for logging](https://12factor.net/logs), | ||||
| > Двенадцатикратное приложение никогда не занимается маршрутизацией или хранением своего выходного потока. Оно не должено пытаться писать или управлять лог-файлами. Вместо этого каждый запущенный процесс записывает свой поток событий, без буферизации, в стандартный вывод. | ||||
|   | ||||
| > При промежуточном или производственном развертывании поток каждого процесса будет захвачен средой выполнения, сопоставлен со всеми другими потоками из приложения и направлен в одно или несколько конечных мест назначения для просмотра и долгосрочного архивирования. Эти архивные пункты назначения не видны и не могут быть изменены приложением, а полностью управляются средой выполнения. | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Пример: обзор архитектуры с использованием Docker и Splunk в качестве примера | ||||
|  | ||||
|  | ||||
|  | ||||
| <br/><br/> | ||||
							
								
								
									
										25
									
								
								sections/production/measurememory.russian.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								sections/production/measurememory.russian.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| # Измеряйте и защищайте использование памяти | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Объяснение в один абзац | ||||
|  | ||||
| В идеальном мире веб-разработчик не должен иметь дело с утечками памяти. На самом деле проблемы с памятью - это известная проблема Node, о которой нужно знать. Прежде всего, использование памяти должно постоянно контролироваться. На сайтах в стадии разработки или небольшого производства вы можете измерить это вручную, используя команды Linux или инструменты и библиотеки npm, такие как node-inspector и memwatch. Основным недостатком этих ручных действий является то, что они требуют активного участия человека для мониторинга - для серьезных производственных площадок абсолютно необходимо использовать надежные инструменты мониторинга, например, (AWS CloudWatch, DataDog или любая аналогичная проактивная система), которая предупреждает, когда происходит утечка. Существует также несколько рекомендаций по разработке для предотвращения утечек: избегайте хранения данных на глобальном уровне, используйте потоки для данных с динамическим размером, ограничивайте область видимости переменных с помощью let и const. | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Что говорят другие блоггеры | ||||
|  | ||||
| * Из блога [Dyntrace](http://apmblog.dynatrace.com/): | ||||
| > ... "Как мы уже узнали, в Node.js JavaScript компилируется в нативный код V8. Получающиеся в результате собственные структуры данных не имеют большого отношения к их исходному представлению и управляются исключительно V8. Это означает, что мы не можем активно выделять или освобождать память в JavaScript. V8 использует хорошо известный механизм сбора мусора для решения этой проблемы". | ||||
|  | ||||
| * Из блога [Dyntrace](http://blog.argteam.com/coding/hardening-node-js-for-production-part-2-using-nginx-to-avoid-node-js-load): | ||||
| > ... "Хотя этот пример приводит к очевидным результатам, процесс всегда один и тот же: | ||||
| Создайте дампы кучи с некоторым временем и достаточным количеством памяти, выделяемой между ними | ||||
| Сравните несколько свалок, чтобы узнать, что растет" | ||||
|  | ||||
| * Из блога [Dyntrace](http://blog.argteam.com/coding/hardening-node-js-for-production-part-2-using-nginx-to-avoid-node-js-load): | ||||
| > ... "ошибка, Node.js попытается использовать около 1,5ГБ памяти, которая должна быть ограничена при работе в системах с меньшим объемом памяти. Это ожидаемое поведение, поскольку сборка мусора является очень дорогостоящей операцией. | ||||
| Решением для этого было добавление дополнительного параметра в процесс Node.js: | ||||
| node –max_old_space_size=400 server.js –production" | ||||
| "Почему сбор мусора стоит дорого? Движок V8 JavaScript использует механизм сборки мусора, который останавливает мир. На практике это означает, что программа останавливает выполнение, пока идет сбор мусора". | ||||
							
								
								
									
										39
									
								
								sections/production/monitoring.russian.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								sections/production/monitoring.russian.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | ||||
| # Мониторинг! | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Объяснение в один абзац | ||||
|  | ||||
| На самом базовом уровне мониторинг означает, что вы можете *легко* определить, когда на производстве происходят плохие вещи. Например, получая уведомления по электронной почте или Slack. Задача состоит в том, чтобы выбрать правильный набор инструментов, который удовлетворит ваши требования, не нарушая ваш банк. Позвольте мне начать с определения базового набора метрик, которые необходимо отслеживать для обеспечения работоспособного состояния - ЦП, ОЗУ сервера, ОЗУ процесса узла (менее 1,4ГБ), количество ошибок в последнюю минуту, количество перезапусков процесса, среднее время ответа. Затем перейдите к некоторым дополнительным функциям, которые вам могут понравиться, и добавьте их в свой список пожеланий. Некоторые примеры функции мониторинга класса "люкс": профилирование БД, межсервисное измерение (то есть измерение бизнес-транзакций), интеграция с внешним интерфейсом, предоставление необработанных данных для пользовательских клиентов BI, уведомления Slack и многие другие. | ||||
|  | ||||
| Для реализации расширенных функций требуется длительная настройка или покупка коммерческого продукта, такого как Datadog, NewRelic и тому подобное. К сожалению, достижение даже базовых знаний - это не прогулка в парке, поскольку некоторые метрики связаны с аппаратным обеспечением (ЦП), а другие живут в процессе узла (внутренние ошибки), поэтому все простые инструменты требуют некоторой дополнительной настройки. Например, решения мониторинга облачных поставщиков (например, [AWS CloudWatch](https://aws.amazon.com/cloudwatch/), [Google StackDriver](https://cloud.google.com/stackdriver/)) скажут вам непосредственно о метриках оборудования, но не о внутреннем поведении приложения. С другой стороны, решениям на основе журнала, таким как ElasticSearch, по умолчанию не хватает аппаратного представления. Решение состоит в том, чтобы дополнить ваш выбор отсутствующими метриками, например, популярным выбором является отправка журналов приложений в [Elastic stack](https://www.elastic.co/products) и настройка некоторого дополнительного агента (например, [Beat]( https://www.elastic.co/products)) для обмена информацией об оборудовании, чтобы получить полную картину. | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Пример мониторинга: панель инструментов AWS cloudwatch по умолчанию. Трудно извлечь метрики в приложении | ||||
|  | ||||
|  | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Пример мониторинга: панель мониторинга по умолчанию для StackDriver. Трудно извлечь метрики в приложении | ||||
|  | ||||
|  | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Пример мониторинга: Grafana как слой пользовательского интерфейса, который визуализирует необработанные данные | ||||
|  | ||||
|  | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Что говорят другие блоггеры | ||||
|  | ||||
| Из блога [Rising Stack](http://mubaloo.com/best-practices-deploying-node-js-applications/): | ||||
|  | ||||
| > … Мы рекомендуем вам смотреть эти сигналы для всех ваших услуг: | ||||
| > Частота ошибок: потому что ошибки связаны с пользователем и сразу же влияют на ваших клиентов. | ||||
| > Время отклика: потому что задержка напрямую влияет на ваших клиентов и бизнес. | ||||
| > Пропускная способность: трафик помогает вам понять контекст повышенной частоты ошибок и задержки. | ||||
| > Нагрузка: говорит о том, насколько "нагружен" ваш сервис. Если загрузка процессора составляет 90%, может ли ваша система обрабатывать больше трафика? ... | ||||
							
								
								
									
										16
									
								
								sections/production/productioncode.russian.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								sections/production/productioncode.russian.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | ||||
| # Делайте ваш код готовым к работе | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Объяснение в один абзац | ||||
|  | ||||
| Ниже приведен список советов по разработке, которые сильно влияют на обслуживание и стабильность производства: | ||||
|  | ||||
| * Руководство по двенадцати факторам - ознакомьтесь с руководством [Twelve factors](https://12factor.net/) | ||||
| * Будьте вне сохранения состояния - не сохраняйте данные локально на определенном веб-сервере (см. отдельную рекомендацию - "Будьте без сохранения") | ||||
| * Кэш - интенсивно используйте кэш, но никогда не выходите из строя из-за несоответствия кеша | ||||
| * Проверка памяти - измеряйте использование памяти и утечки как часть процесса разработки, такие инструменты, как "memwatch", могут значительно облегчить эту задачу | ||||
| * Имя функции - Минимизируйте использование анонимных функций (т.е. встроенный обратный вызов), поскольку типичный профилировщик памяти обеспечит использование памяти для имени метода | ||||
| * Используйте инструменты CI - используйте инструмент CI для обнаружения сбоев перед отправкой в производство. Например, используйте ESLint для обнаружения ошибок ссылок и неопределенных переменных. Используйте –trace-sync-io для определения кода, который использует синхронные API (вместо асинхронной версии) | ||||
| * Разумно логируйте - включайте в каждый оператор журнала контекстную информацию, возможно, в формате JSON, чтобы средства агрегирования журналов, такие как Elastic, могли осуществлять поиск по этим свойствам (см. отдельную рекомендацию - "Увеличьте видимость с помощью умных журналов"). Кроме того, включите идентификатор транзакции, который идентифицирует каждый запрос и позволяет сопоставить строки, описывающие одну и ту же транзакцию (см. отдельную рекомендацию - "Включить идентификатор транзакции") | ||||
| * Управление ошибками - обработка ошибок - это ахиллесова пята реальных сайтов Node.js - многие процессы Node завершаются сбоем из-за незначительных ошибок, в то время как другие зависают в аварийном состоянии вместо сбоя. Настройка вашей стратегии обработки ошибок является абсолютно критической, прочитайте здесь мои [error handling best practices](http://goldbergyoni.com/checklist-best-practices-of-node-js-error-handling/) | ||||
							
								
								
									
										32
									
								
								sections/production/setnodeenv.russian.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								sections/production/setnodeenv.russian.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,32 @@ | ||||
| # Установите NODE_ENV = production | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Объяснение в один абзац | ||||
|  | ||||
| Переменные среды - это набор пар ключ-значение, предоставляемых любой работающей программе, обычно для целей конфигурации. Хотя могут использоваться любые переменные, Node поощряет соглашение об использовании переменной с именем NODE_ENV, чтобы указать, находимся ли мы в данный момент в производстве. Это определение позволяет компонентам обеспечивать лучшую диагностику во время разработки, например, путем отключения кэширования или выдачи подробных операторов журнала. Любой современный инструмент развертывания - Chef, Puppet, CloudFormation и другие - поддерживает настройку переменных среды во время развертывания. | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Пример кода: установка и чтение переменной среды NODE_ENV | ||||
|  | ||||
| ```javascript | ||||
| // Setting environment variables in bash before starting the node process | ||||
| $ NODE_ENV=development | ||||
| $ node | ||||
|  | ||||
| // Reading the environment variable using code | ||||
| if (process.env.NODE_ENV === “production”) | ||||
|     useCaching = true; | ||||
| ``` | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Что говорят другие блоггеры | ||||
|  | ||||
| Из блога [dynatrace](https://www.dynatrace.com/blog/the-drastic-effects-of-omitting-node_env-in-your-express-js-applications/): | ||||
| > ... В Node.js существует соглашение об использовании переменной NODE_ENV для установки текущего режима. Мы видим, что на самом деле он читает NODE_ENV и по умолчанию принимает значение "development", если он не установлен. Мы ясно видим, что установив NODE_ENV в рабочее состояние, количество запросов Node.js может обрабатывать скачки примерно на две трети, в то время как загрузка ЦП даже немного падает. *Позвольте мне подчеркнуть это: установка NODE_ENV в рабочий режим делает ваше приложение в 3 раза быстрее!* | ||||
|  | ||||
|  | ||||
|  | ||||
| <br/><br/> | ||||
							
								
								
									
										40
									
								
								sections/production/smartlogging.russian.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								sections/production/smartlogging.russian.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,40 @@ | ||||
| # Сделайте ваше приложение прозрачным, используя умные логи | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Объяснение в один абзац | ||||
|  | ||||
| Так как вы все равно выводите записи журнала, и вам, очевидно, нужен какой-то интерфейс, который объединяет производственную информацию, где вы можете отслеживать ошибки и основные показатели (например, сколько ошибок происходит каждый час и какая ваша самая медленная конечная точка API), почему бы не вкладывать умеренные усилия в надежную систему ведения журналов, которая помечает все флажки? Достижение этого требует вдумчивого решения в три этапа: | ||||
|  | ||||
| **1. умное ведение журналов** - как минимум, вам необходимо использовать авторитетную библиотеку журналов, такую как [Winston](https://github.com/winstonjs/winston), [Bunyan](https://github.com/trentm/node-bunyan), и записывать значимую информацию в начале и конце каждой транзакции. Также следует отформатировать операторы журнала в формате JSON и предоставить все контекстные свойства (например, идентификатор пользователя, тип операции и т.д.), Чтобы операционная группа могла работать с этими полями. Включите также уникальный идентификатор транзакции в каждой строке журнала, для получения дополнительной информации обратитесь к пункту ниже "Записать идентификатор транзакции в журнал". И последнее, на что следует обратить внимание, это также включение агента, который регистрирует системные ресурсы, такие как память, и процессор, такие как Elastic Beat. | ||||
|  | ||||
| **2. умное агрегирование** - когда у вас есть исчерпывающая информация о файловой системе ваших серверов, пора периодически отправлять ее в систему, которая собирает, обрабатывает и визуализирует эти данные. Стек Elastic, например, является популярным и бесплатным выбором, который предлагает все компоненты для агрегирования и визуализации данных. Многие коммерческие продукты предоставляют аналогичные функции, только они значительно сокращают время установки и не требуют хостинга. | ||||
|  | ||||
| **3. умная визуализация** - теперь информация агрегируется и доступна для поиска, которая вполне удовлетворительная, но только с помощью возможности простого поиска в журналах, хотя это может пойти гораздо дальше без необходимости кодирования или больших затрат. Теперь мы можем показывать важные операционные показатели, такие как частота ошибок, средняя загрузка ЦП в течение дня, количество новых пользователей, подключенных за последний час, и любые другие показатели, которые помогают управлять и улучшать наше приложение. | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Пример визуализации: Kibana (часть стека Elastic) облегчает расширенный поиск по содержимому журнала | ||||
|  | ||||
|  | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Пример визуализации: Kibana (часть стека Elastic) визуализирует данные на основе журналов | ||||
|  | ||||
|  | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Цитата блога. Требования к логгеру | ||||
|  | ||||
| Из блога [Strong Loop](https://strongloop.com/strongblog/compare-node-js-logging-winston-bunyan/): | ||||
|  | ||||
| > Давайте определим несколько требований (для регистратора): | ||||
| > 1. Отметка времени каждой строки журнала. Это довольно очевидно - вы должны быть в состоянии сказать, когда произошла каждая запись в журнале. | ||||
| > 2. Формат регистрации должен быть легко усваиваемым людьми и машинами. | ||||
| > 3. Позволяет использовать несколько настраиваемых целевых потоков. Например, вы можете записывать журналы трассировки в один файл, но при возникновении ошибки запишите в тот же файл, затем в файл ошибок и отправьте электронное письмо одновременно ... | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| <br/><br/> | ||||
							
								
								
									
										26
									
								
								sections/production/utilizecpu.russian.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								sections/production/utilizecpu.russian.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | ||||
| # Используйте все ядра процессора | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Объяснение в один абзац | ||||
|  | ||||
| Неудивительно, что в своей базовой форме Node работает над одним потоком = один процесс = один процессор. Плата за мощное оборудование с 4 или 8 процессорами и использование только одного звучит безумно, верно? Самое быстрое решение, которое подходит для приложений среднего размера, - это использование кластерного модуля Node, который из 10 строк кода порождает процесс для каждого логического ядра и направляет запросы между процессами в стиле циклического перебора. Более того, используйте PM2, который приукрашивает модуль кластеризации простым интерфейсом и отличным интерфейсом мониторинга. Хотя это решение хорошо работает для традиционных приложений, оно может не подходить для приложений, требующих первоклассной производительности и надежного потока DevOps. Для этих расширенных вариантов использования рассмотрите возможность репликации процесса NODE с использованием пользовательского сценария развертывания и балансировки с помощью специализированного инструмента, такого как nginx, или используйте механизм контейнеров, такой как AWS ECS или Kubernetees, которые имеют расширенные функции для развертывания и репликации процессов. | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Сравнение: балансировка с использованием кластера Node против nginx | ||||
|  | ||||
|  | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Что говорят другие блоггеры | ||||
|  | ||||
| * Из документации [Node.js documentation](https://nodejs.org/api/cluster.html#cluster_how_it_works): | ||||
| > ... Второй подход, кластеры Node, должен, теоретически, дать лучшую производительность. На практике, однако, распределение имеет тенденцию быть очень несбалансированным из-за капризов планировщика операционной системы. Нагрузки наблюдались, когда более 70% всех соединений заканчивались всего двумя процессами из восьми ... | ||||
|  | ||||
| * Из блога [StrongLoop](https://strongloop.com/strongblog/best-practices-for-express-in-production-part-two-performance-and-reliability/): | ||||
| > ... Кластеризация возможна с помощью кластерного модуля Node. Это позволяет главному процессу порождать рабочие процессы и распределять входящие соединения среди рабочих. Однако вместо того, чтобы использовать этот модуль напрямую, гораздо лучше использовать один из множества инструментов, которые делают это автоматически; например node-pm или cluster-service ... | ||||
|  | ||||
| * Из поста на Medium [Node.js process load balance performance: comparing cluster module, iptables, and Nginx](https://medium.com/@fermads/node-js-process-load-balancing-comparing-cluster-iptables-and-nginx-6746aaf38272) | ||||
| > ... Кластер Node прост в реализации и настройке, все хранится в сфере Node, не завися от другого программного обеспечения. Просто помните, что ваш основной процесс будет работать почти так же, как ваши рабочие процессы, и с меньшей частотой запросов, чем другие решения ... | ||||
							
								
								
									
										37
									
								
								sections/projectstructre/breakintcomponents.russian.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								sections/projectstructre/breakintcomponents.russian.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | ||||
| # Структурируйте свое решение по компонентам | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Объяснение в один абзац | ||||
|  | ||||
| Для приложений среднего размера и выше монолиты действительно плохи - иметь одно большое программное обеспечение с множеством зависимостей просто сложно, и это часто приводит к спагетти-коду. Даже умные архитекторы - те, кто достаточно опытен, чтобы приручить зверя и "модулизируя" его - тратят большие умственные усилия на проектирование, и каждое изменение требует тщательной оценки воздействия на другие зависимые объекты. Конечным решением является разработка небольшого программного обеспечения: разделите весь стек на отдельные компоненты, которые не делятся файлами с другими, каждый из которых содержит очень мало файлов (например, API, сервис, доступ к данным, тестирование и т.д.), Так что очень легко рассуждать об этом. Некоторые могут назвать эту архитектуру "микросервисами" - важно понимать, что микросервисы - это не спецификация, которой вы должны следовать, а скорее набор принципов. Вы можете принять многие принципы в полноценную архитектуру микросервисов или принять только несколько. Оба хороши, если вы сохраняете сложность программного обеспечения на низком уровне. Самое меньшее, что вы должны сделать, это создать базовые границы между компонентами, назначить папку в корне вашего проекта для каждого бизнес-компонента и сделать его автономным - другим компонентам разрешено использовать его функциональные возможности только через открытый интерфейс или API. Это основа для того, чтобы ваши компоненты были простыми, избежать адской зависимости и проложить путь к полноценным микросервисам в будущем, когда ваше приложение будет расти. | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Цитата из блога: "Масштабирование требует масштабирования всего приложения" | ||||
|  | ||||
| Из блога MartinFowler.com | ||||
|  | ||||
| > Монолитные приложения могут быть успешными, но люди все чаще испытывают разочарование в связи с ними, особенно когда в облаке развертывается все бо̀льшие приложений. Циклы изменений связаны друг с другом - изменение, внесенное в небольшую часть приложения, требует перестройки и развертывания всего монолита. Со временем зачастую трудно сохранить хорошую модульную структуру, что усложняет сохранение изменений, которые должны затрагивать только один модуль в этом модуле. Масштабирование требует масштабирования всего приложения, а не его частей, которые требуют больших ресурсов. | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Цитата из блога: "Так что же кричит в архитектуре вашего приложения?" | ||||
|  | ||||
| Из блога [uncle-bob](https://8thlight.com/blog/uncle-bob/2011/09/30/Screaming-Architecture.html)  | ||||
|  | ||||
| > ... если бы вы смотрели на архитектуру библиотеки, вы бы, скорее всего, увидели парадный вход, зону для клерков, места для чтения, небольшие конференц-залы и галерею за галереей, способную вместить книжные полки для все книги в библиотеке. Эта архитектура будет кричать: "Библиотека!".<br/> | ||||
|  | ||||
| Так что же кричит в архитектуре вашего приложения? Когда вы смотрите на структуру каталогов верхнего уровня и исходные файлы в пакете высшего уровня; они кричат: система здравоохранения, или система учета, или система управления запасами? Или они кричат: Rails, или Spring/Hibernate, или ASP? | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Хорошо: структурируйте свое решение по отдельным компонентам | ||||
|  | ||||
|  | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Плохо: сгруппируйте файлы по техническим ролям | ||||
|  | ||||
|  | ||||
							
								
								
									
										41
									
								
								sections/projectstructre/configguide.russian.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								sections/projectstructre/configguide.russian.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | ||||
| # Используйте конфигурацию с учетом среды, безопасную и иерархическую конфигурацию | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Объяснение в один абзац | ||||
|  | ||||
| При работе с данными конфигурации многие вещи могут просто раздражать и замедлять: | ||||
|  | ||||
| 1. Установка всех ключей с использованием переменных среды становится очень утомительной, когда необходимо ввести 100 ключей (вместо того, чтобы просто фиксировать их в файле конфигурации), однако при работе с файлами только администраторы DevOps не могут изменить поведение без изменения кода. Надежное конфигурационное решение должно объединять оба файла конфигурации + переопределения из переменных процесса | ||||
|  | ||||
| 2. При указании всех ключей в плоском JSON становится сложно найти и изменить записи, когда список увеличивается. Эту проблему можно решить с помощью иерархического файла JSON, сгруппированного по разделам. + Несколько библиотек конфигурации позволяют хранить конфигурацию в нескольких файлах и объединять их во время выполнения. См пример ниже | ||||
|  | ||||
| 3. Хранение конфиденциальной информации, такой как пароль БД, явно не рекомендуется, но быстрого и удобного решения для этой задачи не существует. Некоторые библиотеки конфигурации позволяют шифровать файлы, другие шифруют эти записи во время коммитов GIT или просто не сохраняют реальные значения для этих записей и указывают фактическое значение во время развертывания через переменные среды. | ||||
|  | ||||
| 4. Некоторые расширенные сценарии конфигурации требуют ввода значений конфигурации через командную строку (vargs) или синхронизируют информацию о конфигурации через централизованный кеш, такой как Redis, чтобы несколько серверов использовали одни и те же данные конфигурации. | ||||
|  | ||||
| Некоторые библиотеки конфигурации могут предоставить большинство этих функций бесплатно, посмотрите библиотеки npm, такие как [rc](https://www.npmjs.com/package/rc), [nconf](https://www.npmjs.com/package/nconf) и [config](https://www.npmjs.com/package/config), которые отмечают многие из этих требований. | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Пример кода - иерархическая конфигурация помогает находить записи и поддерживать огромные конфигурационные файлы | ||||
|  | ||||
| ```js | ||||
| { | ||||
|   // Customer module configs  | ||||
|   "Customer": { | ||||
|     "dbConfig": { | ||||
|       "host": "localhost", | ||||
|       "port": 5984, | ||||
|       "dbName": "customers" | ||||
|     }, | ||||
|     "credit": { | ||||
|       "initialLimit": 100, | ||||
|       // Set low for development  | ||||
|       "initialDays": 1 | ||||
|     } | ||||
|   } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| <br/><br/> | ||||
							
								
								
									
										13
									
								
								sections/projectstructre/createlayers.russian.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								sections/projectstructre/createlayers.russian.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | ||||
| # Выделяйте ваши компоненты в отдельный слой, держите Express в его граница | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Разделить код компонента на слои: веб, сервисы и DAL | ||||
|  | ||||
|  | ||||
|  | ||||
|  <br/><br/> | ||||
|  | ||||
| ### 1 минутное объяснение: обратная сторона смешения слоев | ||||
|  | ||||
|  | ||||
							
								
								
									
										59
									
								
								sections/projectstructre/separateexpress.russian.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								sections/projectstructre/separateexpress.russian.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,59 @@ | ||||
| # Разделяйте Express "приложение" и "сервер" | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Объяснение в один абзац | ||||
|  | ||||
| Последний генератор Express поставляется с отличной практикой, которую стоит придерживаться - объявление API отделено от конфигурации, связанной с сетью (порт, протокол и т.д.). Это позволяет тестировать API в процессе, не выполняя сетевых вызовов, со всеми преимуществами, которые он приносит в таблицу: быстрое выполнение тестирования и получение метрик покрытия кода. Это также позволяет развертывать один и тот же API в гибких и различных сетевых условиях. Бонус: лучшее разделение проблем и более чистый код | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Пример кода: объявление API, должно находиться в app.js | ||||
|  | ||||
| ```javascript | ||||
| var app = express(); | ||||
| app.use(bodyParser.json()); | ||||
| app.use("/api/events", events.API); | ||||
| app.use("/api/forms", forms); | ||||
| ``` | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Пример кода: сетевое объявление сервера должно находиться в /bin/www | ||||
|  | ||||
| ```javascript | ||||
| var app = require('../app'); | ||||
| var http = require('http'); | ||||
|  | ||||
| /** | ||||
|  * Get port from environment and store in Express. | ||||
|  */ | ||||
|  | ||||
| var port = normalizePort(process.env.PORT || '3000'); | ||||
| app.set('port', port); | ||||
|  | ||||
| /** | ||||
|  * Create HTTP server. | ||||
|  */ | ||||
|  | ||||
| var server = http.createServer(app); | ||||
| ``` | ||||
|  | ||||
| ### Пример: протестируйте свой API в процессе, используя supertest (популярный пакет тестирования) | ||||
|  | ||||
| ```javascript | ||||
| const app = express(); | ||||
|  | ||||
| app.get('/user', function(req, res) { | ||||
|   res.status(200).json({ name: 'tobi' }); | ||||
| }); | ||||
|  | ||||
| request(app) | ||||
|   .get('/user') | ||||
|   .expect('Content-Type', /json/) | ||||
|   .expect('Content-Length', '15') | ||||
|   .expect(200) | ||||
|   .end(function(err, res) { | ||||
|     if (err) throw err; | ||||
|   }); | ||||
| ```` | ||||
							
								
								
									
										27
									
								
								sections/projectstructre/thincomponents.russian.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								sections/projectstructre/thincomponents.russian.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | ||||
| # Структурируйте свое решение по компонентам | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Объяснение в один абзац | ||||
|  | ||||
| Для приложений среднего размера и выше монолиты действительно плохи - об одном большом программном обеспечении с множеством зависимостей просто сложно рассуждать, и оно часто приводит к спагетти кода. Даже те умные архитекторы, которые умеют укротить зверя и «его модульно» - тратят огромные умственные усилия на дизайн, и каждое изменение требует тщательной оценки воздействия на другие зависимые объекты. Конечным решением является разработка небольшого программного обеспечения: разделите весь стек на автономные компоненты, которые не обмениваются файлами с другими, каждый из которых содержит очень мало файлов (например, API, сервис, доступ к данным, тестирование и т.д.), Так что это очень легко рассуждать об этом. Некоторые могут назвать эту архитектуру «микросервисов» - важно понимать, что микросервисы - это не спецификация, которой вы должны следовать, а скорее набор принципов. Вы можете принять многие принципы в полноценную архитектуру микросервисов или принять только несколько. Оба хороши, если вы сохраняете сложность программного обеспечения на низком уровне. Самое меньшее, что вы должны сделать, это создать базовые границы между компонентами, назначить папку в корне вашего проекта для каждого бизнес-компонента и сделать его автономным - другим компонентам разрешено использовать его функциональные возможности только через открытый интерфейс или API. Это основа для того, чтобы ваши компоненты были простыми, избежать адских зависимостей и проложить путь к полноценным микросервисам в будущем, когда ваше приложение будет расти | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Цитата из блога: "Масштабирование требует масштабирования всего приложения" | ||||
|  | ||||
| Из блога MartinFowler.com | ||||
|  | ||||
| > Монолитные приложения могут быть успешными, но люди все чаще испытывают разочарование в связи с ними, особенно когда в облаке развертывается все больше приложений. Циклы изменений связаны друг с другом - изменение, внесенное в небольшую часть приложения, требует перестройки и развертывания всего монолита. Со временем зачастую трудно сохранить хорошую модульную структуру, что усложняет сохранение изменений, которые должны затрагивать только один модуль в этом модуле. Масштабирование требует масштабирования всего приложения, а не его частей, которые требуют больших ресурсов. | ||||
|  | ||||
|  <br/><br/> | ||||
|  | ||||
| ### Хорошо: структурируйте свое решение по отдельным компонентам | ||||
|  | ||||
|  | ||||
|  | ||||
|  <br/><br/> | ||||
|  | ||||
| ### Плохо: сгруппируйте файлы по техническим ролям | ||||
|  | ||||
|  | ||||
							
								
								
									
										13
									
								
								sections/projectstructre/wraputilities.russian.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								sections/projectstructre/wraputilities.russian.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | ||||
| # Оборачивайте общие утилиты в пакеты npm | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Объяснение в один абзац | ||||
|  | ||||
| Как только вы начнете расти и иметь разные компоненты на разных серверах, которые используют одинаковые утилиты, вы должны начать управлять зависимостями - как вы можете сохранить 1 копию своего кода утилиты и позволить нескольким потребительским компонентам использовать и развертывать ее? ну, есть инструмент для этого, он называется npm ... Начните с упаковки сторонних пакетов утилит с вашим собственным кодом, чтобы в будущем его можно было легко заменить, и опубликуйте свой собственный код как частный пакет npm. Теперь вся ваша кодовая база может импортировать этот код и использовать бесплатный инструмент управления зависимостями. Можно публиковать пакеты npm для личного использования, не публикуя их публично, используя [private modules](https://docs.npmjs.com/private-modules/intro), [private registry](https://npme.npmjs.com/docs/tutorials/npm-enterprise-with-nexus.html) или [local npm packages](https://medium.com/@arnaudrinquin/build-modular-application-with-npm-local-modules-dfc5ff047bcc) | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Совместное использование собственных общих утилит в средах и компонентах | ||||
|  | ||||
|  | ||||
							
								
								
									
										54
									
								
								sections/testingandquality/3-parts-in-name.russian.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								sections/testingandquality/3-parts-in-name.russian.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,54 @@ | ||||
| # Включите 3 части в каждое название теста | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Объяснение в один абзац | ||||
|  | ||||
| В отчете о тестировании должно быть указано, удовлетворяет ли текущая версия приложения требованиям людей, которые не обязательно знакомы с кодом: тестировщик, инженер DevOps, который развертывает, и будущее, которое вы через два года. Это может быть достигнуто наилучшим образом, если тесты говорят на уровне требований и состоят из 3 частей: | ||||
|  | ||||
| (1) Что тестируется? Например, метод ProductsService.addNewProduct | ||||
|  | ||||
| (2) При каких обстоятельствах и сценарии? Например, в метод не передается цена | ||||
|  | ||||
| (3) Каков ожидаемый результат? Например, новый продукт не утвержден | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Пример кода: имя теста, состоящее из 3 частей | ||||
| ```javascript | ||||
| //1. unit under test | ||||
| describe('Products Service', function() { | ||||
|   describe('Add new product', function() { | ||||
|     //2. scenario and 3. expectation | ||||
|     it('When no price is specified, then the product status is pending approval', ()=> { | ||||
|       const newProduct = new ProductService().add(...); | ||||
|       expect(newProduct.status).to.equal('pendingApproval'); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
| ``` | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Пример кода - Антипаттерн: нужно прочитать весь тестовый код, чтобы понять намерение | ||||
| ```javascript | ||||
| describe('Products Service', function() { | ||||
|   describe('Add new product', function() { | ||||
|     it('Should return the right status', ()=> { | ||||
|         //hmm, what is this test checking? what are the scenario and expectation? | ||||
|       const newProduct = new ProductService().add(...); | ||||
|       expect(newProduct.status).to.equal('pendingApproval'); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
| ``` | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### "Как правильно сделать пример: отчет об испытаниях напоминает документ с требованиями" | ||||
|  | ||||
|  [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) | ||||
|  | ||||
|   | ||||
|  | ||||
| <br/><br/> | ||||
							
								
								
									
										61
									
								
								sections/testingandquality/aaa.russian.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								sections/testingandquality/aaa.russian.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,61 @@ | ||||
| # Структурируйте тесты по шаблону AAA | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Объяснение в один абзац | ||||
| Нашей самой большой проблемой тестирования является отсутствие свободного пространства - у нас уже есть производственный код, который заставляет нас быть очень занятыми. По этой причине тестовый код должен оставаться очень простым и легким для понимания. При чтении контрольного примера - это не должно восприниматься как чтение императивного кода (циклы, наследование), а скорее как HTML - декларативный опыт. Чтобы добиться этого, придерживайтесь соглашения AAA, чтобы читатели могли легко проанализировать тест. В этом шаблоне есть и другие похожие форматы, такие как XUnit "Setup, Excercise, Verify, Teardown". Это три А: | ||||
|  | ||||
| Первая A - Arrange: Весь код установки, чтобы привести систему к сценарию, который тест должен симулировать. Это может включать создание экземпляра тестируемого модуля, добавление записей БД, обертки/зацепки над объектами и любой другой подготовительный код. | ||||
|  | ||||
| Вторая A - Act: Выполнить тестируемый модуль. Обычно 1 строка кода | ||||
|  | ||||
| Третья A - Assert: убедитесь, что полученное значение соответствует ожидаемому. Обычно 1 строка кода | ||||
|  | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Пример кода: тест, структурированный по шаблону AAA | ||||
| ```javascript | ||||
| describe.skip('Customer classifier', () => { | ||||
|     test('When customer spent more than 500$, should be classified as premium', () => { | ||||
|         //Arrange | ||||
|         const customerToClassify = {spent:505, joined: new Date(), id:1} | ||||
|         const DBStub = sinon.stub(dataAccess, "getCustomer") | ||||
|             .reply({id:1, classification: 'regular'}); | ||||
|  | ||||
|         //Act | ||||
|         const receivedClassification = customerClassifier.classifyCustomer(customerToClassify); | ||||
|  | ||||
|         //Assert | ||||
|         expect(receivedClassification).toMatch('premium'); | ||||
|     }); | ||||
| }); | ||||
| ``` | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Пример кода - Антипаттерн: нет разделения, сплошной объем, труднее интерпретировать | ||||
| ```javascript | ||||
| test('Should be classified as premium', () => { | ||||
|         const customerToClassify = {spent:505, joined: new Date(), id:1} | ||||
|         const DBStub = sinon.stub(dataAccess, "getCustomer") | ||||
|             .reply({id:1, classification: 'regular'}); | ||||
|         const receivedClassification = customerClassifier.classifyCustomer(customerToClassify); | ||||
|         expect(receivedClassification).toMatch('premium'); | ||||
|     }); | ||||
| ``` | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### "Включите 6 частей в каждом тесте" | ||||
|  | ||||
|  [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) | ||||
|  | ||||
|   | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### "Для читателя теста важно иметь возможность быстро определить, какое поведение проверяет тест" | ||||
| Из книги [XUnit Patterns](http://xunitpatterns.com/Four%20Phase%20Test.html): | ||||
|  | ||||
| > Для читателя теста важно иметь возможность быстро определить, какое поведение проверяет тест. Это может быть очень запутанным, когда вызываются различные варианты поведения тестируемой системы (SUT), некоторые для настройки предтестового состояния (фиксатора) SUT, другие для проверки SUT и третьи для проверки пост-теста состояние СУТ. Четкое определение четырех фаз значительно облегчает понимание цели теста. | ||||
| @ -0,0 +1,42 @@ | ||||
| # Избегайте глобальных тестовых приспособлений и параметров, добавляйте данные для каждого теста | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Объяснение в один абзац | ||||
|  | ||||
| Следуя золотому правилу тестирования - не усложняйте контрольные примеры, каждый тест должен добавлять и воздействовать на свой собственный набор строк БД, чтобы избежать связывания и легко рассуждать о ходе тестирования. В действительности это часто нарушается тестерами, которые загружают данные в БД перед запуском тестов (также называемых «тестовым креплением») для повышения производительности. Хотя производительность действительно является серьезной проблемой - ее можно уменьшить (например, в БД в памяти, см. Раздел «Тестирование компонентов»), однако сложность тестирования - это очень болезненное горе, которое должно руководствоваться другими соображениями. Практически, сделайте каждый тестовый пример явно добавляющим необходимые ему записи БД и действуйте только на эти записи. Если производительность становится критической проблемой - сбалансированный компромисс может прийти в виде заполнения единственного набора тестов, которые не изменяют данные (например, запросы) | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Пример кода: каждый тест действует на свой собственный набор данных | ||||
| ```javascript | ||||
| it("When updating site name, get successful confirmation", async () => { | ||||
|   //test is adding a fresh new records and acting on the records only | ||||
|   const siteUnderTest = await SiteService.addSite({ | ||||
|     name: "siteForUpdateTest" | ||||
|   }); | ||||
|   const updateNameResult = await SiteService.changeName(siteUnderTest, "newName"); | ||||
|   expect(updateNameResult).to.be(true); | ||||
| }); | ||||
| ``` | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Пример кода - Антипаттерн: тесты не являются независимыми и предполагают наличие некоторых предварительно настроенных данных | ||||
| ```javascript | ||||
| before(() => { | ||||
|   //adding sites and admins data to our DB. Where is the data? outside. At some external json or migration framework | ||||
|   await DB.AddSeedDataFromJson('seed.json'); | ||||
| }); | ||||
| it("When updating site name, get successful confirmation", async () => { | ||||
|   //I know that site name "portal" exists - I saw it in the seed files | ||||
|   const siteToUpdate = await SiteService.getSiteByName("Portal"); | ||||
|   const updateNameResult = await SiteService.changeName(siteToUpdate, "newName"); | ||||
|   expect(updateNameResult).to.be(true); | ||||
| }); | ||||
| it("When querying by site name, get the right site", async () => { | ||||
|   //I know that site name "portal" exists - I saw it in the seed files | ||||
|   const siteToCheck = await SiteService.getSiteByName("Portal"); | ||||
|   expect(siteToCheck.name).to.be.equal("Portal"); //Failure! The previous test change the name :[ | ||||
| }); | ||||
| ``` | ||||
							
								
								
									
										51
									
								
								sections/testingandquality/citools.russian.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								sections/testingandquality/citools.russian.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | ||||
| # Тщательно выбирайте платформу CI | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Объяснение в один абзац | ||||
|  | ||||
| Раньше мир CI был гибкостью [Jenkins](https://jenkins.io/) по сравнению с простотой поставщиков SaaS. Теперь игра меняется, так как провайдеры SaaS, такие как [CircleCI](https://circleci.com/) и [Travis](https://travis-ci.org/), предлагают надежные решения, включая контейнеры Docker, с минимальным временем установки, в то время как Jenkins пытается конкурировать и в сегменте «простота». Несмотря на то, что в облаке можно настроить полнофункциональное CI-решение, в случае необходимости контролировать мельчайшие детали Jenkins по-прежнему остается предпочтительной платформой. В конечном итоге выбор сводится к тому, в какой степени процесс CI должен быть настроен: поставщики бесплатных и настраиваемых облачных сред позволяют запускать пользовательские команды оболочки, настраиваемые образы докеров, настраивать рабочий процесс, запускать сборки матрицы и другие богатые функции. Однако, если управление инфраструктурой или программирование логики CI с использованием формального языка программирования, такого как Java, желательны - Дженкинс все еще может быть выбором. В противном случае рассмотрите вариант выбора простой и бесплатной настройки облака. | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Пример кода - типичная конфигурация облачного CI. Одиночный файл .yml и все | ||||
|  | ||||
| ```javascript | ||||
| 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 - почти нулевая настройка облака CI | ||||
|  | ||||
|  | ||||
|  | ||||
| ### Дженкинс - сложный и надежный CI | ||||
|  | ||||
|  | ||||
|  | ||||
| <br/><br/> | ||||
							
								
								
									
										43
									
								
								sections/testingandquality/refactoring.russian.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								sections/testingandquality/refactoring.russian.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,43 @@ | ||||
| # Рефакторинг | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Объяснение в один абзац | ||||
|  | ||||
| Рефакторинг является важным мероприятием в процессе итеративной разработки. Удаление "запахов кода" (плохих методов кодирования), таких как дублированный код, длинные методы, список длинных параметров, улучшит ваш код и сделает его более понятным. Использование инструментов статического анализа поможет вам найти эти запахи кода и построить процесс вокруг рефакторинга. Добавление этих инструментов в вашу сборку CI поможет автоматизировать процесс проверки качества. Если ваш CI интегрируется с таким инструментом, как Sonar или Code Climate, сборка завершится неудачно, если он обнаружит запах кода и сообщит автору, как решить проблему. Эти инструменты статического анализа дополнят такие инструменты lint, как ESLint. Большинство инструментов для рисования будут сосредоточены на стилях кода, таких как отступы и пропущенные точки с запятой (хотя некоторые найдут запахи кода, такие как функции Long) в одном файле, в то время как инструменты статического анализа сосредоточатся на поиске запахов кода (дублирующий код, анализ сложности и т.д.), Которые находятся в отдельные файлы и несколько файлов. | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
|  | ||||
| ### Мартин Фаулер - главный научный сотрудник ThoughtWorks | ||||
|  | ||||
| Из книги "Рефакторинг - улучшение дизайна существующего кода" | ||||
|  | ||||
| > Рефакторинг - это контролируемый метод улучшения дизайна существующей кодовой базы. | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Эван Бурхард - консультант по веб-разработке и автор | ||||
|  | ||||
| Из книги "Рефакторинг JavaScript: Превращение плохого кода в хороший код" | ||||
|  | ||||
| > Независимо от того, фреймворк или | ||||
| "compiles-to-JS" язык или билиотеку вы используете, ошибки и проблемы с производительностью | ||||
| всегда будут проблемой, если низкое качество вашего JavaScript плохое. | ||||
|  | ||||
| <br/><br/> | ||||
|  | ||||
| ### Пример: Анализ сложных методов с помощью CodeClimate (коммерческий) | ||||
|  | ||||
|  | ||||
|  | ||||
| ### Пример: Тенденции и история анализа кода с CodeClimate (коммерческий) | ||||
|  | ||||
|  | ||||
|  | ||||
| ### Пример: Сводка анализа кода и тенденции с SonarQube (коммерческий) | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| <br/><br/> | ||||
		Reference in New Issue
	
	Block a user
	 Yoni Goldberg
					Yoni Goldberg