backend для мобильных приложений

Содержание:

Топовый стек: Backend и Frontend для мобильного приложения

Мини-обзор без референсов

%D1%84%D0%BE%D1%82%D0%BE %D0%93%D0%B0%D0%BB%D1%8F

Ingredients

Directions

Node.js (бэк) + React Native (фронт)

Одна из наиболее сильных связок в качестве стека для разработки приложения. React Native — это кроссплатформенный фреймворк, который можно отнести к флагману мобильного девелопмента. С его помощью были написаны или переписаны на React. Между прочим, инста — это настоящий хайлоад : за один месяц приложение посещает 1 миллиард активных пользователей, более 500 миллионов используют его ежедневно. Даже Tesla использует этот фреймворк для мобильного приложения по управлению автомобилем

2nd jpg 1

Мобильное приложение React с API-интерфейсом Node.js работает через Java Scrtipt как на веб-интерфейсе, так и на бэкенде. Это позволяет писать действительно нативные приложения — React переводит весь написанный JavaScript-код на «родной» язык конкретного устройства, например Java на Android или Objective-C на iOS, а для стилизации можно использовать даже CSS-код

Python (бэк) + Kotlin (фронт)

3rd 2

Довольно интересная связка, где в качестве бэка используется Python (работа с БД), и языком программирования Kotlin в качестве графической оболочки (GUI). В Pynhon есть бесплатные фреймворки для разработки мобильных приложений (Kivy или Beeware), но как «фронт» питон для программирования UI приложений не очень удобен (здесь как раз подойдет Kotlin), зато его можно задействовать в бэкенде, т.к язык располагает к жонглированию больших объёмов данных и применению машинного обучения (не зря же его используют в Data Sciense).

Один из самых известных фреймворков Django как раз написан на Python

Котлин же как раз очень удобен в плане разработки интерфейса, благодаря user-friendly синтаксису и получивший полную поддержку установочных пакетов Google и IDE, включая Android и SDK.

Laravel + Flutter

1st 2

Флаттер — крутой инструмент разработчика UI для создания красивых и нативных приложений на всех платформах — десктоп, мобайл, веб. Среда Flutter используется как единая база кода, которая компилируется в собственный код для iOS и Android. Flutter довольно давно снискал популярность среди западных front-end разработчиков. У нас же в стране хоть и хвалят его за упрощенный процесс верстки, но пока не пользуется большим спросом.

Lavarel — фреймворк, работающий на бэке. С его помощью, используя API, можно писать «классические» серверные функции — учетные записи пользователей, управление заказами и т.д.(например, авторизация делается с помощью Laravel Passport). Он имеет открытый исходный код и имеет ряд функций для упрощения разработки и автоматизированными тестами.

Источник

Как организовать бэкенд мобильного приложения?

cxckzjwahn

Что мы делаем? Сервис регистрации и авторизации пользователя для мобильного приложения

В пет-проектах каждого мобильного разработчика рано или поздно наступает момент, когда требуется быстро и без лишней головной боли создать сервер для своего приложения. Не важно, какую функцию должен выполнять сервер: будь то хранение данных или регистрация/авторизация пользователей.

Как правило, вначале все идут (ну или большинство) по пути наименьшего сопротивления. Мы ищем готовое решение и смотрим, как быстро его можно приспособить для наших нужд.

На данном этапе первое, что получается «нагуглить» — это сервисы Firebase, бесплатных лимитов которых более чем достаточно для организации бекенда небольшого мобильного приложения. Но в данном случае, рассматривая именно российского разработчика, мы рискуем наступить на грабли нашего законодательства — трансграничную передачу данных и хранение персональных данных пользователя.

(ФЗ 152 «О персональных данных», ст. 12, Глава 2)

Соблазн использования именно Firebase велик, но если мы хотим застраховаться от ненужной возни с различными надзорными ведомствами, то начинаем смотреть альтернативные варианты.

Следующий этап — это использование VDS-сервера с каким либо open-source или freemium решением, где за основу берется готовый «сервис-как-услуга» или решение, позволяющее развернуть похожий функционал.

Несколько лет назад на Хабре я уже писал подробное руководство по настройке BaasBox (статья была убрана из паблика по причине устаревшей информации) на арендованном сервере и приводил пример использования различных вызовов в iOS-приложении для языка Objective C. Но BaasBox реально «тяжеловес» и диктует свой минимум для арендуемого сервера. Немного поигравшись с ним, было решено использовать другое решение. Parse-server на тот момент только недавно был отдан в open-source разработку компанией Facebook, не имел столь большого количества адаптеров, как в настоящее время, но его возможностей было более чем достаточно для личных проектов и приложений частных заказчиков (многие проекты до сих пор существуют и стабильно работают).

Справедливости ради, стоит отметить, что parse-server очень сильно повзрослел и активно развивается. На текущий момент воссоздан практически весь функционал, что был доступен в коммерческом предке. Можно писать свои хуки, локализованные пуш-уведомления, менеджер процессов и есть даже подписка на изменение объектов, основанная на сокетах (ParseLiveQuery — если будет интересно, напишу отдельно статью по настройке ParseLiveQuery).

Но parse-server перестал быть интересен именно в тот момент, когда потребовалось реализовать нестандартный тип данных, с которым сложно работать на основе определенных в системе типов. Также мешает то, что не являясь профильным серверным разработчиком, ранее я не придавал значения более эффективному развертыванию окружения и многие файлы конфигураций делались руками, при этом действия постоянно повторялись на каждом новом сервере. Именно в этот момент и приходит понимание, что коробочное решение — это не решение всех проблем, и следует переходить к следующему этапу организации своего сервера для мобильного приложения.

В последнее время мой основной язык разработки — Swift. Поэтому именно он и интересен мне в первую очередь в написании серверного кода. Сам по себе язык Swift легко установить на unix-системе, но это не даст никаких явных преимуществ. По своей сути это будет напоминать разработку консольного приложения со сложной логикой. Придется много времени потратить на воссоздание базовых методов, необходимых в работе сервера.

Как и во многих других языках, server side swift имеет свои фреймворки и коммьюнити, участвующие в развитии этих решений.

На текущий момент можно выделить три наиболее значимых решения для разработки server side swift:

В части документации и поддержки, мне более нравится Vapor, но это дело вкуса. Кому то будут близки другие решения. Так или иначе, во многих моментах они похожи.

Естественно, что далее на протяжении всего цикла статей в своих примерах я буду использовать Vapor. На его основе мы реализуем сервис регистрации/авторизации пользователя, отправку и подтверждение email, возможность сброса и изменения пароля.

image loaderimage loader
image loaderimage loader
Стоит ли делать реализацию без практической пользы?

Скорей всего, нет! Поэтому мы сделаем максимально взрослый сервис, который можно брать и использовать для организации логики хранения данных пользователя на своем сервере.

Если решение взрослое, то оно влечет применение обдуманных решений. Мы должны упростить масштабирование, реализовать валидацию данных и предусмотреть хранение сессии пользователя, чтобы не заставлять его каждый раз вводить свой логин и пароль.

Что нам для этого потребуется?

Честно говоря, я в свое время скептически относился к докеру, но следовало более внимательно рассмотреть эту технологию. Цель статьи не в объяснении его работы и обучению работы с ним (подозреваю, что мне самому предстоит еще узнать много интересных возможностей докера). Но те, кто не знает, что это такое, и как с ним работать, могут самостоятельно начать знакомство с Docker по официальной ссылке: www.docker.com

Забегая вперед, оставлю еще полезную ссылку на приложение Kitematic, которое призвано упростить работу с контейнерами докера: kitematic.com (must have для тех, кто не любит пользоваться терминалом).

Итак, начнем с установки Docker на mac-компьютер:

Переходим по ссылке hub.docker.com/editions/community/docker-ce-desktop-mac и скачиваем Get Docker Desktop For Mac (Stable)

image loader

Открываем полученный образ и далее, установка ничем не отличается от стандартного копирования приложения в каталог программ.

image loader

После достаточно запустить приложение и дождаться полной инициализации сервиса.

image loaderimage loader

Если еще нет Docker ID, то его следует создать на hub.docker.com А если есть, то просто авторизоваться в приложении.

image loader

Вот и все, подготовка к использованию Docker завершена. Осталось лишь проверить текущую версию и информацию об окружении.

> docker version
image loader

> docker info
image loader
На этом подготовка к разработке сервиса авторизации завершена. В следующей части мы посмотрим, как можно использовать контейнеры различных сервисов, разберемся с docker-compose для автоматизации сборки нашего окружения и начнем писать код.

P.S.: Небольшой совет из личного опыта. Когда мы разрабатываем сервисы на своей локальной машине, Docker выделяем для своего использования ресурсы по умолчанию. Если мы хотим визуализировать ожидаемое поведение сервиса на удаленном сервере, стоит позаботиться о ресурсах на локальной машине, максимально приближенным к характеристикам сервера. Сделать это можно в настройках приложения Docker Desktop, что мы скачали:

image loader

Автор статьи:
Виталий Подольский, преподаватель HackerU

Источник

Отличный backend для любых мобильных приложений 2021

Эта статья предназначена для разработчиков, которые находятся в поиске оптимального бэкенда для своего мобильного приложения.

В 2016 году мы решили, что для нашей CMS обязательно нужны мобильные приложения. Именно в этом году мы приступили к разработке полномасштабного движка внешних API и ведем данную разработку и по сей день.

В процессе разработки наших мобильных приложений, мы столкнулись со множеством задач, организационных, архитектурных и технических, которые мы успешно решали, попутно систематизируя свои знания и требования к идеальному бэкенду. В этой статье, мы подробно расскажем о нашем опыте и наших инструментах.

Проблемы и решения

Документация для API

Первой проблемой, с которой мы сразу столкнулись – это координация взаимодействия бэкенд-разработчиков API и фронтенд-разработчиков приложения. Чтобы коммуникация данных специалистов не занимала неприлично большое время, нужно было максимально сделать независимой работу каждого из этих специалистов.

Именно для этого, мы разработали самодокументируемый API. Это означает, что бэкенд-программист пишет методы API, правила валидации параметров, документирует все входящие параметры, назначение метода, пример результата выполнения метода, а разработчик приложения пользуется только готовой документацией, которая строится в реальном времени.

Вот как выглядит код backend разработчика:

Вот так выглядит построенная документация со стороны фронтенд программиста:

api method help

Документация строится в разрезе версий и языков для каждого метода. Как только программист размечает свою документацию на нескольких языках, соответствующие переключатели (язык и версии) появляются в документации.

api method langs

Логирование

Приложение, которое подразумевает взаимодействие по API не мыслимо без удобных инструментов логирования. Это основной и самый первый пункт, который мы доводили до максимального удобства.

В ReadyScript в административной панели в настройках модуля Внешнее API есть пункт Журнал запросов к API, который открывает подробный список всех произведенных к API запросов с удобной фильтрацией.

api log list

Лог показывает Дату, время, IP, метод, статус ответа, параметры входящего запроса, тело ответа на запрос.

api log view

Фронтенд разработчик приложения должен иметь доступ в данный раздел. Понятные и достаточно подробные сообщения об ошибках окончательно исключают необходимость взаимодействия фронт и бек разработчиков.

Версионирование и языки

Модуль «Внешнее API» поддерживает возможность версионности методов API. Это означает, что метод различных версии может иметь различный набор параметров, а также возвращать различный результат.

Пример вызова метода news.getList версии 1 /api/methods/news.getList?token=abcd. &v=1

Пример вызова метода news.getList версии 2 /api/methods/news.getList?token=abcd. &some_param=345&v=2

Пример метода API news.getList, который имеет 3 версии:

Язык, на котором следует вернуть результат передается через необязательный параметр lang (по умлчанию он равен ru). В случае, если параметр lang передан, перед выполнением метода API, модуль устанвливает указанный язык в качестве текущего в системе на время выполнения данного запроса.

Модуль внешнее API может автоматически формировать справку на нескольких языках, если использовать специальный синтаксис при создании phpDoc комментария.

Авторизация и готовые методы

Практически любое приложение нуждается в готовом API для авторизации, в результате которого приложению выдается токен, который наделен необходимыми правами.

В ReadyScript для этого есть готовый метод API. Достаточно выполнить POST запрос на /api/methods/oauth.token?grant_type=password&client_id=myapp&client_secret=myappsecret&username=demo_example.com&password=xxxxxxx

И получить в ответ JSON со сведениями об авторизационном токене и полными сведениями о пользователе.

Вообще в ReadyScript есть 77 готовых методов API для работы с пользователями, категориями, товарами, брендами, статьями, уведомлениями, заказами, корзиной, push-уведомлениями, меню, и др.

С одной стороны, готовые методы – это отличный пример того, как могут быть реализованы методы API, с другой – это готовые методы, которыми реально можно пользоваться.

Разграничение прав пользователей

Доступ к авторизованным методам API можно получить только имея токен авторизации, а данный токен можно получить только для некоторого объекта приложения(не зря в методе авторизации присутствует client_id, client_secret).

Объект приложения – с технической точки зрения – это класс, который имеет свой client_id и client_secret, в котором необходимо задекларировать все методы API, с которыми будет работать данное приложение.

Также непосредственно внутри реализации каждого метода API всегда можно бросить исключение, что будет обработано и возвращено в JSON API как ошибка.

Регистрация Push-токенов, отправка Push уведомлений

Push-уведомления – это базовая фишка любого приложения, но не многие понимают как это устроено «под капотом» и что для этого необходимо на стороне backend’а.

В доставке сообщений участвуют следующие сервисы: Ваш backend, сервис Firebase Cloud Messaging, мобильное устройство вашего клиента.

Firebase Cloud Messaging (FCM) – выступает в роли сервера, который держит связь со всеми клиентами вашего приложения. Именно он выдает push-token или идентификатор устройства, используя который потом можно конкретному человеку отправить push уведомление.

Именно в настройках FCM, вам нужно будет загрузить необходимые файлы и сертификаты от Apple и Google для вашего конкретного приложения. Только после этого будет возможна связь приложения и FCM.

Рассмотрим теперь детально последовательность действий приложения по получению и push-token и сообщения его backend’у.

Далее, когда бэкенд желает отправить push-уведомление клиенту, действия выполняются в следующем порядке:

Как видно, из написанного выше, бэкенд должен иметь методы API для сохранения push-token’а, а также уметь работать с FCM для отправки push уведомлений. ReadyScript умеет это делать из коробки.

Для регистрации push-token’а достаточно выполнить GET или POST запрос к API:

Также допускается передавать push-token бэкенду в момент авторизации пользователя в приложении, для этого достаточно добавить параметр custom[push-token] в запросе к методу oauth.token

Готовая админка для бэкенда

Данные, которые отображаются в мобильном приложении должны где-то администрироваться. То есть должен быть интерфейс, куда заходят контентщики, модераторы или администраторы приложения и работают с контентом приложения.

ReadyScript позволяет быстро создавать максимально комфортные для работы разделы с удобными панелями поиска и навигации. Все разделы сразу адаптивные, что означает, что ими можно пользоваться даже на мобильном устройстве.

admin table. view

Программисту в ReadyScript не нужно писать свой HTML с формами. Достаточно описать состав полей ORM объектов средствами ООП и все формы система будет строить автоматически. Более того, структура базы данных будет приведена в соответствие с описанием ORM объектов.

admin form

ReadyScript предоставляет удобные инструменты для создания виждетов, из которых можно собирать удобны dash-board (сводку информации).

admin dashboard

Эргономика панели администрирования – это важная составляющая любого бизнеса. Использование готовой административной панели ReadyScript – это экономия времени на экспериментах и возможность сразу использовать многолетний опыт нашей команды, основанный на постоянном взаимодействии с нашими клиентами.

Пошаговая инструкция по разработке собственных методов API

Программистам важно один раз увидеть код, чтобы понять, что их будет ожидать, когда они возьмутся за какой-нибудь реальный проект. Специально для этого, мы подготовили отдельную статью, в которой пошагово рассматриваем процесс разработки собственных методов API на платформе ReadyScript.

Какие приложения пользуются внешним API ReadyScript?

В начале статьи мы написали, что перед нами стояла задача строить собственные приложения. И мы разработали в итоге приложение для администраторов и курьеров, а также целый SaaS сервис ReadyScript Mobile, который позволяет нашим клиентам быстро получить полномасштабное мобильное приложение интернет-магазина для конечных клиентов.

Наши внешние API мы также используем в наших Desktop приложениях, разработанных на стеке Electron.js + Angular.

Приложения хорошо себя показали на реальных нагрузках, об одном из наших клиентов, мы написали обзорную статью. JSON API работают быстро и стабильно.

Таким образом, мы стали первыми потребителями собственного движка внешних API и можем ответственно рекомендовать его для использования в различных проектах всем нашим партнерам.

Для каких приложений можно выбрать ReadyScript в качестве бэкенда?

Хотя фреймворк ReadyScript особенно заточен для электронной коммерции и имеет для этого огромное число базовых сущностей(товары, доставки, оплаты, заказы, склад, цены, …), которые хорошо спроектированы и документированы, сфера его применения этим не ограничивается.

Академичность и глубокая документированность фреймворка, позволяет быстро изучать его основные принципы работы и расширять его функциональность новыми сущностями, взаимосвязями, новыми методами внешнего API с помощью дополнительных модулей.

Организовывайте работу разработчиков, опираясь на нашу инфраструктуру и создавайте ваши собственные приложения любой тематики с удобным и надежным JSON API на бэкенде с ReadyScript.

Лицензирование

Модуль внешних API присутствует во всех редакциях платформы ReadyScript (Витрина, Маркет, Гипермаркет, Мегамаркет). Это означает, что нет ограничения в выборе. Подробное описание возможностей разных редакций представлено здесь.

ReadyScript обладает самой гибкой системой лицензирования. Вы можете бесконечно разрабатывать и тестировать ваш сервис на локальных доменах *.local, *.test.

30 дней можно использовать trial-версию ReadyScript на «боевом» домене, далее потребуется приобрести временную или бессрочную лицензию на продукт.

Технологический стек. Полезные ссылки

Для работы CMS ReadyScript требуется PHP 7.1+, MySQL 5+

Источник

Как написать максимально хреновый бэкенд для мобильного приложения

image loader

Известно, что практически ни одно мобильное приложение не обходится без бэкенда.

Если вы мобильный разработчик, то наверняка сталкивались с такими бородатыми дядями, которые меланхолично тянут логику на перле и вечно что-то пишут в консоли. Или может это был сутулый анимешник с длинными волосами, всосавший php с молоком матери.
Так или иначе, большинство из них ни разу не сталкивалось с мобильной разработкой, а кое-кто считает себя при этом гуру.

Специально для таких случаев, я подготовил список вредных советов о том как угробить бэкенд вашего приложения.

Приятного чтения.
Итак, если вы серверный разработчик:

02ec39bdb6f047519f2d01db84bcccc0

Когда показывал эту статью коллегам, то многие бэкенд разработчики тоже решили поделиться парой наболевших моментов:

416d63d7db7f47bab2eae3b339a109e6
(Может быть, им просто одиноко и не с кем поговорить?)

Полезные рекомендации

Вместе посмеяться над знакомыми ситуациями — это здорово, но кроме этого хотелось бы поделиться еще действенными практиками, которые мы используем у себя. Даже когда приходится работать с внешними мобильными разработчиками, они всегда благодарят нас за исключительно удобное API и профессионализм.

Все дальнейшие советы относятся к бэкенду, но если вы мобильный разработчик, то вам тоже будет интересно и полезно это прочитать. Ведь в первую очередь именно вы заинтересованы в изменениях.

Документация

Это интерфейс для мобильного разработчика. Она должна быть не просто информативна, но еще легко читаться и быть приятной глазу. Звучит странно, но чем легче воспринимается документ, тем быстрее и проще с ним работать, и тем меньше возникает к вам вопросов в процессе.

Самый простой и удобный вариант — это использовать Swagger. Хоть его изначальный внешний вид и оставляет желать лучшего:

image loader

Но его можно без проблем облагородить с помощью форматтера:

image loader

Получается симпатично и удобно. В качестве альтернатив можно использовать Apiary, но придется разделять код и документацию, что нежелательно, либо заморачиваться с рендерингом.

Единообразие

В мобильной разработке есть сложность — многие решения и фреймворки крайне неповоротливы. Нельзя просто взять и поменять формат для какого-то одного конкретного запроса, либо это предельно сложно. Как и нельзя изменить название определенного поля только для определенного случая: бедный девелопер будет орать в голосину, пытаясь воткнуть под это костыль.

Все должно быть целостно: везде одинаковые названия, один формат взаимодействия (предпочтительно JSON), и тп.

Особенно хорошо, если названия параметров в запросе и ответе идеально совпадают с полями соответствующих классов в мобильном приложении. Звучит странно, но это настолько упрощает жизнь разработчикам, что они будут вам за это шоколадки таскать из магазина.

В некоторых местах упрощение доходит до абсурда: например, сохранение в Realm (мобильная база данных) может быть произведено практически сразу из json. Если будет интересно, то отдельно расскажу о том, как мы избавлялись от middleware в мобильном приложении.

Пример кода по сохранению любых пришедших объектов на iOS:
image loader
Один generic метод на любую запись в базу с сервера. Классно, правда?

Тоже самое касается и изображений. Лучше всего, когда на картинку сразу приходит ссылка, которую не нужно ‘доделывать’. И по тому же правилу — название ссылки должно быть везде одинаковым.

У нас был случай, когда нужно было искать изображения в гугле для определенных информационных блоков в мобильном приложении. В итоге мы просто сделали псевдо-ссылку на картинку, к которой приложение обращается, а внутри сервак ищет подходящее изображение в гугле и делает на нее редирект. А для приложения это выглядит как самая обыкновенная пикча, которая просто немного дольше соображает.

Достаточность

Когда работаешь над сервером, то привычно, что все находится в едином scope запроса, где достаточно просто открыть транзакцию на запись и в нее последовательно протолкнуть данные. Все изолированно, предсказуемо и линейно.

В мобильном приложении такого нет. Все крутится асинхронно, а если требуется соблюсти целостность данных из разных запросов, то это выливается в сложнейшие манипуляции с многопоточностью, злющими критическими секциями и распределением приоритетов, чтобы не было и намека на тормоза. Не зря вопрос про синхронизацию потоков в собеседовании на мобильного разработчика задают одним из первых.

Теперь понимаете, почему мобильные девелоперы стараются, чтобы все приходило в едином запросе? От этого зависит, уйдут они сегодня домой или нет)

И конечно, если какие-то данные нужно загрузить асинхронно, то не надо их пихать в общую кучу, это надо понимать.

В конце концов, не поленитесь открыть дизайн приложения и посмотреть из чего состоит экран для которого вы делаете API. Посоветуйтесь с вашими мобильными коллегами, определите как лучше вам отдавать им данные и какие последующие запросы будут от них зависеть. Может быть, в данном конкретном запросе нужно выдать чуть больше информации, чем кажется достаточным. Но зато это сделает последующую работу удобнее и приятнее на клиенте. Помогая в таких мелочах, вы надолго запомнитесь. И потом будут вспоминать с теплотой всю их профессиональную жизнь.

В этот же пункт хочется отнести отладочную информацию. Если вы сделали запрос для получения списка комментариев, то озаботьтесь, чтобы эти комментарии там были. Вам накопипастить однотипных данных — дело одной минуты, а для напарника из мобильного отдела — это целый выдох облегчения.

Стабильность

Просто архиважный пункт на который хочется отдельно обратить внимание. Всегда проверяйте свое API, а еще лучше — пусть тесты делают это за вас. Каждый баг на бэкенде равен десяти на клиенте. Ведь между сервером и пользователем находится множество уровней абстракций, которые надо исключить перед тем, как винить сервер.

Каждый баг тратит время пользователя, тестировщика, мобильного разработчика и только потом — вас. На вас возложена наибольшая ответственность, и ваши ошибки обходятся компании дороже всего.

В качестве бонуса хочется добавить, что здорово, когда есть pretty print, хотя бы на время разработки. Бывает, что надо разобраться с тем, что пришло от сервера, не заглядывая в документацию.

А что приятнее читать, такое:

image loader

image loader

Разница, мне кажется, на лицо.
Главное, не забудьте отключить Pretty Print на боевом сервере, поскольку ресурсов он жрет как не в себя.

Заключение

Хочется всем просто сказать, что правило на самом деле одно и довольно простое — не заставляйте коллег скрежетать зубами от вашей работы.

В следующий раз планирую рассказать о том, как мы переезжали на Go и избавились от огромного куска бизнес логики на клиенте, сократив бинарник приложения больше, чем на треть.

Источник

Понравилась статья? Поделить с друзьями:

А вот еще кое-что интересное для вас:

  • Для чего нужен дубликаты госномера авто. 10 причин сделать себе его
  • Разновидности похоронных бюро и сферы их деятельности
  • Как быстро изучить английский язык? Плюсы и минусы онлайн школы по изучения языков
  • Эффективное создание текста вакансии: ключевые шаги и рекомендации
  • Размещение серверов в дата-центрах: преимущества и недостатки

  • 0 0 голоса
    Article Rating
    Подписаться
    Уведомить о
    0 Комментарий
    Старые
    Новые Популярные