Как стать автором
Обновить
297.39
Конференции Олега Бунина (Онтико)
Профессиональные конференции для IT-разработчиков

Flutter, руководство для начинающих

Время на прочтение 15 мин
Количество просмотров 31K
На дворе середина 2019 года, кроссплатформа плотно вошла в жизнь стартапов по всему миру, но все чаще в ее сторону смотрят и команды аутсорс-разработки, и клиенты, которые делают ставку на снижение затрат. Кто-то делает ставку на React Native, кто-то исследует возможности Kotlin Multiplatform, а новый гость подкаста AppsCast Евгений Сатуров saturovv последние полгода активно разрабатывает на Flutter, следит за обновлениями фреймворка и продвигает технологию в массы. Максимум полезных ссылок и советов для начинающего Flutter-разработчика: от гайдлайнов до репозиторием с примерами реализации архитектуры — в разговоре с Евгением.



AppsCast — подкаст, посвященный мобильной разработке и выходящий при поддержке конференции AppsConf. Каждые две недели новый гость, с которым мы с Даниилом Поповым (int02h) обсуждаем технологии, лучшие практики, жизнь разработчиков, а так же холиварим и делимся опытом.

Алексей Кудрявцев: Всем привет, сегодня у нас в гостях Женя Сатуров, разработчик в компании Surf и ведущий Flutter Dev Podcast. Женя, расскажи чуть подробнее о себе.

Евгений Сатуров: Всю сознательную жизнь я был андроид-разработчиком, но уже не так уверен в своем безоблачном будущем как раньше. Последние полгода мы в компании активно интересуемся Flutter, пробуем его интегрировать в производственный процесс разработки. 

Алексей Кудрявцев: Как ты из андроид-разработки вдруг пересел на Flutter?

Евгений Сатуров: Сложный вопрос. Я сам иногда его себе задаю. Про Flutter я совершенно случайно услышал от самого главного его пропагандиста в стране Звиада Кардавы на девфесте в Новосибирске. Мы поизучали и решили попробовать, уже полгода пишем на Flutter, подружились с декларативным UI. 

Flutter цепляет


Даниил Попов: Что вас привлекло в Flutter? 

Евгений Сатуров: У Flutter низкий порог вхождения, в нем отсутствуют понятия Activity и Fragment, а жизненный цикл элементарен и состоит из трех этапов. Всё в Flutter — это виджет: само приложение, которое мы привыкли представлять в виде application class, любой блок — это виджет, в который вложен другой виджет. Все экраны строятся исключительно композицией. Структура Flutter-приложения предполагает более упорядоченную архитектуру, более стройный data flow. 

Немного ломается голова, когда ты пытаешься после Андроид-разработки написать в Flutter кастомную вьюшку. Там так не работает. Ты должен вставлять вьюшки друг в друга и получать более сложные, комбинированные элементы. 

На Google I/O представили Jetpack Compose для Android, позволяющий писать UI декларативно. Идея полностью позаимствована из Flutter, даже названия переиспользованы. 

Алексей Кудрявцев: Есть такая теория заговора, что компания Google подготавливает Андроид-разработчиков к Flutter. 

Евгений Сатуров: Я могу тебе еще одну теорию заговора подкинуть — компания Apple готовит своих разработчиков к Flutter. 

Отличие Flutter от других кроссплатформенных решений


Алексей Кудрявцев: Все, что ты рассказал, похоже на характеристику React Native или продуктов Xamarin. В чем отличие?

Евгений Сатуров: Написать хорошее производительное приложение на React Native сложно из-за технических решений, которые лежат в его основе. Взаимодействие с платформой возможно только через JavaScript Bridge. В процессе это операции значительно проседает производительность, что критично при отрисовке UI.

Flutter же справился с проблемой производительности дорогой ценой — разработчикам фреймворка пришлось написать свои паки виджетов на Dart (на нем же написан и Flutter). При отрисовке не просто исчезла проблема проседания по fps, но и команда Flutter уверяет, что в теории можно достичь не только 60fps, но и 120fps на девайcах, которые это поддерживают.

Многие муссируют тему, почему фреймворк не поддерживает Kotlin и появится ли он, но разработчики Flutter говорят, что такой задачи у них нет, но может быть это сделает кто-то ещё, вроде JetBrains. 

Даниил Попов: Это же очевидно, есть Kotlin Multiplatform. Нужно сделать часть компилятора, который компилит Kotlin в Dart, и будет профит.

Алексей Кудрявцев: Ты так говоришь, как будто это как пальцами щелкнуть. 

Евгений Сатуров: Основная часть работы уже сделана. На Google I/O рассказали про оптимизацию Garbage Collector в Kotlin, которая позволит утилизировать тонны объектов в миллисекунду. Это важно, так как при рендеринге UI тысячи граф виджетов каждые 16 миллисекунд генерятся заново и их надо срочно утилизировать, чтобы память не забивалась. Раньше Kotlin так не умел в отличии от Dart, теперь же ничего не мешает затащить его в Flutter. 

Алексей Кудрявцев: Первая часть процесса утилизации — аллоцирование множества объектов. Нет проседает ли производительность на этом этапе?

Евгений Сатуров: Сами по себе объекты легковесны. Если копнуть глубже, то Flutter-приложение — это огромный recyclerview, список с переиспользуемыми элементами, которые рендерятся только при изменении данных, стоящих за ними. При этом виджеты, которые пересоздаются каждые 16 миллисекунд, не имеют ничего общего с виджетами, которые есть в Android и ответственны за отрисовку себя на канве. 

Тут виджет — это Data Class, в котором есть данные, описывающие этот виджет. Виджет, который рисуется на канве, существует в единственном экземпляре в течение всего жизненного цикла. Полностью пересоздается только его обёртка с данными. Это позволяет работать быстро, не забивая память.

Flutter — это полностью открытый open source проект.

Это не тот open source, который раз в квартал зеркалируется из закрытого репозитория в публичный гитхаб. Это настоящий open source, где разработка ведется прямо в открытом репозитории на гитхабе. Ты можешь внести любые изменения в виджеты, написать свой widget pack и использовать его в своей компании. 

Алексей Кудрявцев: Если они сделали полностью свои виджеты, то как обстоят дела с анимациями и переходами между экранами, например, на iOS?

Евгений Сатуров: Важнее вопрос, как вообще заставить приложение выглядеть привычно для пользователей данной платформы. Из коробки это не происходит практически ни в каком случае. Если ты пишешь приложение на Dart и используешь какой-то widget pack, то при запуске, приложение на Android и на iOS будет выглядеть одинаково.

Для того, чтобы получить нативный опыт на платформе, нужно вручную произвести проверку платформы на запущенном приложении. Если это iOS, то дальше используешь виджеты из Cupertino Pack, если это Android — виджеты из Material Pack. Тоже самое с переходами: можно активировать swipe back для iOS, а на Android останется нативная навигация.

Алексей Кудрявцев: Как идет переключение между паками? Тебе реально нужно написать «if iOS, юзай вот это», «if Android, то вот это»?

Евгений Сатуров: Да, именно так, прямо дословно. На Google I/O я спрашивал Flutter-разработчиков, почему не сделать переключение из коробки, зашить внутрь проверку на платформу, которая в данный момент работает, и автоматическую постановку виджетов. Ведь люди ожидают, что кроссплатформенный, UI-фреймворк будет сам все это делать. Они ответили, что хотят дать пользователям свободу выбора того, как приложение должно выглядеть. 

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

Про внутренности Flutter


Даниил Попов: Получается, у Flutter свой рендеровский движок, который самостоятельно рисует все виджеты?

Евгений Сатуров: Да, но «свой» — не совсем корректное слово. Это Skia, известный движок, который давно работает и в Chrome, и в Firefox, и в ряде других браузеров. 

На самом деле, команда Flutter — это отпочковавшаяся команда Chromium.

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

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

Алексей Кудрявцев: А что еще под капотом у Flutter? Можешь рассказать из чего еще он состоит, где там оптимизации, что позволяет добиться такой производительности?

Евгений Сатуров: Если говорить про архитектуру самой платформы, то нужно выделить два основных слоя. Базовый написан «на плюсах». К нему относится Skia — графический движок, который рисует всю эту красоту, текстовый движок, который полностью позаимствован из Андроида, и Dart VM. Второй слой написан полностью на Dart. Он содержит все widget packs: анимации, обработку жестов, Foundation Pack со всякой всячиной. За счет того, что все написано на Dart, обеспечивается неплохая производительность. 

Сразу вставлю пять копеек: если после этого выпуска вы решите попробовать сделать что-то на Flutter, установите плагин на Android Studio, соберете свое первое приложение и скажете, что вас жестоко обманули, так как все тормозит, то будете правы. Это происходит при дебажной сборке, которая и правда тормозит, анимации лагают, списки еле скроллятся, а приложение весит около 60Мб. Дело в том, что в дебажную версию вы тянете огромный кусок Dart VM. Это плата за возможность перекомпиляции на лету. Когда соберете релизную сборку, все эти мегабайты как ветром сдует, приложение станет намного быстрее работать, без проседания fps вообще. Это ремарка очень важна, чтобы не напугать начинающих Flutter-разработчиков.

Dart VM — это отдельная тема. Примечательно, что основным контрибьютером является наш российский разработчик Слава Егоров, с которым записали выпуск для Flutter Dev Podcast. Dart VM позволяет быстро обновлять код при внесении изменений. Называется это Hot Reload — вы вносите изменения в код, нажимаете кнопочку, и через секунду изменения уже видны на девайсе. Это очень ускоряет разработку и создает благостную атмосферу в команде.

Алексей Кудрявцев: Мне кажется, важно, что во время Hot reload ты остаешься в состоянии потока. Это кайфово на маленьких проектах. А вот когда проект большой, ты одну вьюшку передвинул и ждешь десять минут. 

Евгений Сатуров: Да, слышал жалобы айосников, что сборка до 10-15 минут может доходить.

Одной из очень сильных сторон Flutter является туллинг.

Я не знаю, как в iOS, но в Андроиде туллинг — это боль. Каждое обновление Android Studio что-то ломает, да и сама она работает медленно, требует нереальных ресурсов, самого последнего процессора и гору оперативки. Flutter сразу же предлагает легковесный туллинг. Необязательно работать в Android Studio, можно скачать VS Code, установить на него плагин, и этого будет достаточно для разработки. Сразу скажу, что для полноценной работы с Flutter вам все-таки понадобится техника от Apple, так как иначе вы не сможете проверить вашу сборку на iPhone.

Даниил Попов: Ты сказал, что Flutter развивается семимильными шагами, но не будет ли из-за этого проблем с обратной совместимостью? Например, я убедил бизнес сделать приложение на Flutter, мы написали, отладили, и тут выходит новая версия Flutter или Dart, и у нас не компилится код, все разваливается. Я сел в лужу перед заказчиком. 

Евгений Сатуров: Такое вполне может произойти. Есть такая интересная вещь, как UX-опросы, которые проводит команда Flutter.

В последнем опросе был вопрос: «Готовы ли вы к неподдерживаемым изменениям без обратной совместимости во имя простоты и чистоты фреймворка?» Более 80% ответили, что готовы.

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

С чего начать?


Даниил Попов: С чего начать, если решил попробовать для себя Flutter? Я ради интереса открыл кодлабы Гугла и там есть конкретные примеры, как с Java пересесть на Dart. Есть ли такое для iOS-разработчиков?

Евгений Сатуров: Команда Flutter-разработки выпустила серию статей, как мигрировать представителям различных профилей. Есть Flutter for Android developers, Flutter for iOS developers. Я открываю и вижу там, например, «What is the equivalent for UI view in Flutter?» или «Where is my Storyboard?». На все эти вопросы даются ответы. Советую начать с этих статей, они все есть в документации Flutter. 

Еще нужно затронуть тему, как подружиться с Dart как с языком разработки для Flutter. Для этого есть Dart Language Tour. Там раскрыты все основные концепции Dart. Но, положа руку на сердце, некоторые вещи отличаются чуть более существенно (особенно, если копнуть глубже), некоторых вещей не хватает, например, перегрузки функции, там до сих пор нужно ставить точку с запятой в конце строки…

Алексей Кудрявцев: Есть ли какая-то документация? На кого подписаться в твиттере? Блоги на Медиуме?

Евгений Сатуров: Конечно, сейчас очень много информации. Есть сайт Flutter с подробными инструкциями, как настроить среду разработки, что загрузить, какие SDK, плагины установить. Есть кодлабы, они достаточно простые и в меру информативные, так как не дают и сотой части того, что представляет собой Flutter. Но для начала, чтобы в принципе понять концепцию, кодлабы подойдут. Не рекомендую проходить все, есть достаточно заковыристые, в которых идет интеграция Google Maps в приложение. Это тоже интересно, но больши возни с ключами, чем реальной разработки. Достаточно пройти первые три. Есть и более функциональные примеры — клоны реальных приложений Whatsapp, Instagram с допущениями.

Алексей Кудрявцев: Это круто, вкупе с инструкцией по миграции.

Евгений Сатуров: Да, можно посмотреть, как в реальности люди делают те вещи, которые мы привыкли видеть в приложениях. Это помогает начать.
Помимо этого есть куча платных курсов на Udemy, но я сомневаюсь, что это сильно нужно. Я посмотрел, из чего они состоят, и всю эту информацию (может, не так структурировано) можно найти абсолютно бесплатно. 

Еще рекомендую сайт https://itsallwidgets.com/, который позволяет (неважно, собираетесь вы что-то разрабатывать на Flutter или нет) прямо сейчас установить на свой девайс showcase-приложения и посмотреть, как они работают. Есть приложение History of Everything, которое было написано за три месяца. Это абсолютный фан, сумасшедшие анимации. Там гигантский таймлайн, который можно зумить, и на нем начинают появляться различные эпизоды жизни человечества. У каждого своя кастомная анимация. Все сделано на Dart без нативных библиотек. На этом сайте можно понять, где граница возможностей Flutter: есть игры, написанные исключительно на Dart, отрисованные на Skia, есть и обычные приложения. 

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

И можно еще использовать несколько репозиториев на GitHub, созданных энтузиастами. Все они называются одинаково — Awesome Flutter. Это сборники со всеми сэмплами, библиотеками, статьями.

По поводу информационных ресурсов. Я рекомендую подписаться на официальный youtube-канал Flutter. Есть шоу, которые выходят на регулярной основе. Flutter Widget of the week — каждую неделю подробный рассказ об отдельном виджете, основные кейсы применения и возможности. The Boring Flutter Development Show — интересный формат шоу, которое идет целый час и выходит без монтажа. Все это время участники кодят. Такое ощущение, что делают это без особой подготовки, так как постоянно вылезают ошибки, они пытаются что-то сделать, тупят, не понимают, что происходит. Смотреть за этим поразительно интересно.

Если посмотреть все эти шоу (их было относительно немного), то можно стать совершенно другим человеком и поверить, что пишешь на Flutter всю свою жизнь. Они поднимают интересные темы, проблемы, с которыми люди сталкиваются, и проходят путь в поисках решения. В нем снимаются все главные звезды Flutter: Emily Fortuna, Andrew Brogdon. На них можно подписаться в твиттере, они активно постят. Обязательно стоит подписаться на Brian Egan, у него есть репозиторий с 16 сэмплами с разными архитектурными паттернами. Это незаменимая вещь, когда ты уже пишешь на Flutter и в начале проекта нужно выбрать архитектуру, которой ты будешь пользоваться. Ты просто идешь к Брайану, и он уже все за тебя приготовил. Эти ребята двигают индустрию Flutter-разработки вперед. 

Flutter в продакшене 


Алексей Кудрявцев: Допустим, я — технический директор компании. Где мне искать Flutter-разработчиков?

Евгений Сатуров: Все как у людей: есть открытые чаты в телеграме с достаточным количеством людей, которые уже пишут на Flutter. Но я бы сказал, что не надо искать именно Dart-разработчика. Язык — это инструмент и его незнание препятствием для найма не является. Другой вопрос, что Flutter — это не только код на Dart. Вам все равно потребуется обращаться к платформе. И вот тут вопрос: как быстро андроидщики разберутся, как это делать на iOS, и наоборот, как быстро разберется ваш веб-разработчик, как это делать и там, и там. 

На текущий момент, наиболее сбалансированная команда Flutter-разработки состоит из Android и iOS-разработчиков.

Другое дело, что этого не всегда удается достичь, так как айосники до сих пор настороженно относятся к Flutter.

Алексей Кудрявцев: Как Flutter используется в продакшене? Как много проектов вы на нем написали как студия? И насколько это просто заходит?

Даниил Попов: И кто кроме вас еще на нем пишет?

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

Для них Flutter — это «палочка-выручалочка», как и любая кроссплатформа, просто Flutter дает по-настоящему классный результат.

И уже есть заказчики, которые приходят и говорят: — Нам нужно только на Flutter. В последнее время это случается все чаще.

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

По поводу того, кто еще использует Flutter. Недавно я узнал, что определенные проекты (конечно, не флагманские) пишут в Одноклассниках, в Grab, такси в юго-восточной Азии, которых недавно купил Uber. 

Общая тенденция такова: это хорошо подходит для прототипирования, подходит для экспериментов, потому что есть интероп с нативом.

Можно быстро написать экран на Flutter в нативном iOS или Android-приложении, выкатить A\B тесты и посмотреть, работает ли гипотеза и стоит ли тратить на нее время, а потом уже сделать качественную нативную разработку с тем, что пользователям действительно понравилось. 

Еще подходит для реальных продакшн-проектов, если они небольшие и простые по концепции (скачиваете json, показываете списки, взаимодействуете с пользователем).

В каких случаях Flutter не стоит использовать? Если приложение крутится вокруг платформенной фичи, например, навороченной фотокамеры, либо постоянно работает с сенсорами, например, гироскопом. Тогда использование Flutter бессмысленно — у вас будет относительно простой UI, который вы переиспользуете между платформами, но будет куча нативного кода, который вы напишите дважды. 

Про проблемы


Алексей Кудрявцев: Какие есть сейчас проблемы?

Евгений Сатуров: Например, в iOS есть какие-то низкоуровневые оптимизации рендеринга, но во Flutter они работать не будут, потому что там свой графический движок. Проблема ли это?

Алексей Кудрявцев: В iOS все, что ты рендеришь, превращается в битмапу, которая отправляется в отдельный процесс на рендер-сервер, а он их складывает и рендерит на GPU. То, что происходит в iOS-приложении — это тупо CPU. Получается, что, если ты пишешь приложение на Flutter, весь твой рендеринг будет отрабатывать на CPU, и только битмапы будут отправляться на GPU. Где-то тут может потеряться производительность. Хотя можно напрямую использовать opengl в приложении. Если Flutter использует именно так, то тогда все хорошо. 

Евгений Сатуров: Есть мелкие проблемы со сборкой. Как я говорил, есть слой Flutter Engine, который компилируется и подключается как эндикей либа. Есть досадная неприятность, которую вылечить не удалось: когда мы собираем APK под разные конфигурации архитектуры процессора, эта нативная библиотека не пакуется в сборку для 64-битной системы. Нужно танцевать с бубном, собирать по-особенному. 

Есть и странные неприятности (неясные андроидщикам), когда для того, чтобы сборка iOS-приложения прошла успешно, нужно запустить X-Code (хотя бы раз запустить и закрыть). 

Есть некоторые косяки с документацией. Сейчас индекс удовлетворенности разработчиков Cupertino Widgets в районе 70%. В нашей практике был кейс переопределения view controller — это возможно сделать, но в документации не описано. Таких багов документации все меньше — видно, что она написана с любовью.

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

Будущее Flutter


Алексей Кудрявцев: Какие планы у Flutter, есть ли roadmap?

Евгений Сатуров: На самом деле, план развития впечатляющий. На Google I/O представили Flutter for Web, который позволяет Flutter-приложение превращать в web-приложение практически в два клика. Вся работа по отрисовке ложится на Flutter Engine. Подробностей пока нет, но можно собрать несложный прототип. Один из главных пунктов roadmap — полноценный выход в веб. Точной даты нет, но есть вероятность, что это случится до конца календарного года.

Второй пункт, более отдаленный во времени, — это выход на десктопы.

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

Теоретически, Flutter-приложения уже работают на десктопах. Есть репозиторий с showcase с официальной конференции Flutter Live, прошедшей впервые в декабре прошлого года в Лондоне. Один из докладчиков подготовил презентацию в формате flutter-приложения: все элементы на слайдах были виджетами. Это стало известно, только когда он закончил презентацию и свернул приложение, Скорее всего до конца года выйдет что-то вроде developer preview, но пока поддержка десктопов неофициальная. 

Это основные вехи, которые ждут Flutter в будущем. Есть много мелких доработок, но они неинтересны тем, кто не в контексте.

В Release Notes можно увидеть полный перечень коммитов, которые были сделаны для релиза. Можно пройти по коммитам, какие изменения в релизе произошли, можно посмотреть на все ближайшие этапы релизного цикла, все задачи, которые будут закрыты до того, как релиз выйдет в свет. Вся информация открыта и доступна в репозитории, там найдутся все ответы, а если чего-то не найдете, то пишите issues и вам быстро ответят ребята из команды Flutter. 

Выводы


Даниил Попов: Я сделал выводы. Команда Flutter серьезно относится к своему продукту и делает гайды для миграции с других платформ, сэмплы, чтобы можно было пощупать. Когда я писал на Xamarin, мне этого не хватало. Похвально, что Flutter гордятся своим творением и стараются на него всех пересадить. 

Лично у меня после прохождения кодлабов, Dart сложности не вызвал. Интереснее было бы мнение Алексея, но он кодлабы не проходил. По словам Жени получается, что Dart — не такая страшная штука, и за неделю его легко выучить. Если мне потребуется сделать игру или нагруженное UI приложение, скорее всего я попробую это сделать на Flutter.

Евгений Сатуров: Подытожить можно цитатой известного Android-разработчика, который ни разу не писал на Flutter: «Сейчас 2019 год, и я сильно удивлюсь, если какой-то стартап сегодня начнет писать нативное приложение, когда есть Flutter».

Достаточно радикально, но кто знает, в каком будущем мы проснемся завтра.

Если вы уже пишите на Flutter или успешно освоили в продакшене другие кроссплатформенные фреймворки, то скорее подавайте свой доклад на осеннюю AppsConf.
Теги:
Хабы:
Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку
+30
Комментарии 9
Комментарии Комментарии 9

Публикации

Информация

Сайт
www.ontico.ru
Дата регистрации
Дата основания
Численность
31–50 человек
Местоположение
Россия