Русский
Русский
English
Статистика
Реклама

Гайд

Шифрование диска с помощью VeraCrypt на Windows для неискушенных пользователей

19.05.2021 18:19:31 | Автор: admin

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

Сегодня я расскажу, как мы будем выстраивать линию обороны для защиты данных на устройстве с Windows.

Этот материал вдохновлен статьёй Олега Афонина "Как укрепить Веру. Делаем шифрованные контейнеры VeraCrypt неприступными". Если вы хотите углубиться в тему ИБ, то можете задонатить и подписаться на него.

Важно

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

Узнать заранее поддерживает ли ваш данную технологию можно на официальном сайте вендора. Например Intel:

Или проверить можно на сторонних сайтах, пример здесь.

Также можно проверить наличие данной технологии с помощью самой программы VeraCrypt. После установки зайдите в Сервис > Тест скорости... Нас интересует показатель в правом нижнем углу.

Показатель "Да" будет означать наличие ускорения, показатель "Н/П" ее отсутствие.

Установка

Скачивайте с официального сайта. Заходим на вкладку Downloads, выбираем версию (Installer for) для своей операционной системы, я выбрал Windows.

Далее открываем скачанный файл и начинаем установку. Тут все просто, подтверждаем все пункты пока не установим программу.

VeraCrypt в конце процедуры может пожаловаться на функцию быстрого запуска ОС. В этом случае, отключаем ее:

Перезагружаем компьютер.

Эксплуатация

После перезагрузки открываем VeraCrypt и создаем новый том. В открывшемся мастере создания томов мы делаем следующее:

  1. Выбираем "Зашифровать раздел или весь диск с системой"

  2. Тип шифрования обычный

  3. Область шифрования на выбор два варианта, "Зашифровать системный раздел Windows" или "Зашифровать весь диск". Если у вас доступен второй, то выбираем его.

  4. Число операционных систем "Одиночная загрузка", если у вас на машине только одна ОС.

Шифрование

И тут мы переходим к самому интересному, методам шифрования.

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

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

Лично я выберу Whirlpool.

Внимание, ни при каких условиях не выбирайте Streebog, данный алгоритм содержит дыру в безопасности (разработан Центром защиты информации и специальной связи ФСБ России с участием ОАО "ИнфоТеКС")

Далее идет выбор пароля. Подробнее о том из чего состоит хороший пароль вы можете найти в нашей статье. Важный совет: придумайте уникальный, который еще нигде не использовали. Корпорации хранят даже ваши старые логины-пароли на серверах. Один запрос "правоохранительных" органов и все ваши данные авторизации окажутся у них в руках.

Ставим галочку "Использовать PIM" и идем дальше.

PIM (Personal Iterations Multiplier)

Нас попросят ввести PIM, там же приводится описание данного термина. Чем больше тем безопаснее, но вместе с тем медленнее. Подождать лишние секунды при загрузке несложно, а нам полезнее.

Если вам интересны конкретные цифры, то ниже будут представлены картинки с тестами:

Настройки PIM по умолчанию (485):

500:

1000:

Чтобы у вас сложилось понимание почему мы должны его использовать, представим, что даже если злоумышленник знает пароль, ему придется перебирать все вариации PIM, то есть (1,2,3 ... n) чтобы расшифровать диск. И если не знать точного числа, то можно застрять надолго, что играет нам на руку.

Но даже при высоком значении стоит выбирать номер очень аккуратно. То есть комбинации 1234 / 2012 / 1939 / год рождения ребенка / поступления / совершеннолетия сразу отбрасываем. Число никак не должно быть связано с вами, и при этом не быть слишком тривиальным.

Итак, PIM должен быть большим, анонимным и неординарным. Например 1709.

Нам предложат сгенерировать дополнительные ключи, нам они не требуются, нажимаем далее.

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

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

Пре-тест

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

Для особых случаев в ходе пре-теста (например если вы резко забыли пароль и PIM придуманные 5 минут назад) существует механизм обхода ввода пароля. Нажимаем на ESC и загружаемся в Windows. VeraCrypt уведомит нас что пре-тест провалился и предложит пройти его снова. Мы от предложения отказываемся.

Заходим в Система > Окончательно расшифровать системный раздел/диск. Убеждаемся что ничего не зашифровано и повторяем весь процесс шифрования с начала.

В случае успешного входа нас встретит VeraCrypt с оповещением, что пре-тест выполнен успешно, и нам остается лишь зашифровать диск, что мы и делаем, нажав Encrypt, после чего ждем около 15 минут.

Вы сделали это. Вы - Молодец.

Дальше ответы на вопросы:

За раз шифруется только 1 диск ?

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

Разве увеличение длины пароля на два-три знака из расширенного набора символов не даст схожий или даже лучший результат чем PIM?

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

Подробнее..

Разбираем тестовое задание на должность фронтенд-разработчика на Vue.js

22.09.2020 20:11:13 | Автор: admin

Первое правило тестовых заданий - никогда не делайте тестовые задания!

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

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

Для ознакомления с заданием, которое я получил, прошу под спойлер:

Техническое задание:

Средствами Vue.js реализуйте небольшое SPA приложение для заметок.

Каждая заметка имеет название и список задач (todo list), далее - Todo. Каждый пункт Todo состоит из чекбокса и относящейся к нему текстовой подписи.

Приложение состоит всего из 2х страниц.

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

  • перейти к созданию новой заметки

  • перейти к изменению

  • удалить (необходимо подтверждение)

Страница изменения заметки позволяет определенную заметку отредактировать, отметить пункты Todo, а после сохранить изменения. Действия с заметкой:

  • сохранить изменения

  • отменить редактирование (необходимо подтверждение)

  • удалить (необходимо подтверждение)

  • отменить внесенное изменение

  • повторить отмененное изменение Действия с пунктами Todo:

  • добавить

  • удалить

  • отредактировать текст

  • отметить как выполненный

Требования к функционалу:

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

  • Подтверждение действий (удалить заметку) выполняется с помощью диалогового окна.

  • Интерфейс должен отвечать требованиям usability.

  • После перезагрузки страницы состояние списка заметок должно сохраняться.

  • Можно пренебречь несоответствием редактирования текста с помощью кнопок отменить/повторить и аналогичным действиям с помощью комбинацияй клавиш (Ctrl+Z, Command+Z, etc.).

Технические требования:

  • Диалоговые окна должны быть реализованы без использования "alert", "prompt" и "confirm".

  • В качестве языка разработки допускается использовать JavaScript или TypeScript.

  • В качестве сборщика, если это необходимо, используйте Webpack.

  • Верстка должна быть выполнена без использования UI библиотек (например Vuetify).

  • Адаптивность не обязательна, но приветствуется.

  • Логика приложения должна быть разбита на разумное количество самодостаточных Vue-компонентов.

Особое внимание стоит обратить на следующие моменты:

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

  • Читабельность и наличие элементарной архитектуры.

  • Чистота и оформление кода не менее важный фактор. Код должен быть написан в едином стиле (желательно в рекомендуемом для конкретного языка). Также к чистоте относятся отсутствие копипаста и дублирования логики.

Тестовое задание должно быть предоставлено в следующем виде:

  • Ссылка на публичный репозиторий (GitHub, BitBucket, GitLab) с исходным кодом.

  • Ссылка на сайт для тестирования функционала. Или Dockerfile и docker-compose.yaml, позволяющие развернуть локально командой docker-compose up работоспособную копию сайта.ехническое заданиеехническое заданиеехническое задание

Вот что у меня в итоге получилось.

Надо сразу предупредить, что особым архитектурным изяществом мое решение не обладает. Этому есть свои причины. С одной стороны, конечно, хочется впечатлить работодателя, с другой стороны, тестовое задание (далее просто ТЗ) делается в ущерб времени для личной жизни, поиска других предложений, подготовки к собеседованию и т.д.

Разберем по пунктам задание и возможные способы его решения:

Средствами Vue.js реализуйте небольшое SPA приложение для заметок. Тут все просто: используем Vue CLI для создания проекта.

Каждая заметка имеет название и список задач todo list, (далее - Todo). Каждый пункт Todo состоит из чекбокса и относящейся к нему текстовой подписи. - А вот и первая сложность, у нас будет два уровня абстракции: множество заметок и множество дел, которые составляют заметку.

Приложение состоит всего из 2х страниц. Тут возник вопрос - использовать ли Vue Router? Это же всего две страницы. Дальше из задания мы узнаем, что первая страница используется для отображения списка заметок, а вторая - для редактирования отдельной заметки. Конечно, можно переключать компоненты условным оператором, но раутер даст возможность перехода на сгенерированные страницы для каждой заметки. Но это уже больше двух страниц, или сгенерированные страницы считаются за одну, так как они по одному шаблону сделаны? После недолгих колебаний я решил все-таки его использовать.

Дальше следуют подробности по каждой странице, обратим внимание на два пункта:

  • отменить внесенное изменение

  • повторить отмененное изменение

Это про редактирование заметки. Решение тут же пришло мне в голову: создать массив, который запоминал бы историю изменений заметки, каждый элемент массива содержал бы состояние заметки до следующего изменения. С помощью кнопок можно было бы "скакать" по истории, и реактивность Vue нам очень в этом помогает.

Do и RedoDo и Redo
  • Все действия на сайте должны происходить без перезагрузки страницы. Это означает стандартное SPA, мы и так используем Vue CLI.

  • Подтверждение действий (удалить заметку) выполняется с помощью диалогового окна.

  • Диалоговые окна должны быть реализованы без использования "alert", "prompt" и "confirm".

    Диалоговое окно должно создавать Promise, который зависит от решения юзера. Желательно, чтобы решение было переиспользуемым для всех наших случаев. Помучавшись над решением, я пришел к выводу, что лучше использовать готовое решение, к тому же запретов на пакеты не было. Я использовал vue-modal-dialogs - очень удобная библиотека, рекомендую. Надеюсь её перепишут для Vue 3.

  • Интерфейс должен отвечать требованиям usability. Другими словами, он должен быть удобным. Лучше бы написали конкретные требования, так не очень понятно.

  • После перезагрузки страницы состояние списка заметок должно сохраняться. - Так как серверной части у нашего приложения не планируется, заметки следует сохранять на стороне клиента, для этого есть два решения Cookie и localStorage. Выбираем кому что ближе. Я выбрал localStorage. К тому же я решил не использовать Vuex, а вместо него использовать локальное хранилище, как единыйисточник истины. Для небольшого приложения без бэка это выглядит разумным решением, экономящем время, в других случаях я не рекомендовал бы так делать.

  • В качестве языка разработки допускается использовать JavaScript или TypeScript. - а разве есть еще варианты? Честно говоря, ТЗ оставляет ощущение, что тот кто его составлял плохо знаком с Vue. TypeScript на Vue 2 спорно применять, слабая поддержка. Посмотрим, что будет на Vue 3.

    Важное замечание для тех, кто захочет воссоздать его с нуля на новой версии! Мой проект написан на Vue 2, обещали, что старый синтаксис будет работать, но все же.

  • В качестве сборщика, если это необходимо, используйте Webpack. Vue CLI это и есть Webpack, настроенный для удобства создания SPA на Vue.js

  • Верстка должна быть выполнена без использования UI библиотек (например Vuetify) - это минус. Для того чтобы "оживить" приложение, я использовал Material Icons от Гугла, вместо кнопок. Не знаю, оценил ли заказчик, он так и не ответил.

  • Адаптивность не обязательна, но приветствуется. - flexbox в помощь.

  • Логика приложения должна быть разбита на разумное количество самодостаточных Vue-компонентов. - у меня вышло семь: 2 на страницы, еще заметка, тудушка, заголовок заметки, кнопка-иконка и диалоговое окно.

    Остальные пункты менее важны.

Еще из вкусностей:

Я использовал пакет v-click-outside. Название говорит само за себя. Он добавляет директиву, которая срабатывает при клике вне элемента. Можно было написать самому, но я решил не изобретать велосипед. Использовал для отмены редактирования тудушки, если пользователь кликнул где-то еще. Это в задании не было, включим это в юзабилити.

Еще мне пришла в голову такая мысль: а что делать, если юзер захочет покинуть страницу редактирования заметки? Куда повесить вызов диалогового окна: на историю браузера, на кнопки меню? Есть элегантное решение. Vue-Router добавляет хуки жизненного цикла в компонент. Хук beforeRouteLeave поможет нам во всех ситуациях когда пользователь пытается покинуть страницу. Пусть наш хук вызывает модальное окно. Только не забыть сделать его асинхронным, ведь окно возвращает промис. Например, вот так:

  async beforeRouteLeave (to, from, next) {    if (await confirm('Do you realy want to leave this page?',       'All unsaved changes will be lost.')) {        this.clearNote()        next()      } else{        next(from)      }  }

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

Если возникли вопросы и замечания, прошу в комментарии или личку.

Подробнее..

Создание нейронной сети Хопфилда на JavaScript

05.06.2021 18:10:05 | Автор: admin

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

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

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

Исходникина Github и демо.

Дляреализациипонадобится:

  • Браузер

  • Базовоепониманиенейросетей

  • БазовыезнанияJavaScript/HTML

Немноготеории

Нейронная сеть Хопфилда (англ. Hopfield network) полносвязная нейронная сеть ссимметричной матрицей связей. Такая сеть может быть использована для организации ассоциативной памяти, как фильтр, атакже для решения некоторых задач оптимизации.

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

Структурная схема нейросети ХопфилдаСтруктурная схема нейросети Хопфилда

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

Алгоритм работы сети:

  1. Инициализация
    Веса нейронов устанавливаются по следующей формуле:

    w_{ij}=\left\{\begin{matrix} \sum_{k=1}^{m} x_{i}^{k} * x_{j}^{k} & i \neq j \\0, & i=j \end{matrix}\right.

    где m количество образов
    x_{i}^{k}, x_{j}^{k} i - ый и j - ый элементы вектора k - ого образца.

  2. Навходы сети подается неизвестный сигнал. Фактически его ввод осуществляется непосредственной установкой значений выходов:
    y_{j}(0) = x_{j}

  3. Рассчитывается выход сети (новое состояние нейронов иновые значения выходов):

    y_{j}(t+1)=f\left ( \sum_{i=1}^{n} w_{ij}*y_{i}(t)\right )

    где f пороговая активационная функция собластью значений [-1; 1];
    t номер итерации;
    j = 1...n; n количество входов инейронов.

  4. Проверка изменения выходных значений запоследнюю итерацию. Если выходы изменились переход кпункту3, иначе, если выходы стабилизировались, завершение функционирования. При этом выходной вектор представляет собой образец, наилучшим образом сочетающийся свходными данными.

Разработка

Визуальная часть

Для начала посмотрим как работает итоговый проект.

Демонстрация работы программыДемонстрация работы программы

Онсостоит издвух элементов Canvas итрех кнопок. Это простейший HTML иCSS код, ненуждающийся впояснении (можете скопировать сгитхаба).

Левый элемент Canvas нужен для рисования изображений, которые затем будут использованы для обучения (кнопка Запомнить) или распознавания нейросети. Направом элементе отображается результат распознавания сигнала, находящегося наданный момент налевом Canvas (вданном случае сеть вспомнила буквуТ наоснове искаженного сигнала).

Здесь нужно обратить внимание нато, что область для рисования представлена сеткой 1010 ипозволяет закрашивать клетки только черным цветом. Так как всети Хопфилда число нейронов равно числу входов, количество нейронов будет равно длине входного сигнала, тоесть 100 (унас всего 100 клеток наэкране). Входной сигнал при этом будет двоичным массив, состоящий из1и1, где 1 это белый, а1 черный цвет.

Наконец-то приступим кнаписанию кода, сначала инициализируем необходимые переменные.

Код инициализации
// Размер сетки установим равным 10 для простоты тестированияconst gridSize = 10;// Размер одного квадрата в пикселяхconst squareSize = 45;// Размер входного сигнала (100)const inputNodes = gridSize * gridSize;// Массив для хранения текущего состояния картинки в левом канвасе,// он же является входным сигналом сетиlet userImageState = [];// Для обработки движений мыши по канвасуlet isDrawing = false;// Инициализация состоянияfor (let i = 0; i < inputNodes; i += 1) {    userImageState[i] = -1;  }// Получаем контекст канвасов:const userCanvas = document.getElementById('userCanvas');const userContext = userCanvas.getContext('2d');const netCanvas = document.getElementById('netCanvas');const netContext = netCanvas.getContext('2d');

Реализуем функцию рисования сетки, используя инициализированные ранее переменные.

Функция отрисовки сетки
// Функция принимает контекст канваса и рисует// сетку в 100 клеток (gridSize * gridSize)const drawGrid = (ctx) => {  ctx.beginPath();  ctx.fillStyle = 'white';  ctx.lineWidth = 3;  ctx.strokeStyle = 'black';  for (let row = 0; row < gridSize; row += 1) {    for (let column = 0; column < gridSize; column += 1) {      const x = column * squareSize;      const y = row * squareSize;      ctx.rect(x, y, squareSize, squareSize);      ctx.fill();      ctx.stroke();    }  }  ctx.closePath();};

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

Обработчики движений мыши
// Обработка клика мышиconst handleMouseDown = (e) => {  userContext.fillStyle = 'black';  // Рисуем залитый прямоугольник в позиции x, y  // размером squareSize х squareSize (45х45 пикселей)  userContext.fillRect(    Math.floor(e.offsetX / squareSize) * squareSize,    Math.floor(e.offsetY / squareSize) * squareSize,    squareSize, squareSize,  );  // На основе координат вычисляем индекс,  // необходимый для изменения состояния входного сигнала  const { clientX, clientY } = e;  const coords = getNewSquareCoords(userCanvas, clientX, clientY, squareSize);  const index = calcIndex(coords.x, coords.y, gridSize);  // Проверяем необходимо ли изменять этот элемент сигнала  if (isValidIndex(index, inputNodes) && userImageState[index] !== 1) {    userImageState[index] = 1;  }  // Изменяем состояние (для обработки движения мыши)  isDrawing = true;};// Обработка движения мыши по канвасуconst handleMouseMove = (e) => {  // Если не рисуем, т.е. не было клика мыши по канвасу, то выходим из функции  if (!isDrawing) return;  // Далее код, аналогичный функции handleMouseDown  // за исключением последней строки isDrawing = true;  userContext.fillStyle = 'black';  userContext.fillRect(    Math.floor(e.offsetX / squareSize) * squareSize,    Math.floor(e.offsetY / squareSize) * squareSize,    squareSize, squareSize,  );  const { clientX, clientY } = e;  const coords = getNewSquareCoords(userCanvas, clientX, clientY, squareSize);  const index = calcIndex(coords.x, coords.y, gridSize);  if (isValidIndex(index, inputNodes) && userImageState[index] !== 1) {    userImageState[index] = 1;  }};

Как вымогли заметить, обработчики использует некоторые вспомогательные функции, такие как getNewSquareCoords, calcIndex иisValidIndex. Ниже код этих функций скомментариями.

Вспомогательные функции
// Вычисляет индекс для изменения в массиве// на основе координат и размера сеткиconst calcIndex = (x, y, size) => x + y * size;// Проверяет, помещается ли индекс в массивconst isValidIndex = (index, len) => index < len && index >= 0;// Генерирует координаты для закрашивания клетки в пределах // размера сетки, на выходе будут значения от 0 до 9const getNewSquareCoords = (canvas, clientX, clientY, size) => {  const rect = canvas.getBoundingClientRect();  const x = Math.ceil((clientX - rect.left) / size) - 1;  const y = Math.ceil((clientY - rect.top) / size) - 1;  return { x, y };};

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

Функция очистки сетки
const clearCurrentImage = () => {  // Чтобы убрать закрашенные клетки, просто заново отрисовываем   // всю сетку и сбрасываем массив входного сигнала  drawGrid(userContext);  drawGrid(netContext);  userImageState = new Array(gridSize * gridSize).fill(-1);};

Теперь можно переходить кразработке мозга программы.

Реализация алгоритма нейросети

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

Инициализация весов сети
...const weights = [];  // Массив весов сетиfor (let i = 0; i < inputNodes; i += 1) {  weights[i] = new Array(inputNodes).fill(0); // Создаем пустой массив и заполняем его 0  userImageState[i] = -1;}...

Так как каждый нейрон всети Хопфилда связан совсеми остальными нейронами, веса сети представлены двумерным массивом, каждый элемент которого является одномерным массивом размером inputNodes элементов. Витоге мыполучаем 100нейронов, укаждого изкоторых по100связей.

Теперь реализуем обработку входного сигнала (изменение весов) нейросетью согласно формуле изпервого шага алгоритма. Данный процесс происходит понажатию накнопку Запомнить. Запомненные образы будут является эталонами для последующего восстановления.

Код обработки входного сигнала
const memorizeImage = () => {  for (let i = 0; i < inputNodes; i += 1) {    for (let j = 0; j < inputNodes; j += 1) {      if (i === j) weights[i][j] = 0;      else {        // Напоминаю, что входной сигнал находится в массиве userImageState и является        // набором -1 и 1, где -1 - это белый, а 1 - черный цвет клеток на канвасе        weights[i][j] += userImageState[i] * userImageState[j];      }    }  }};

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

Функция распознавания искаженного сигнала
// Где-то в html подключаем библиотеку lodash:<script src="http://personeltest.ru/aways/cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>...const recognizeSignal = () => {  let prevNetState;  // На вход сети подается неизвестный сигнал. Фактически   // его ввод осуществляется непосредственной установкой значений выходов  // (2 шаг алгоритма), просто копируем массив входного сигнала  const currNetState = [...userImageState];  do {    // Копируем текущее состояние выходов, // т.е. теперь оно становится предыдущим состоянием    prevNetState = [...currNetState];    // Рассчитываем выход сети согласно формуле 3 шага алгоритма    for (let i = 0; i < inputNodes; i += 1) {      let sum = 0;      for (let j = 0; j < inputNodes; j += 1) {        sum += weights[i][j] * prevNetState[j];      }      // Рассчитываем выход нейрона (пороговая ф-я активации)      currNetState[i] = sum >= 0 ? 1 : -1;    }    // Проверка изменения выходов за последнюю итерацию    // Сравниваем массивы при помощи ф-ии isEqual  } while (!_.isEqual(currNetState, prevNetState));  // Если выходы стабилизировались (не изменились), отрисовываем восстановленный образ  drawImageFromArray(currNetState, netContext);};

Здесь для сравнения выходов сети напредыдущем итекущем шаге используется функция isEqual избиблиотеки lodash.

Для отрисовки полученного сигнала используется функция drawImageFromArray. Она преобразует выходной сигнал сети вдумерный массив иотрисовывает его направом канвасе.

Функция отрисовки изображения из массива точек
const drawImageFromArray = (data, ctx) => {  const twoDimData = [];  // Преобразуем одномерный массив в двумерный  while (data.length) twoDimData.push(data.splice(0, gridSize));  // Предварительно очищаем сетку  drawGrid(ctx);  // Рисуем изображение по координатам (индексам массива)  for (let i = 0; i < gridSize; i += 1) {    for (let j = 0; j < gridSize; j += 1) {      if (twoDimData[i][j] === 1) {        ctx.fillStyle = 'black';        ctx.fillRect((j * squareSize), (i * squareSize), squareSize, squareSize);      }    }  }};

Финальные приготовления

Для полноценного запуска программы осталось только добавить наши функции вкачестве обработчиков для элементов HTML ивызвать функции отрисовки сетки.

Привязываем функции к HTML элементам
const resetButton = document.getElementById('resetButton');const memoryButton = document.getElementById('memoryButton');const recognizeButton = document.getElementById('recognizeButton');// Вешаем слушатели на кнопкиresetButton.addEventListener('click', () => clearCurrentImage());memoryButton.addEventListener('click', () => memorizeImage());recognizeButton.addEventListener('click', () => recognizeSignal());// Вешаем слушатели на канвасыuserCanvas.addEventListener('mousedown', (e) => handleMouseDown(e));userCanvas.addEventListener('mousemove', (e) => handleMouseMove(e));// Перестаем рисовать, если кнопка мыши отпущена или вышла за пределы канвасаuserCanvas.addEventListener('mouseup', () => isDrawing = false);userCanvas.addEventListener('mouseleave', () => isDrawing = false);// Отрисовываем сеткуdrawGrid(userContext);drawGrid(netContext);

Демонстрация работы нейросети

Обучим сеть двум ключевым образам, буквам Т и Н:

Эталонные образы для обучения сетиЭталонные образы для обучения сети

Теперь проверим работу сети на искаженных образах:

Попытка распознать искаженный образ буквы НПопытка распознать искаженный образ буквы НПопытка распознать искаженный образ буквы ТПопытка распознать искаженный образ буквы Т

Программа работает! Сеть успешно восстановила исходные образы.

В заключение стоит отметить, что для сети Хопфилда число запоминаемых образов mнедолжно превышать величины, примерно равной 0.15 * n(где n размерность входного сигнала иколичество нейронов). Кроме того, если образы имеют сильное сходство, то они, возможно, будут вызывать усети перекрестные ассоциации, тоесть предъявление навходы сети вектораА приведет кпоявлению наеевыходах вектораБ инаоборот.

Исходникина Github и демо.

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

Подробнее..

Из песочницы Как продвигаться в TikTok?

11.11.2020 14:20:14 | Автор: admin
Ещё пару лет назад мы и представить не могли, что TikTok это не просто песня знаменитой исполнительницы Kesha, но и главное и обсуждаемое приложение для генерации контента в мире! Уже сегодня оно имеет более 20 млн пользователей в нашей стране, а в мире примерно 1,5 млрд установок и 700 млн активных пользователей. Многие уже называют его главным приложением поколения. Однако площадка интересна не только своей быстрорастущей аудиторией, но и продвижением брендов. В мире по сей день ведутся споры, что TikTok является пузырем для продвижения и не стоит затрат, а другие, наоборот, считают это отличным инструментом в своем арсенале для повышения узнаваемости и охватов.

Так что же такое TikTok? В чем его особенности? Как можно продвигаться на платформе? И почему его все так любят? Специалисты Коммуникационного агентства 4D собрали все самое важное о TikTok в новом материале блога.



О TikTok


Если описать TikTok простым языком, то это приложение для создания коротких музыкальных клипов и обмена сообщениями. Такой формат идеально вписался в современную жизнь людей, когда они потребляют контент в основном с мобильных устройств. При этом пользователи всё чаще предпочитают именно короткий контент, который удобно потреблять в любое время и в любом месте: ролики в TikTok имеют хронометраж до минуты, но чаще всего снимаются 15-секундные видео.

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

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

Многие до сих пор сравнивают TikTok со Stories от Instagram или Snapchat, т. к. контент также подаётся в вертикальном и коротком форматах, однако платформа стала популярна не только благодаря им. Основное её отличие атмосфера абсолютного творчества и свободы самовыражения, искренность и настоящие эмоции авторов контента. Можно сказать, что TikTok дал огромный толчок на тренд быть настоящим. Именно это и зацепило пользователей, ведь на платформе знаменитым может стать каждый, не используя специальное оборудование или сторонние видеоредакторы. Достаточно иметь хорошую идею.

Касаемо интерфейса, то TikTok является довольно простым и состоит всего из 5 разделов:

  • Главная: лента постов от пользователей, на которых вы подписаны
  • Интересное: лента с популярными роликами и рекомендациями
  • Кнопка для добавления своего видео
  • Уведомления
  • Страница профиля



Кто сидит в TikTok?


Основной ЦА приложения являются по-прежнему подростки и молодежь, которые обеспечивают основной рост популярности приложению. Также можно сказать, что пользователи повзрослели, так как платежеспособная аудитория тоже представлена на площадке в полной мере.



Согласно данным представителя TikTok, озвученным на конференции Маркетинг #реальноговремени, месячная аудитория TikTok в России в январе 2020 года составила 18 млн активных пользователей, хотя ещё в мае 2019 года их число не превышало и 8 млн. Из них 60% женщины, 40% мужчины. Дети и подростки составляют 43% аудитории. Вторая, наиболее массово представленная возрастная группа в России, от 18 до 34 лет составляет 33% от общей аудитории TikTok. Из них основное количество приходится на платёжеспособных пользователей в возрасте от 25 до 34 лет 21%. Однако в сегменте российской аудитории TikTok 40% пользователи младше 18 лет. Именно за их счет идет активный рост пользователей приложения. Например, доля авторов младше 18 лет выросла за 2018 год на 40%, по данным Brand Analytics. А уже сегодня исследование Oberlo говорит нам о том, что у TikTok 800 миллионов активных пользователей по всему миру, а 41% пользователей TikTok это люди в возрасте от 16 до 24 лет.

Самые популярные тиктокеры, также являются молодыми ребятами, средний возраст которых составляет 18-25 лет. Одними из наиболее популярных тиктокеров являются Рахим Абрамов (22 года), Дина Саева (21 год), Даня Милохин (18 лет) и другие.

Продвижение в TikTok


Несмотря на распространённое убеждение, что контент в TikTok полный треш, видеосервисом пользуется каждый седьмой россиянин, что привлекает рекламодателей. Продвижение с помощью тиктокеров уже освоили Coca Cola, PepsiCo, МегаФон, Макдональдс, Mail.ru и другие крупные компании. А по данным отчёта Conviva многие спортивные, новостные и стриминговые бренды за рубежом активно используют соцсеть для дистрибуции своего контента и привлечения новых пользователей.



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

Но для кого подойдет реклама в таком приложении, как TikTok? Можно с уверенностью сказать, что продвижение подойдет почти любому аккаунту. Однако наиболее результативная реклама может быть для следующих сегментов:

  • бренды;
  • интернет-магазины;
  • службы доставки;
  • товары для детей;
  • компании из сфер красоты и спорта;
  • студии танцев;
  • мобильные приложения;
  • курсы и школы иностранных языков;
  • FMCG (или же товары повседневного спроса);
  • владельцы сервисов.

Основное преимущество рекламы TikTok нативность. Контентмейкеры создают интересные и веселые для пользователей ролики, используя продукт рекламируемого бренда.

С помощью сайта бизнес может получить доступ к рекламным форматам TikTok, включая TopView полноэкранный баннер, который появляется при первом запуске приложения. Кроме того, на платформе представлены форматы:

  • Brand Takeover это полноэкранный баннер с обратным отсчётом на 3-5 секунд до кнопки закрытия.
  • Hashtag Challenge это флешмоб от имени бренда, который длится шесть дней.
  • In-Feed Video кампания с роликом на 5-15 секунд в ленте пользователей.
  • Branded Effects брендированные 2D или 3D-фильтры.

Поговорим о них более подробно.

Brand Takeover


Особенность данного вида рекламы в TikTok заключается в том, что крупное объявление появляется сразу после открытия приложения. Это фото, gif или видео размером до 2 МБ. Объявление содержит ссылку на сайт или уникальный хештег. Также данный инструмент рекомендовано использовать в дополнении с другими, например, с Hashtag Challenge.

Brand Takeover измеряется такими метриками как: просмотры, охват и переходы.



Hashtag Challenge


Челленджи являются главным рекламным форматом в TikTok. На платформе постоянно проходят разнообразные челленджи, к которым может присоединиться любой желающий. Отметим, что это один из самых эффективных способов быстрого продвижения на TikTok.

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

Все ролики доступны по хештегу, а охват таких кампаний может серьезно перевыполнить план за счет вовлечения не только инфлюенсеров, но и их подписчиков. Именно поэтому TikTok предлагает брендам участие в Hashtag Challenge в качестве эффективного рекламного формата.
В рекламных кампаниях этот инструмент нередко используют вместе с Branded Effect. Это 2D или 3D-маска, которую человек может использовать в своём видео и стать создателем брендированного и оригинального контента.

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



In-Feed Native Video


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

В In-Feed Video можно также добавить дополнительный функционал для взаимодействия с пользователями, такой, как опросы. Например, блогер рассказывает про свой опыт работы с приложением и спрашивает, пользовались ли им его подписчики. При ответе нет переход происходит в AppStore или Google Play для установки, при ответе да на сайт рекламодателя со спецпредложением. Также можно добавить функцию Super like, когда при нажатии на like появляется брендированный спецэффект. В нижней части экрана при использовании In-Feed Video возможно разместить баннер. Последнее важно, когда необходимо обязательное присутствие бренда в кадре и заявить продукт или упаковку с первой секунды.

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



Branded Effects


Данный формат снова напоминает нам маски от Instagram и линзы в Snapchat и эффекты в Facebook. В TikTok их можно создавать на ограниченное количество времени (до 10 дней). Брендированные материалы будут показываться в ключевых местах во всем приложении. Например, это могут быть кастомизированные стикеры, фильтры и специальные эффекты в форматах 2D, 3D и даже AR.



Познакомившись с основными инструментами приложения, все ещё непонятно, что же даст продвижение в TikTok?

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

Работа с рекламным кабинетом в TikTok


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

Для создания рекламной кампании в TikTok необходимо перейти на страницу TikTok Ads и нажать на кнопку Создать.



Выберите цель:

  • Traffic (увеличение посещаемости);
  • Conversions (аналитика конверсий);
  • App Install (увеличение количества пользователей демонстрацией фирменного приложения).



Ad Group Name. Назовите кампанию.



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



Ad Details. Укажите тип продвижения: переход на сайт или установка приложения.



Display Name. Введите название бренда и загрузите логотип.



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



Ad Tegs. Укажите теги, максимальное количество 20 тегов. Алгоритм TikTok будет использовать их для подбора пользователей для кампании.



User Comment. Функция, открывающая или закрывающая комментарии под роликом.



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



Targeting. Создайте релевантную аудиторию по указанным данным.

Установите бюджет:

  • Daily Budget ограничение по дням;
  • Total Budget определение общего бюджета.



Установите ставку за клик.



Создайте креативы.



Все креативы уже полностью зависят от вас.

Аналитика TikTok


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

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



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

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



В левом столбце выберете интересующий вас параметр и получите анализ по эффективным для публикации дням недели, времени суток, зависимости вовлечения от формата публикации и объема текста.



Заключение


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

Дизайнеру приложений как создать и передать в разработку тёмную тему

16.07.2020 12:18:27 | Автор: admin


В конце 2019 года зарелизили iOS 13 и Android 10 с поддержкой автопереключения на тёмную тему. Мы решили добавить её в приложение Ростелеком Ключ под iOS и Android, над которым работали в тот момент. В процессе не обошлось без сложностей. Рассказываем о нашем опыте, чтобы вы в аналогичной ситуации сэкономили время и нервы.

Зачем делать тёмную тему


Может показаться, что это всё на волне хайпа. Но не только :)

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

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

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

В нашем случае приложение РТ Ключ кросс-платформенный сервис для управления устройствами на территории дома: домофонами, шлагбаумами, камерами видеонаблюдения во дворе и в подъезде. Жители домов используют его как днём, так и ночью.

Справедливо заметить, что тёмная тема также помогает экономить заряд (для некоторых типов экранов: OLED/amoled да, LCD нет). А в долгосрочной перспективе она может замедлить развитие близорукости.

Как перейти на тёмную сторону: пошаговая инструкция


Если вы совсем ничего не знаете о тёмной теме, то можно начать знакомство со статей в Human Interface Guidelines для iOS и в Material Guide для Android. Там подробно разобрано, как цвета и слои взаимодействуют друг с другом в ночном режиме. Перейдём к нашим советам:

1. Приведите в порядок макеты и соберите UI kit

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

  • Цветовая палитра стилей для обычного состояния элементов, состояния при нажатии, цвета для неактивных элементов, инпутов в фокусе и так далее.
  • Текстовые стили.
  • Все элементы интерфейса (кнопки, поля ввода, элементы списков, блоки с заголовками и так далее) в различных состояниях и ситуациях в виде master components.
  • Сет иконок в черном цвете.
  • Иллюстрации.

UI kit нашего приложения можно рассмотреть в Figma.

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

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

2. Договоритесь о названиях цветов

Чтобы дизайнерам, iOS и Android-разработчикам было проще общаться между собой, цвета мы решили назвать универсально для обеих платформ. В прошлой версии UI kit цветовые стили мы обозначили незатейливо по номерам: C1, C2, C3 Это было не слишком удобно: при обсуждении все называли цвета не по цифрам, а по оттенкам: фиолетовый, оранжевый, чёрный и т. д.

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

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

  • Назначение цвета или элемент, на котором он используется.
  • Приоритетность использования (опционально).
  • Состояние элемента, если это применимо (опционально).


Слева наименования для цветов кнопки в обычном состоянии, при нажатии на iOS, цвет Ripple в Android и неактивная кнопка на обеих платформах. Справа имена для текстов на различных поверхностях

В общем, если в вашем проекте ещё нет UI kit, а вместо цветовых стилей назначены обычные цвета, пора причесать макеты.

3. Подберите цвета для тёмной темы

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

3.1. Фоновый цвет

Начать перерисовку макета стоит с фонового цвета: он занимает большую часть экрана. В гайдах Material Design советуют брать за основу нейтральный тёмно-серый (#121212). Он, в отличие от черного, оставляет простор для построения глубины экрана.

Фоновый цвет должен хорошо сочетаться с цветом интерактивных элементов: кнопок, иконок и т. д. У нас в светлой палитре для интерактивных элементов использовался фирменный фиолетовый цвет Ростелекома #7700ff. В дальнейшей работе отталкивались от него.

Нейтральный тёмно-серый плохо смотрелся с брендовым фиолетовым, поэтому мы последовали советам гайдлайнов Material Design. Ребята рекомендуют наложить поверх нейтрального фонового серого #121212 фирменный цвет с 8% непрозрачности.


Нейтральные и брендированные цвета фона в тёмной теме

Помимо основного фона у нас встречаются карточки с небольшим подъемом над поверхностью. В Material Design рекомендуют в тёмной теме создавать элевацию элементов за счёт осветления фона: чем ближе карточка к пользователю, тем светлее.

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



3.2. Создание базовой палитры

В Material Design рекомендуют при создании брендированной тёмной темы заменять цвета на менее насыщенные аналогичного оттенка. В качестве фирменного цвета для РТ Ключ мы использовали фиолетовый.

При попытке осветлить его по рецепту Material Design его оттенок стал розоватым. Оригинальный фирменный цвет выглядел синее, поэтому мы вручную изменили его оттенок.


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

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

Navbar и крупные кнопки в осветленной фиолетовой версии особенно сильно отвлекали внимание от контента, а если мы снижали яркость, линейные иконки терялись на тёмном фоне.


В исходной светлой теме насыщенный фиолетовый цвет одинаково хорошо смотрится на крупных блоках с белым текстом и на тонких линейных иконках на светлом фоне. А на тёмном фоне всё не так

Пришлось как в тёмной, так и в светлой теме заменить один исходный цвет на три: один для контурных иконок, второй для больших кнопок с фоном, третий для уголка на главном экране и navbar на остальных.


Заменили один фиолетовый на три так намного лучше

Помимо фиолетового мы использовали оранжевый, желтый, бирюзовый и красный. Оранжевый для call to action элементов, желтый для уведомлений, бирюзовый для подтверждения операции, красный для ошибок.

Когда мы осветлили эти четыре цвета по совету Material Design, серьезно изменилась контрастность приложения по сравнению со светлой темой. Пришлось отступить от гайдов: оранжевый, бирюзовый и красный мы не осветлили, а затемнили. Жёлтый оставили неизменным, поскольку при затемнении он грязнил.



3.3. Особенности палитры iOS

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

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


Оттеночный цвет (tint) в темной теме

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

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

3.4. Особенности палитры Android

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

Your browser does not support HTML5 video.

Ripple в Android приложении

Также в Android есть особенности отрисовки status bar и navigation bar. Status bar строка состояния, где отображаются уведомления, уровень сигнала, заряд батареи и время. Navigation bar панель, где располагаются кнопки назад, домой и недавние приложения.

С появлением смартфонов с крупными дисплеями, доходящими до самого края устройства, челками и дырками под камеру, в Material Design представили концепцию edge to edge. Её суть в том, что служебные элементы не должны съедать полезную площадь, и как можно большее место на экране должен занимать полезный контент.

Для этого в Android доработали поддержку прозрачных status bar и navigation bar. Дело в том, что эти панельки не на всех телефонах имеют одинаковую высоту. И если до начала поддержки edge to edge мы назначали им прозрачный фон, на некоторых устройствах они некрасиво накладывались на контент экрана. Теперь в материальных компонентах появились системные отступы: разработчики могут определять размер status bar и navigation bar и задавать соответствующий отступ для контента. Поэтому раньше в Material Design рекомендовали выбирать непрозрачный фон для status bar и navigation bar, а теперь наоборот.

Однако важно учитывать, что не во всех поддерживаемых версиях Android можно назначить цвет иконок в системных компонентах:

  • до 6.0 иконки в status bar и navigation bar всегда белые;
  • с версии 6.0 можно задать, белыми или черными будут иконки в status bar, но navigation bar будет вести себя так, как в предыдущих версиях.
  • с версии 8.1 можно выбрать цвет иконок как в status, так и в navigation bar.

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

  • в старых версиях Android до 6.0 для обеих панелек задали черный фон с 50% прозрачности на нем хорошо смотрятся белые иконки;
  • с 6.0 и до 8.1 navigation bar остается с полупрозрачным черным фоном, а status bar полностью прозрачный;
  • с версии 8.1 фон обеих панелек полностью прозрачный.

Если вы по каким-то причинам не готовы к такой поддержке edge to edge, лучше сделать status bar и navigation bar универсальными. Поддержка edge to edge:

3.5. Проверьте контрастность элементов

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

Лучше всего проверять контрастность с помощью тестирования: открыть интерфейс на смартфоне, используя Figma Mirror или аналогичный софт, выйти на яркое солнце (тёмная тема предназначена для использования в темноте, но людям ничто не помешает использовать её на свету).

Также будет полезно попросить посмотреть на приложение людей с нарушениями зрения (близорукостью, дальнозоркостью, дальтонизмом). Но если такой возможности нет, контрастность можно проверить на сайте contrast-ratio или с помощью плагина в Figma.

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


Для тёмной темы приходится делать отдельные версии иллюстраций и анимаций в тёмных цветах

Как передавать в разработку

Мы работали в связке Figma + Zeplin. Это может показаться странным, но мы всей компанией перешли на Figma из Sketch в конце лета 2019, прямо перед началом работы нам тёмной темой. И чтобы сэкономить время на адаптацию разработчиков к новому инструменту, продолжили работать с Zeplin. И тут он преподнес нам несколько сюрпризов.

В палитре Zeplin нельзя создать цветовые стили с одинаковыми HEX. Поэтому нам пришлось незначительно, практически незаметно для глаза, менять HEX у фиолетового цвета в светлой теме.
Даниил Субботин, iOS-разработчик Redmadrobot subdan:
Обнаружилось, что ни один инструмент дизайнера, в том числе Zeplin, не поддерживает темную тему и поэтому не позволяет иметь несколько цветовых палитр в одном проекте. Пришлось искать пути обхода. Например, мы создали два проекта: один со светлой палитрой, а другой с тёмной.


1. Особенности iOS dev


Следующий сюрприз, который нам преподнес Zeplin: из него можно экспортировать только одну палитру в Xcode-проект. Либо светлую, либо тёмную. При попытке экспортировать цвета тёмной палитры Zeplin просто заменял ими все светлые. Мы стали переносить цвета вручную, копируя HEX-значения. То же самое делали и с изображениями.

Даниил Субботин, iOS-разработчик Redmadrobot subdan:
После долгих мучений я написал утилиту, которая выгружает обе цветовые палитры прямо в Xcode-проект, используя Zeplin API. Это сильно упростило жизнь. Дизайнер сообщает, что добавил новый цвет или изменил старый, я запускаю скрипт, и все изменения автоматически подтягиваются в проект

2. Особенности Android dev


На Android тёмная тема доступна на всех версиях ОС (мы тестировали начиная с пятой). Но переключать её в системе можно только на 10-м Android, поэтому стоит добавить в приложение возможность переключать её вручную.

Владислав Шипугин, android-разработчик Redmadrobot shipa_o:
Мы добавили следующие варианты выбора темы: всегда светлая, всегда тёмная, выбирается в зависимости от режима энергосбережения (9-я версия андроида и ниже), переключается в зависимости от настроек системы (10-я версия андроида и выше). Но важно учесть, что выбранная пользователем тема приложения в системе не сохраняется. Нужно запоминать её внутри и активировать при каждом запуске приложения


В Android есть своя система цветов для материальных компонентов (кнопок, app bar, текстовых полей и т. д.). Гайдлайны Material Design о цвете.

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

Как поддерживать и развивать


С тех пор как мы проработали тёмную тему, у нас добавилось несколько новых функций, появились планшетные пользователи, а продуктовый офис в Ростелекоме задумался о том, чтобы выпустить приложение РТ Ключ в виде white label для застройщиков в их фирменных цветах.

Оля Сартакова, арт-директор Redmadrobot:
Мы поняли, что текущую версию дизайна, разработанную для запуска MVP, пора переосмыслить как структурно, так и визуально. Мы полностью переработали структуру приложения с учетом тех функций, которые должны появиться в ближайшие два года, добавили дашборд для быстрого доступа к самым популярным функциям, избавились от ярких фирменных элементов в оформлении (вроде уголка на главном экране и цветного nav bar). А вот грамотная работа над цветовой системой позволила практически полностью сохранить её при тотальном редизайне приложения.

Вторая версия дизайна приложения в той же цветовой палитре:


Даниил Субботин, iOS-разработчик Redmadrobot subdan:
К моменту запуска второй версии мы безболезненно переехали на Figma, я адаптировал утилиту, которую изначально написал для Zeplin, под Figma. Теперь мы обновляем цвета, иконки и картинки в Xcode и Android Studio в один клик


Скачать нашу утилиту можно здесь.

Выводы: как у нас, только лучше


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

  • Соберите UI kit.
  • Продумайте систему наименования цветов или воспользуйтесь нашей.
  • Подберите брендированный фоновый цвет.
  • Подберите оттенок для основного и второстепенных фирменных цветов.
  • Если ваше приложение кроссплатформенное, составьте список отличий цветовых схем iOS и Android. А также проверьте, не нужно ли добавить в приложение на Android ручную настройку тёмной темы.
  • Проверьте контрастность выбранных цветов.
  • Подготовьте иллюстрации и анимации для тёмной темы.
  • Обновите UI kit.
  • Воспользуйтесь нашей утилитой для передачи элементов в разработку.

Полезные материалы


Чтобы ещё глубже погрузится в тёмную тему:


И немного полезностей для разработчиков:

Подробнее..

Быстрый старт гайд по автоматизированному тестированию для Android-разработчика. JVM

14.12.2020 14:08:42 | Автор: admin

Привет! Меня зовут Сергей Иванов, я ведущий разработчик Android в Redmadrobot. С 2016 использую автотесты различных категорий и успел в этом набить немало шишек. Именно поэтому решил поделиться опытом. Возможно, что кому-то статья поможет систематизировать знания или начать применять эту практику в работе.

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

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

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

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

  • базовые понятие автоматизированного тестирования;

  • категории тестов их специфика на Android;

  • как писать тестируемый код;

  • как и какие инструменты использовать для тестирования;

  • как писать полезные и поддерживаемые тесты;

  • что тестировать;

  • как и когда применять методологию Test Driven Development.


При производстве приложений автотесты помогают:

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

  2. Локализовать проблему. Чем более низкоуровневым является тест, тем более точно он способен указать на причину ошибки.

  3. Ускорить разработку. Это вытекает из предыдущих пунктов и из того, что благодаря автотестам разработка разных частей фичи может быть оперативно разделена на несколько разработчиков. Установив контракты между компонентами приложения, разработчик может разработать свой компонент и проверить его корректность при отсутствии остальных (например, при полном отсутствии UI).

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

Но есть и проблемы:

  1. Нужно время на внедрение, написание и поддержку.

  2. При некорректном внедрении практики могут принести больше вреда, чем пользы.

Важные базовые понятия автоматизированного тестирования

System Under Test (SUT) тестируемая система. В зависимости от типа теста системой могут быть разные сущности (о них подробнее написал в разделе категории тестов).

Для различия уровня тестирования по использованию знаний о SUT существуют понятия:

Black box testing тестирование SUT без знания о деталях его внутреннего устройства.

White box testing тестирование SUT с учётом деталей его внутреннего устройства.

Выделяют также Gray box testing, комбинацию подходов, но ради упрощения он будет опущен.

Для обеспечения базового качества автотестов важно соблюдать некоторые правила написания. Роберт Мартин сформулировал в книге "Clean Code" глобальные принципы F.I.R.S.T.

Fast тесты должны выполняться быстро.

Independent тесты не должны зависеть друг от друга и должны иметь возможность выполняться в любом порядке.

Repeatable тесты должны выполняться с одинаковым результатом независимо от среды выполнения.

Self-validating тесты должны однозначно сообщать о том, успешно их прохождение или нет.

Timely тесты должны создаваться своевременно. Unit-тесты пишутся непосредственно перед кодом продукта.

Структура теста состоит как минимум из двух логических блоков:

  • cовершение действия над SUT,

  • проверка результата действия.

Проверка результата заключается в оценке:

  • состояния SUT или выданного ею результата,

  • cостояний взаимодействующих с SUT объектов,

  • поведения (набор и порядок вызовов функций других объектов, которые должен совершить SUT, переданные в них аргументы).

При необходимости также добавляются блоки подготовки и сброса тестового окружения, отчасти связанные с первыми тремя принципам F.I.R.S.T.

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

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

Зачастую для настройки окружения применяются тестовые дублеры.

Test doubles (Тестовые дублёры) фиктивные объекты, заменяющие реальные объекты, от которых зависит SUT, для достижения целей теста.

Тестовые дублеры позволяют:

  • зафиксировать тестовое окружение, имитируя неважные, нереализованные, нестабильные или медленные внешние объекты (например, БД или сервер),

  • совершать проверки своих вызовов (обращений к функциям, свойствам).

Самая популярная классификация включает 5 видов тестовых дублеров, различных по своим свойствам: Dummy, Fake, Stub, Spy, Mock.

Stub объект, который при вызовах его функций или свойств возвращает предустановленные (hardcoded) результаты, а не выполняет код реального объекта. Если же функция не имеет возвращаемого значения, то вызов просто игнорируется.

Mock объект, позволяющий проверять поведение SUT путём отслеживания обращений к функциям и свойствам объекта: были ли в ходе теста вызваны функции мока, в правильном ли порядке, ожидаемые ли аргументы были в них переданы и т.д. Может также включать функциональность Stub.

Почитать об этих и остальных видах дублеров можно в первоисточнике.

Эта классификация не является стандартом, и в фреймворках для создания тестовых дублёров часто ради удобства API несколько типов обобщают термином Mock. А вот чем они на самом деле будут являться, зависит от их последующей конфигурации и применения в тесте. Например, при использовании фреймворка Mockito, экземпляр тестового дублера может быть создан как Dummy, а потом превращен в Stub и в Mock.

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

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

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

Категории тестов

Есть разные версии категоризации тестов, по разным характеристикам, поэтомусуществует некоторая путаница.

Покажу основные категории уровней тестов, на которых тестируется система, на примере одного из самых распространенных вариантов пирамиды тестирования:

Unit-тесты проверяют корректность работы отдельного unit-а (модуля). Unit-ом (то есть SUT данного типа тестирования) может быть класс, функция или совокупность классов.

Integration-тесты (в приложении) проверяют корректность взаимодействия модулей или наборов этих модулей (компонентов). Определение SUT данной категории является еще более расплывчатым, т.к. в свою очередь зависит от того, что считается модулем.

Грань между Unit- и Integration-тестированием довольно тонкая. Интеграционными тестами, в зависимости от масштаба и контекста, в принципе могут называть тесты, проверяющие взаимодействие чего-либо с чем-либо с определенной долей абстракции: приложение(клиент)-сервер, приложение-приложение, приложение-ОС и др. Но в дальнейшем я буду говорить об интеграционном тестировании в рамках приложения.

End-to-end-тесты (E2E) интеграционные тесты, которые воздействуют на приложение и проверяют результат его работы через самый высокоуровневый интерфейс (UI), то есть на уровне пользователя. Использование тестовых дублеров на этом уровне исключено, а значит обязательно используются именно реальные сервер, БД и т.д.

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

Вернёмся к категориям. В Android сложность категоризации автотестов усугубляется еще и тем, что они могут работать на JVM или в Instrumentation-среде (эмулятор или реальное устройство). Последние называют инструментальными.

Чтобы было удобнее ориентироваться в видах тестов, не путаясь в терминологии, предлагаю такую категоризацию для мобильного приложения на Android:

JVM Integration tests интеграционные тесты, проверяющие взаимодействие модулей или совокупностей модулей без использования Instrumentation. Характеризуются они высокой скоростью исполнения, сравнимой с Unit-тестами, также выполняющимися на JVM.

Instrumentation Integration non-UI tests интеграционные тесты, исполняемые уже в реальной Android-среде, но без UI.

Component UI tests интеграционные инструментальные тесты с использованием UI и фиктивных сервера и БД, если таковые требуются. Тест может состоять как из одного экрана, запущенного в изоляции, так и из нескольких экранов с соблюдением их реального флоу.

E2E UI tests интеграционные инструментальные UI-тесты без тестовых дублеров только с реальным флоу экранов. Максимально приближены к ручным тестам.

Если Unit-тесты являются сильно завязанными на детали реализации, очень быстро выполняются, относительно легко пишутся и наиболее точно при поломке указывают на причину ошибки, то в случае E2E UI ситуация противоположная. Изменение этих характеристик происходит постепенно от низа к верху пирамиды.

При переходе от тестов на JVM к тестам на Instrumentation из-за использования настоящей Android-среды происходит резкое падение скорости выполнения этих тестов. Это становится серьезным ограничением. Особенно когда тесты необходимо запускать часто и много раз подряд. Поэтому к написанию инструментальных тестов следует прибегать лишь в случаях, когда использование настоящих Android-зависимостей действительно необходимо.

UI-тесты

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

Часто они оказываются нестабильны в своём поведении и могут то выполняться, то падать, даже если не вносилось никаких изменений в реализацию (нестабильные тесты называют Flaky). Мало того, UI-тесты могут совершенно по-разному себя вести на разных устройствах, эмуляторах и версиях Android. Когда же UI-тесты являются еще и E2E, добавляется хрупкость и снижается скорость выполнения из-за реальных внешних зависимостей. Причем в случае ошибки найти её причину бывает затруднительно, поскольку проверки в таких тестах осуществляются на уровне состояния UI. В таких ситуациях выгоднее обойтись силами QA-инженеров.

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

Поэтому, для написания UI-тестов желательно иметь разработчиков или QA-инженеров-автоматизаторов, которые будут заниматься именно ими бльшую часть времени.

Unit-тесты

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

Степень хрупкости же можно снизить за счет использования black box-стиля написания даже на этом уровне, когда возможно. Но не следует злоупотреблять применением тестовых дублеров: если уже реализованная сущность имеет тривиальную логику или наличие логики не подразумевается, стоит использовать ее настоящую реализацию.

А заменять дублером следует только то, что действительно необходимо для приемлемой изоляции SUT в конкретном случае. Иногда (но далеко не всегда!) бывает оптимальнее сделать переиспользуемый рукописный дублер, чем конфигурировать его фреймворком для создания дублеров в множестве мест.

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

Подытожим

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

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

  • Лучше делать акцент на быстро выполняющиеся тесты. Так, после Unit-тестов рекомендую проверять JVM Integration-тестами интеграцию в том масштабе, который можно комфортно обеспечить без использования Instrumentation от ViewModel до слоя данных.

Дальше я буду говорить преимущественно о тестах на JVM. Но некоторые моменты актуальны и для остальных категорий.

Инструментарий

Раньше для написания JVM-тестов наши разработчики использовали фреймворки Junit 4 и Junit 5, но потом переключились на молодой перспективный Spek 2. Junit 4 нужен для инструментальных тестов с другими фреймворками они не работают.

Для проверок (assert) используем AssertJ отличную библиотеку с богатым набором читабельных ассертов и удобных дополнительных функций.

Для создания тестовых дублеров применяем Mockito-Kotlin 2 Mockito 2, адаптированный для Kotlin.

Для стаббинга и мокирования сервера MockWebServer библиотеку от Square, рассчитанную на работу с OkHttp.

Фреймворки PowerMock и Robolectric не используем из соображений скорости выполнения тестов и их надёжности. Кроме того, эти фреймворки поощряют плохо пахнущий код это дополнительные зависимости, без которых вполне можно обойтись. Для этого код должен быть тестируемым.

Дизайн кода

Признаки нетестируемого кода:

  • Наличие неявных зависимостей, сильная связанность. Это затрудняет изолированное unit-тестирование, тестирование на раннем этапе развития фичи, распараллеливание разработки. Использование статических функций, создание сложных объектов внутри класса, ServiceLocator исключают возможность использования тестовых дублеров.

  • Обилие Android-зависимостей. Они требуют Instrumentation или объемную подготовку среды на JVM с тестовыми дублерами, если их использование вообще возможно (см. прошлый пункт).

  • Наличие явного управления асинхронным и многопоточным поведением. Если результат работы SUT зависит от выполнения асинхронной работы, особенно порученной другому потоку (или нескольким), то не получится просто так гарантировать правильность и стабильность выполнения тестов. Тест может совершить проверки и завершиться раньше, чем асинхронная работа будет выполнена, и результат не будет соответствовать желаемому. При этом принудительное ожидание в тестах (в первую очередь на JVM) плохая практика, поскольку нарушается принцип Fast.

Пример
class ExampleViewModel constructor(val context: Context) : BaseViewModel() {    private lateinit var timer: CountDownTimer    fun onTimeAccepted(seconds: Long) {        val milliseconds = MILLISECONDS.convert(seconds, SECONDS)        // Неявная зависимость, Android-зависимость, запуск асинхронной работы        timer = object : CountDownTimer(milliseconds, 1000L) {            override fun onTick(millisUntilFinished: Long) {                showTimeLeft(millisUntilFinished)            }            override fun onFinish() {                // Неявная зависимость. Вызов статической функции с Android-зависимостью                WorkManager.getInstance(context)                    .cancelUniqueWork(SeriousWorker.NAME)            }        }        timer.start()    }

Как сделать код тестируемым

Следовать принципам SOLID, использовать слоистую архитектуру. Грамотное разделение и реализация сущностей позволит писать изолированные тесты именно на интересующую часть функционала, не допускать чрезмерного разрастания тестового файла и, при необходимости, осуществлять распараллеливание разработки. DI позволит подменять настоящие реализации тестовыми дублёрами.

Стремиться к чистоте функций. Это функции, которые:

  1. При одинаковом наборе входных данных возвращают одинаковый результат.

  2. Не имеют побочных эффектов, т.е. не модифицируют внешние переменные (класса, глобальные) и переданные в качестве входных данных параметры.

Пример теста такой функции:

val result = formatter.toUppercase("адвокат")assertThat(result).isEqualTo("АДВОКАТ")

Минимизировать количество Android-зависимостей. Часто прямое использование Android-зависимостей в SUT не является необходимым. Тогда их следует выносить вовне, оперируя в SUT типами, поддерживающимися на JVM.

Самая распространенная Android-зависимость в потенциально тестируемых классах ресурсы, и их выносить из, скажем, ViewModel, ну, совсем не хочется. В таком случае можно внедрить Resources во ViewModel, чтобы стаббить конкретные ресурсы (их id актуальны на JVM) и проверять конкретные значения:

mock<Resources> { on { getString(R.string.error_no_internet) } doReturn "Нет интернета" }

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

interface ResourceProvider {    fun getString(@StringRes res: Int, vararg args: Any): String}class ApplicationResourceProvider(private val resources: Resources) : ResourceProvider {    override fun getString(res: Int, vararg args: Any): String {        return resources.getString(res, *args)    }}class TestResourceProvider : ResourceProvider {    override fun getString(res: Int, vararg args: Any): String = "$res"}

При таком поведении TestResourceProvider по умолчанию правильность строки в ожидаемом результате можно сверять по id ресурса:

val string = TestResourceProvider().getString(R.string.error_no_internet)assertThat(string).isEqualTo(R.string.error_no_internet.toString())

В общем случае лучше вообще не заменять дублерами типы, принадлежащие сторонним библиотекам и фреймворкам. Это может привести к проблемам при обновлении их API. Обезопасить себя можно также с помощью Wrapper. Подробнее ситуация разобрана в статье Dont Mock Types You Dont Own.

Использовать Wrapper-ы для статический функций, управления асинхронным и многопоточным поведением. Существует немало стандартных статических функций или Android-зависимостей в виде таких функций. Если нужно иметь с ними дело, то следует помещать их во Wrapper-ы и внедрять в SUT для последующей подмены.

Это поможет и при работе с асинхронностью и многопоточностью: инкапсулирующий управление ими Wrapper можно заменить тестовым дублером, который позволит проверяемому коду выполняться в одном потоке и синхронно вызвать асинхронный код. Для RxJava и Kotlin Coroutines есть стандартные решения от их авторов.

Дизайн тестов

Важно оформлять тесты качественно. Иначе они помогут в момент написания, но в будущем будет уходить много времени на их понимание и поддержку.

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

Spoiler
public void testSubClassSerializerInvokedForBaseClassFieldsHoldingArrayOfSubClassInstances() {    Gson gson = new GsonBuilder()            .registerTypeAdapter(Base.class, new BaseSerializer())            .registerTypeAdapter(Sub.class, new SubSerializer())            .create();    ClassWithBaseArrayField target = new ClassWithBaseArrayField(new Base[] {new Sub(), new Sub()});    JsonObject json = (JsonObject) gson.toJsonTree(target);    JsonArray array = json.get("base").getAsJsonArray();    for (JsonElement element : array) {        JsonElement serializerKey = element.getAsJsonObject().get(Base.SERIALIZER_KEY);        assertEquals(SubSerializer.NAME, serializerKey.getAsString());    }}

Чтобы достичь желаемого эффекта от тестов, необходимо уделить внимание качеству их дизайна.

Наименование теста и разделение на блоки

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

  • Given настройка SUT и среды;

  • When действие, инициирующее работу SUT, результат работы которой нужно проверить;

  • Then проверка результатов на соответствие ожиданиям.

Пример разделения тела теста:

@Testfun `when create - while has 1 interval from beginning of day and ending not in end of day - should return enabled and disabled items`() {    // given    val intervalStart = createDateTime(BEGINNING_OF_DAY)    val intervalEnd = createDateTime("2019-01-01T18:00:00Z")    val intervals = listOf(        ArchiveInterval(startDate = intervalStart, endDate = intervalEnd)    )    // when    val result = progressItemsfactory.createItemsForIntervalsWithinDay(intervals)    // then    val expected = listOf(        SeekBarProgressItem.createEnabled(intervalStart, intervalEnd),        SeekBarProgressItem.createDisabled(intervalEnd, createDateTime(END_OF_DAY))    )    assertThat(result).isEqualTo(expected)}

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

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

Для тестов на Junit применим следующий паттерн именования в простых случаях:

  • when - should

    when аналогично блоку When;

    should аналогично блоку Then.

В более сложных случаях, когда есть дополнительные условия:

  • when - while/and - should , где

    while предусловие до вызова целевой функции SUT;

    and условие после вызова функции SUT.

Пример:

@Testfun `when doesValueSatisfyRegex - while value is incorrect - should return false`() {

Так имя теста написано в виде требования, и в случае падения будет сразу видно, какой сценарий отработал некорректно:

Фреймворк Spek 2 выводит всё это на новый уровень. Он предоставляет из коробки DSL в стиле Gherkin (BDD).

object GetCameraGroupsInteractorTest : Spek({    Feature("Transform cached cameras to groups of cameras") {        ...        Scenario("subscribe while has non-grouped camera and unsorted by groups order cameras") {            ...            Given("non-grouped camera and unsorted by groups order cameras") {                ...            }            When("subscribe") {                ...            }            Then("should return four groups") {                ...            }            ...        }    }})

Блоки Given, When, Then подтесты глобального теста, описанного с помощью блока Scenario. Теперь нет необходимости ставить всё описание в названии, можно просто расположить все части в соответствующих блоках.

Результат выполнения имеет иерархический вид:

Эти блоки могут присутствовать внутри Scenario в любом количестве, а для придания еще более человекочитаемого вида можно использовать блок And. Теперь насыщенный сценарий можно оформить, не растянув при этом название теста далеко за границу экрана:

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

Чтобы добиться схожего разделения и отображения результатов с помощью Junit 5, понадобилось бы написать в тестах много бойлерплейта с аннотациями.

Устранение лишнего кода

Чтобы сделать содержимое тестов читабельнее, нужно следовать нескольким правилам:

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

В Spek 2 вместо создания полностью отдельных тестов, если они концептуально относятся к одному сценарию, разделение проверок можно сделать с помощью блоков Then/And внутри Scenario:

...Then("should return four groups") {...}And("they should be alphabetically sorted") {...}And("other group should contain one camera") {...}And("other group should be the last") {...}...

В Junit 4 такой возможности нет. На помощь приходит механизм SoftAssertions из AssertJ, который гарантирует выполнение всех assert в тесте. Например:

// thenassertSoftly {    it.assertThat(capabilityState)        .describedAs("Capability state")        .isInstanceOf(Available::class.java)    it.assertThat((capabilityState as Available).disclaimer)        .describedAs("Disclaimer")        .isNull()}

2. Если проверки объемные, нежелательные к разделению и повторяющиеся, следует выносить их в отдельную функцию с говорящим названием.

3. Использовать обобщающие конструкции тестового фреймворка для одинаковой настройки окружения, если настройка повторяется для большого количества тестов, находящихся на одном уровне иерархии (например, beforeEachScenario и afterEachScenario в случае Spek 2). Если настройка одинакова для нескольких тестовых файлов, можно использовать Extension для Junit 5, Rule для Junit 4, а для Spek 2 подобного механизма из коробки нет, поэтому нужно обходиться конструкциями before/after.

4. Объемные схожие настройки тестового окружения следует также выносить в отдельную функцию.

5. Использовать статические импорты для повсеместно применяемых функций вроде функций проверок AssertJ и Mockito.

6. Если создание вспомогательных объектов объемное, используется в разных тестовых файлах и с разными параметрами, следует завести генератор с дефолтными значениями:

Пример генератора
object DeviceGenerator {    fun createDevice(        description: String? = null,        deviceGroups: List<String> = emptyList(),        deviceType: DeviceType = DeviceType.CAMERA,        offset: Int = 0,        id: String = "",        photoUrl: String? = null,        isActive: Boolean = false,        isFavorite: Boolean = false,        isPublic: Boolean = false,        model: String? = null,        vendor: String? = null,        title: String = "",        serialNumber: String = "",        streamData: StreamData? = null    ): Device {        return Device(            description = description,            deviceGroups = deviceGroups,            deviceType = deviceType,            offset = offset,            id = id,            photoUrl = photoUrl,            isActive = isActive,            isFavorite = isFavorite,            isPublic = isPublic,            model = model,            vendor = vendor,            title = title,            serialNumber = serialNumber,            streamData = streamData        )    }}Given("initial favorite camera") {    val devices = listOf(        createDevice(id = deviceId, isFavorite = true)    )    ...}

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

Тесты как документация

Когда предыдущие пункты соблюдены, тесты уже можно применять как документацию, свернув тестовые функции в IDE.

Для сворачивания и разворачивания всех блоков кода в файле в случае Mac используются комбинации клавиш Shift + + - и Shift + + +, для управления конкретным блоком + - и + + соответственно.

В тестах на Junit 4 можно сделать еще лучше, сгруппировав тесты по регионам, ведь их тоже можно сворачивать.

Пример

В тестах на Spek 2 нет нужды делать разделение тестов по регионам, поскольку их можно хорошо сгруппировать с помощью блоков Scenario и Feature.

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

Наконец пример тестов на Spek 2 в режиме документации

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

Она лучше обычной текстовой, поскольку в отличие от тестов, обычную документацию можно забыть актуализировать. Чем тесты более высокоуровневые, тем более близкими к составленным аналитиком функциональным требованиям будут их названия. Это будет заметно в разделе "JVM Integration Testing".

Параметрические тесты

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

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

В документации Spek 2 не написано о возможности написания параметрических тестов, хотя она есть, и писать их проще, чем в Junit 4 и Junit 5. Для этих целей удобно использовать стиль тестов Specification.

Пример параметрического теста в Speck 2
class OrientationTypeTest : Spek({    describe("Orientation type") {        mapOf(            -1 to Unknown,            -239 to Unknown,            361 to Unknown,            2048 to Unknown,            340 to Portrait,            350 to Portrait,            360 to Portrait,            0 to Portrait,            ...        ).forEach { (tiltAngle, expectedOrientation) ->            describe("get orientation by tilt angle $tiltAngle") {                val result = OrientationType.getOrientation(tiltAngle)                it("return $expectedOrientation type") {                    assertThat(result).isEqualTo(expectedOrientation)                }            }        }    }})

Результат выполнения:

Снижение хрупкости non-UI тестов

Я писал, что степень хрупкости unit-тестов при изменениях исходного кода, обусловленную их привязкой к деталям реализации модуля, можно снизить. Это применимо для всех non-UI тестов.

Написание тестов в стиле White box искушает расширять видимость функций/свойств SUT для проверок или установки состояний. Это простой путь, который влечет за собой не только увеличение хрупкости тестов, но и нарушение инкапсуляции SUT.

Избежать этого помогут правила. Можно сказать, что взаимодействие с SUT будет в стиле Black box.

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

  2. Нужно стараться делать функции чистыми. Об этом я говорил выше.

  3. Проверки в тесте следует осуществлять по возвращаемому значению вызываемой публичной функции, публичным свойствам или, в крайнем случае, по взаимодействию с mock-объектами (с помощью функции verify() и механизма ArgumentCaptor в Mockito)

  4. Делать только необходимые проверки в рамках теста. Например, если в тесте проверяется, что при вызове функции A у SUT происходит вызов функции X у другого класса, то не следует до кучи проверять значения её публичных полей, особо не имеющих отношения к делу, и что у SUT не будет более никаких взаимодействий с другими функциями связанного класса (функция verifyNoMoreInteractions() в Mockito).

  5. Если для проведения определенного теста невозможно привести SUT в требуемое предварительное состояние с помощью аргументов целевой функции, моков/стабов или изменения полей, то следует вызвать другие публичные функции, вызов которых приводит SUT в интересующее состояние в условиях реальной работы приложения. Например, вызвать функции onLoginInputChanged и onPasswordInputChanged для подготовки теста onEnterButtonClick во ViewModel

Существует аннотация-маркер @VisibleForTesting для выделения функций/свойств, модификатор доступа которых расширили для тестирования. Благодаря этому маркеру Lint подскажет разработчику, обратившемуся к функции/свойству в таком месте исходного кода, в котором они на самом деле не должны быть доступны, что видимость функции расширена только для тестирования. Несмотря на возможность использования такого маркера, прибегать к расширению видимости всё равно не рекомендуется.

Тестирование асинхронного кода с RxJava

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

Для тестирования SUT, осуществляющей планирование Rx-операций, нужно произвести замену реализаций Scheduler-ов так, чтобы весь код выполнялся в одном потоке. Также важно иметь в виду, что на JVM нельзя использовать AndroidSchedulers.mainThread().

В большинстве случаев все Scheduler-ы достаточно заменить на Schedulers.trampoline(). В случаях, когда нужен больший контроль над временем события, лучше использовать io.reactivex.schedulers.TestScheduler с его функциями triggerActions(), advanceTimeBy(), advanceTimeTo().

Замену реализаций можно совершить двумя способами:

  • RxPlugins (RxJavaPlugins & RxAndroidPlugins);

  • Подход Schedulers Injection.

Первый способ официальный и может быть применен независимо от того, как спроектирована SUT. Он имеет не самое удачное API и неприятные нюансы работы, усложняющие применение в некоторых ситуациях (например, когда внутри тестового файла в одних тестах нужно использовать Schedulers.trampoline(), а в других TestScheduler).

Суть подхода Schedulers Injection заключается в следующем: экземпляры Scheduler-ов попадают в SUT через конструктор, благодаря чему в тесте они могут быть заменены на иные реализации. Этот подход является очень прозрачным и гибким. Также он останется неизменным независимо от выбранного тестового фреймворка (Junit 4, Junit 5, Spek 2) чего нельзя сказать об RxPlugins, которыми придется в каждом управлять по-своему.

Из минусов Shedulers Injection можно выделить необходимость внедрения дополнительного аргумента в SUT и необходимость использования вместо rx-операторов с Sheduler по умолчанию (таких как delay()) их перегруженные варианты с явным указанием Scheduler.

Есть две неплохие статьи на тему обоих подходов: раз, два. Но там упомянуты не все нюансы RxPlugins.

Я предпочитаю второй подход. Чтобы упростить внедрение и подмену реализаций в тесте, я написал SchedulersProvider:

Реализация и применение SchedulersProvider
interface SchedulersProvider {    fun ui(): Scheduler    fun io(): Scheduler    fun computation(): Scheduler}class SchedulersProviderImpl @Inject constructor() : SchedulersProvider {    override fun ui(): Scheduler = AndroidSchedulers.mainThread()    override fun io(): Scheduler = Schedulers.io()    override fun computation(): Scheduler = Schedulers.computation()}fun <T> Single<T>.scheduleIoToUi(schedulers: SchedulersProvider): Single<T> {    return subscribeOn(schedulers.io()).observeOn(schedulers.ui())}// другие необходимые функции-расширения...

Его применение в коде:

class AuthViewModel(    ...    private val schedulers: SchedulersProvider) : BaseViewModel() {    ...    loginInteractor        .invoke(login, password)        .scheduleIoToUi(schedulers)    ...

А вот и его тестовая реализация с Scheduler-ами по умолчанию, вместо которых при надобности можно передать TestScheduler:

class TestSchedulersProvider(    private val backgroundScheduler: Scheduler = Schedulers.trampoline(),    private val uiScheduler: Scheduler = Schedulers.trampoline()) : SchedulersProvider {    override fun ui(): Scheduler = uiScheduler    override fun io(): Scheduler = backgroundScheduler    override fun computation(): Scheduler = backgroundScheduler}

Применение в тесте:

authViewModel = AuthViewModel(    ...    router = mock(),    schedulers = TestSchedulersProvider(),    loginInteractor = loginInteractor,    ...)

Вообще, RxJava из коробки имеет и другие полезные инструменты для тестирования (TestObserver, TestSubscriber), но они не входят в рамки статьи.

JVM Integration Testing

JVM Integration-тесты проверяют взаимодействие модулей или совокупностей модулей на JVM. Какие именно связки стоит тестировать, зависит от конкретных случаев.

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

Тест взаимодействует с SUT через ViewModel, инициируя действия и проверяя результат.

Чтобы достичь максимальной степени проверки SUT в данном случае следует заменять тестовыми реализациями только те сущности, которые действительно в этом нуждаются. Типичный набор таких сущностей:

  • android.content.res.Resources или собственный Wrapper. Обычно достаточно стаба, обеспечивающего исправный возврат строк из ресурсов.

  • androidx.arch.core.executor.TaskExecutor. Требуется в любых тестах на JVM, у которых SUT использует LiveData, поскольку стандартная реализация имеет Android-зависимость. Подробнее можно почитать в этой статье. Google предлагает готовое решение этой проблемы в форме Rule лишь для Junit 4, поэтому для Spek 2 и Junit 5 использую рукописный класс, содержащий код из того самого решения:

object TestLiveDataExecutionController {    fun enableTestMode() {        ArchTaskExecutor.getInstance()            .setDelegate(object : TaskExecutor() {                override fun executeOnDiskIO(runnable: Runnable) = runnable.run()                override fun postToMainThread(runnable: Runnable) = runnable.run()                override fun isMainThread(): Boolean = true            })    }    fun disableTestMode() {        ArchTaskExecutor.getInstance().setDelegate(null)    }}

Соответствующие функции достаточно вызывать перед первым и после последнего теста в тестовом файле. Пример применения в Spek 2:

object DeviceDetailViewModelIntegrationTest : Spek({    beforeGroup { TestLiveDataExecutionController.enableTestMode() }    afterGroup { TestLiveDataExecutionController.disableTestMode() }...
  • Сервер. Для имитации сервера используется MockWebServer от создателей OkHttp. Он позволяет предустанавливать ответы на конкретные запросы, проверять состав запросов, факты их вызова и др.

  • Interceptors с Android-зависимостями. Не следует пренебрегать добавлением интерцепторов в тестовую конфигурацию клиента OkHttp, соблюдая тот же порядок, что и в настоящем клиенте, чтобы серверные запросы и ответы правильно обрабатывались. Однако некоторые интерцепторы могут иметь Android-зависимости их следует подменить. Например, это могут быть интерцепторы логирования. Интерцепторы последовательно передают данные друг другу и эту цепочку нельзя прерывать, поэтому фиктивный интерцептор должен выполнять это минимальное требование:

// StubInterceptorInterceptor { chain ->    return@Interceptor chain.proceed(chain.request().newBuilder().build())}
  • Персистентные хранилища данных (SharedPreferences, Room и т.д.)

Базовая логика управления тестовым сетевым окружением сконцентрирована в классе BaseTestNetworkEnvironment. Он используется на JVM и в Instrumentation. За специфическую конфигурацию под каждую из сред отвечают его классы-наследники: JvmTestNetworkEnvironment и InstrumentationTestNetworkEnvironment.

Сервер запускается при создании экземпляра *NetworkEnvironment до запуска теста и отключается функцией shutdownServer() после завершения теста (в случае Gherkin-стиля Spek 2 до и после Scenario соответственно).

Для удобной настройки ответов на конкретные запросы используется функция dispatchResponses. При необходимости к mockServer можно обратиться напрямую.

Реализация BaseTestNetworkEnvironment
abstract class BaseTestNetworkEnvironment {    companion object {        private const val BASE_URL = "/"        private const val ENDPOINT_TITLE = "Mock server"    }    val mockServer: MockWebServer = MockWebServer().also {         it.startSilently()     }    // класс, специфичный для инфраструктуры проекта    protected val mockNetworkConfig: NetworkConfig    init {        val mockWebServerUrl = mockServer.url(BASE_URL).toString()        mockNetworkConfig = TestNetworkConfigFactory.create(mockWebServerUrl, BASE_URL)    }    /**     * Используется для предустановки фиктивных ответов на конкретные запросы к [MockWebServer].     *     * [pathAndResponsePairs] пара путь запроса - ответ на запрос.     *     * Если [MockWebServer] получит запрос по пути, которого нет среди ключей [pathAndResponsePairs],     * то будет возвращена ошибка [HttpURLConnection.HTTP_NOT_FOUND].     */    fun dispatchResponses(vararg pathAndResponsePairs: Pair<String, MockResponse>) {        val pathAndResponseMap = pathAndResponsePairs.toMap()        val dispatcher = object : Dispatcher() {            override fun dispatch(request: RecordedRequest): MockResponse {                val mockResponse = request.path?.let {                   pathAndResponseMap[it]                 }                return mockResponse ?: mockResponse(HttpURLConnection.HTTP_NOT_FOUND)            }        }        mockServer.dispatcher = dispatcher    }    fun shutdownServer() {        mockServer.shutdown()    }    /**     * Запуск сервера с отключенными логами     */    private fun MockWebServer.startSilently() {        Logger.getLogger(this::class.java.name).level = Level.WARNING        start()    }}

Содержимое JvmTestNetworkEnvironment уже сильно зависит от специфики конкретного проекта, но цель его неизменна заменить некоторые сущности локального сетевого окружения тестовыми дублерами, чтобы код работал на JVM.

Пример реализации JvmTestNetworkEnvironment
// Если не передавать в конструктор класса специфические экземпляры тестовых дублеров, то будут использоваться// стабы с минимальным предустановленным поведением, необходимым для функционирования сетевого флоу.class JvmTestNetworkEnvironment(    val mockPersistentStorage: PersistentStorage = mockPersistentStorageWithMockedAccessToken(),    val mockResources: ResourceProvider = TestResourceProvider()) : BaseTestNetworkEnvironment() {    private val nonAuthZoneApiHolderProvider: NonAuthZoneApiHolderProvider    private val authZoneApiHolderProvider: AuthZoneApiHolderProvider    init {        val moshiFactory = MoshiFactory()        val serverErrorConverter = ServerErrorConverter(moshiFactory, mockResources)        val stubInterceptorProvider = StubInterceptorProvider()        val interceptorFactory = InterceptorFactory(            ErrorInterceptorProvider(serverErrorConverter).get(),            AuthInterceptorProvider(mockPersistentStorage).get(),            stubInterceptorProvider.get(),            stubInterceptorProvider.get()        )        nonAuthZoneApiHolderProvider = NonAuthZoneApiHolderProvider(            interceptorFactory,            moshiFactory,            mockNetworkConfig        )        authZoneApiHolderProvider = AuthZoneApiHolderProvider(            interceptorFactory,            moshiFactory,            UserAuthenticator(),            mockNetworkConfig        )    }    fun provideNonAuthZoneApiHolder() = nonAuthZoneApiHolderProvider.get()    fun provideAuthZoneApiHolder() = authZoneApiHolderProvider.get()}

Функции для упрощения создания серверных ответов:

fun mockResponse(code: Int, body: String): MockResponse = MockResponse().setResponseCode(code).setBody(body)fun mockResponse(code: Int): MockResponse = MockResponse().setResponseCode(code)fun mockSuccessResponse(body: String): MockResponse = MockResponse().setBody(body)

Тела фиктивных серверных ответов сгруппированы по object-ам, соответствующим разным запросам. Это делает тестовые файлы чище и позволяет переиспользовать ответы и значения их полей в разных тестах. Одни и те же ответы используются тестами на JVM и Instrumentation (в том числе UI).

После добавления комментария "language=JSON" IDE подсвечивает синтаксис JSON. Подробнее о Language injections можно почитать тут.

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

Пример object с фиктивными серверными ответами
object LoginResponses {    const val INVALID_CREDENTIALS_ERROR_DESCRIPTION = "Неверный логин или пароль"        fun invalidCredentialsErrorJson(        errorDescription: String = INVALID_CREDENTIALS_ERROR_DESCRIPTION    ): String {        // language=JSON        return """            {              "error": {                "code": "invalid_credentials",                "description": "$errorDescription",                "title": "Введены неверные данные"              }            }            """.trimIndent()    }...}

Схожим образом вынесены и пути запросов:

const val LOGIN_REQUEST_PATH = "/auth/login"object GetCameraRequest {    const val DEVICE_ID = "1337"    const val GET_CAMERA_REQUEST_PATH = "/devices/camera/$DEVICE_ID"}...

Общие для JVM и Instrumentation файлы должны находиться в директории, доступной обоим окружениям. Доступ настраивается в build.gradle:

android {    sourceSets {        // Instrumentation        androidTest {            java.srcDirs += 'src/androidTest/kotlin'            java.srcDirs += 'src/commonTest/kotlin'        }        // JVM        test {            java.srcDirs += 'src/test/kotlin'            java.srcDirs += 'src/commonTest/kotlin'        }    }}

Взаимодействие View и ViewModel построено особым способом, благодаря которому очень удобно писать unit-тесты ViewModel и integration-тесты. Публичные функции ViewModel представляют события со стороны View (обычно они соответствуют действиям со стороны пользователя) и именуются в событийном стиле:

ViewModel воздействует на View посредством двух LiveData:

  • state описание состояния View

  • events однократные события, не сохраняющиеся в state

Этот подход в более удобном виде реализован в нашей библиотеке.

Пример организации ViewModel, ViewState и ViewEvents
class AuthViewModel(...) {    val state = MutableLiveData<AuthViewState>()    val events = EventsQueue<ViewEvent>()    ...}sealed class AuthViewState {    object Loading : AuthViewState()    data class Content(        val login: String = "",        val password: String = "",        val loginFieldState: InputFieldState = Default,        val passwordFieldState: InputFieldState = Default,        val enterButtonState: EnterButtonState = Disabled    ) : AuthViewState() {        sealed class InputFieldState {            object Default : InputFieldState()            object Error : InputFieldState()            object Blocked : InputFieldState()        }...    }}class EventsQueue<T> : MutableLiveData<Queue<T>>() {    fun onNext(value: T) {        val events = getValue() ?: LinkedList()        events.add(value)        setValue(events)    }}// ViewEvents:interface ViewEventdata class ShowSnackbarError(val message: String) : ViewEventclass OpenPlayStoreApp : ViewEvent...
Наконец, пример JVM Integration-теста
object AuthViewModelIntegrationTest : Spek({    Feature("Login") {        // region Fields and functions        lateinit var authViewModel: AuthViewModel        lateinit var networkEnvironment: JvmTestNetworkEnvironment        val login = "log"        val password = "pass"        fun setUpServerScenario() {            networkEnvironment = JvmTestNetworkEnvironment()            val authRepository = networkEnvironment.let {                AuthRepositoryImpl(                    nonAuthApi = it.provideNonAuthZoneApiHolder(),                    authApi = it.provideAuthZoneApiHolder(),                    persistentStorage = it.mockPersistentStorage,                    inMemoryStorage = InMemoryStorage()                )            }            val clientInfo = ClientInfo(...)            val loginInteractor = LoginInteractor(authRepository, clientInfo)            authViewModel = AuthViewModel(                resources = networkEnvironment.mockResources,                schedulers = TestSchedulersProvider(),                loginInteractor = loginInteractor                analytics = mock()            )        }        beforeFeature { TestLiveDataExecutionController.enableTestMode() }        afterFeature { TestLiveDataExecutionController.disableTestMode() }        beforeEachScenario { setUpServerScenario() }        afterEachScenario { networkEnvironment.shutdownServer() }        // endregion        Scenario("input credentials") {...}        Scenario("click enter button and receive invalid_credentials error from server") {            Given("invalid_credentials error on server") {                networkEnvironment.dispatchResponses(                    LOGIN_REQUEST_PATH to mockResponse(HTTP_UNAUTHORIZED, invalidCredentialsErrorJson())                )            }            When("enter not blank credentials") {                authViewModel.onCredentialsChanged(login, password)            }            And("click enter button") {                authViewModel.onEnterButtonClick(login, password)            }            Then("reset password, mark login and password input fields as invalid and disable enter button") {                val state = authViewModel.state.value                val expectedState = Content(                    login = login,                    password = "",                    loginFieldState = Content.InputFieldState.Error,                    passwordFieldState = Content.InputFieldState.Error,                    enterButtonState = Content.EnterButtonState.Disabled                )                assertThat(state).isEqualTo(expectedState)            }            And("create snackbar error event with message from server") {                val expectedEvent = authViewModel.events.value!!.peek()                assertThat(expectedEvent).isEqualTo(ShowSnackbarError(INVALID_CREDENTIALS_ERROR_DESCRIPTION))            }        }        ...    }    ...})

Так тестируется основная логика пользовательских сценариев. Эти сценарии с теми же данными затем могут быть проверены в UI-тестах.

Что в итоге нужно тестировать?

Не нужно тестировать чужие библиотеки это ответственность разработчиков библиотек (исследовательское тестирование исключение). Тестировать нужно свой код.

Unit-тесты следует писать на логику, в которой есть реальная вероятность совершения ошибки. Это могут быть ViewModel, Interactor, Repository, функции форматирования (денег, дат и т.д.) и другие стандартные и нестандартные сущности. Тривиальную логику тестировать не стоит. Но нужно следить за изменением непокрытой тестами логики, если она при очередном изменении перестанет быть тривиальной, то тогда её нужно протестировать.

100%-е покрытие кода тестами несёт с собой вред: трата лишнего времени на написание бесполезных тестов, боль при изменении реализации, при поддержке бесполезных тестов, иллюзия хорошо протестированной системы. Процент покрытия не отражает реальной картины того, насколько хорошо система протестирована.

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

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

При исправлении бага в коде, который не покрыт тестами, следует его ими покрыть.

JVM Integration-тесты от ViewModel до слоя данных следует писать для каждого экрана. Менее масштабные JVM Integration при надобности. Возможны случаи, когда большинство модулей, включая ViewModel, сами по себе являются слишком простыми, чтобы их стоило покрывать unit-тестами. Однако создание масштабного JVM integration-теста на всю цепочку будет очень кстати, тем более что пишутся такие тесты достаточно просто и однотипно.

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

Тесты Instrumentation Integration non-UI только когда нужно проверить что-то, что нельзя адекватно проверить на JVM.

E2E UI- и Component UI-тесты нужны для замены части ручных тестов при регрессионном тестировании. Разумно доверить их написание QA-инженерам. В настоящее время мы с коллегами ищем оптимальный подход к тому, как организовывать UI-тесты, в каком количестве их писать и как сочетать с более низкоуровневыми тестами.

Test Driven Development

Можно подумать, что о написании тестов уже известно достаточно и пора идти в бой, но есть еще один момент Вы, вероятно, собрались написать очередную фичу и затем покрыть её тестами? Замечательная идея. Именно так и стоит делать, пока навык написания тестов не будет более менее отработан. Такой подход называют Test Last. Конечно же, среди пишущих тесты разработчиков он наиболее распространен. Но он имеет серьезные недостатки:

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

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

  • тесты остаются на последнюю очередь и на них зачастую не остается времени.

Решить эти проблемы можно, используя принцип Test First, придуманным Кентом Беком. Он основан на идее: "Never write a single line of code unless you have a failing automated test" (не стоит писать код реализации, пока для него не написан падающий тест).

На базе этого принципа Кент Бек создал методологию Test Driven Development (TDD, разработка через тестирование). Согласно ей, разработка должна вестись итеративно, путем цикличного повторения шагов Red-Green-Refactor (микро-цикл):

  • написать тест на логику, которую предстоит реализовать, и убедиться, что он падает;

  • написать простейшую реализацию, чтобы тест выполнился успешно;

  • провести рефакторинг реализации, не сломав тесты.

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

Позже Роберт Мартин развил TDD, сформулировав Three Laws of TDD (нано-цикл):

  • перед написанием какого-либо кода реализации необходимо написать падающий тест;

  • тест не должен содержать больше, чем нужно для его падения или провала компиляции;

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

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

Со временем Робертом были сформулированы еще два более масштабных цикла. Про всех них можно почитать в его статье.

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

Я несколько отступился от канонов и нашел эффективным такой алгоритм работы при реализации новой фичи:

1. Вникнуть в задачу, спроектировать связи между модулями, определить их ответственность.

2. Создать SUT, описать его интерфейс.

  • Если функции должны возвращать какой-то результат, можно писать в их теле TODO(), чтобы код мог скомпилироваться, тогда при вызове функции тест будет прерван эксепшеном. Другой вариант хардкодить возврат простого объекта или null. Так тесты смогут совершить проверки после вызова функции, но тут лучше быть поаккуратнее.

fun doSomething(): Boolean { TODO() }

3. Создать тестовый файл для SUT, объявить тесты-требования.

  • Описать столько кейсов, сколько получится. Нормально, если в ходе написания реализации на ум придут еще какие-то кейсы.

    В пустые тесты/блоки можно добавлять вызов функции fail() (из Junit или AssertJ), чтобы не забыть реализовать какой-то из тестов, поскольку пустой тест при запуске выдает положительный результат.

@Testfun `when invoke - should do something`() {    fail { "not implemented" }}

4. Реализовать тест(ы)

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

5. Реализовать SUT, чтобы реализованные тесты успешно выполнились.

  • По умолчанию в момент времени стоит фокусироваться на прохождении одного конкретного теста.

6. Отрефакторить SUT, сохранив успешность выполнения реализованных тестов.

7. Если остались нереализованные тесты, перейти к пункту #4.

Алгоритм доработки SUT, которая уже покрыта тестами:

  1. Объявить новые тесты согласно новым требованиям,

  2. Реализовать новые тесты,

  3. Реализовать доработку в SUT, чтобы новые тесты выполнились успешно

  4. Если старые тесты упали:

    • Они актуальны при новых требованиях исправить реализацию SUT и/или эти тесты,

    • Они неактуальны удалить.

  5. Отрефакторить SUT, сохранив успешность выполнения реализованных тестов,

  6. Если остались нереализованные тесты, перейти к пункту 2.

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

Приступаем к реализации по принципу Test Last, но как только достаточное представление сформируется, делаем паузу и переходим к тестам, продолжая дальнейшую разработку уже по TDD. Незачем также применять TDD для реализации тривиальной логики, если вы не собираетесь покрывать её тестами.

По итогу получаем от подхода следующие преимущества:

  • Предварительное написание тестов вынуждает реализовывать SUT заведомо тестируемой. Тесты оказываются слабо связанными с деталями реализации.

  • Тесты являются спецификацией SUT (если при этом соблюдать правила их именования). Часто они вытекают напрямую из функциональных требований к задаче. Сфокусированное перечисление тестов-требований до начала реализации помогает лучше понять и запомнить требования, лучше продумать детали интерфейса SUT. Увеличивается вероятность заблаговременного выявления всех необходимых краевых кейсов. Это само по себе уже помогает допускать меньше ошибок в будущей реализации, а возможность запуска готовых тестов в любой момент дает уверенность в том, что реализация осуществляется правильно.

  • Наличие тестов делает рефакторинг реализации безопасным. После каждого изменения реализации можно быстро прогнать все тесты SUT и в случае обнаружения поломки сразу же её устранить. Время, затрачиваемое на отладку, очень сильно сокращается.

  • На тесты хватает времени, ведь они неотъемлемая часть процесса разработки

  • Все эти факторы в совокупности сокращают время, затрачиваемое на разработку и на развитие приложения в будущем.

  • Приятно видеть, как красные тесты один за другим превращаются в зелёные

TDD это в первую очередь подход к разработке. Методология замечательно показывает себя при реализации SUT с unit- и JVM integration-тестами, поскольку их можно быстро и часто запускать. С Instrumentation non-UI-тестами применять её можно, но из-за длительности запуска придется запускать тесты реже. Применять же TDD с UI-тестами крайне не рекомендуется.

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

Заключение

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

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

Можно извлекать существенную пользу за счет применения TDD с тестами на JVM. Применять его следует не всегда. Разработчику нужно самостоятельно подобрать комфортный размер шага в цикле разработки по TDD.

Полезные материалы

Подробнее..

Java Core для самых маленьких. Часть 1. Подготовка и первая программа

11.02.2021 22:07:58 | Автор: admin

Вступление. Краткая история и особенности языка.

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

Начало разработки языка было положено еще в 1991 году компанией Sun Microsystems, Inc. Вначале язык был назван Oak (Дуб), но в 1995 он был переименован в Java. Публично заявили о создании языка в 1995 году. Причиной создания была потребность в независящем от платформы и архитектуры процессора языке, который можно было бы использовать для написания программ для бытовой электротехники. Но поскольку в таких устройствах применялись различные процессоры, то использование популярных на то время языков С/С++ и прочих было затруднено, поскольку написанные на них программы должны компилироваться отдельно для конкретной платформы.

Особенностью Java, которая решила эту проблему, стало то, что компилятор Java выдает не машинный исполняемый код, а байт-код - оптимизированный набор инструкций, которые выполняются в так называемой виртуальной машин Java (JVM - Java Virtual Machine). А на соответствующую платформу предварительно устанавливается JVM с необходимой реализацией, способная правильно интерпретировать один и тот же байт-код. У такого подхода есть и слабые стороны, такие программы выполняются медленнее, чем если бы они были скомпилированы в исполняемый код.

Установка программного обеспечения - JDK

В первую очередь, нам нужно установить на компьютер так называемую JDK (Java Development Kit) - это установочный комплект разработчика, который содержит в себе компилятор для этого языка и стандартные библиотеки, а виртуальную машинуJava (JVM) для вашей ОС.

Для того чтобы скачать и установить JDK открываем браузер, и в строке поиска Google вводим download JDK или переходим по этой ссылке.

Скролим ниже и находим таблицу с вариантами скачивания JDK. В зависимости от нашей операционной системы выбираем файл для скачивания.

Процесс установки для ОС Windows имеет несколько этапов. Не стоит пугаться, все очень просто и делается в несколько кликов. Вот здесь подробно описан процесс установки. Самое важное для пользователей Windows это добавить системную переменную JAVA_HOME. В этой же статье достаточно подробно расписано как это сделать (есть даже картинки).

Для пользователей MacOS также стоит добавить переменную JAVA_HOME. Делается это следующим образом. После установки .dmg файла JDK переходим в корневую папку текущего пользователя и находим файл .bash_profile. Если у вас уже стоит zsh то ищем файл .zshenv. Открываем этот файл на редактирование и добавляем следующие строки:

export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_271.jdk/Contents/Homeexport PATH=${PATH}:${JAVA_HOME}

Здесь обратите внимание на версию JDK указанную в пути - jdk1.8.0_271.jdk. Могу предположить, что у вас она будет отличаться, поэтому пройдите по указанному пути и укажите свою версию. Сохраняем изменения и закрываем файл, он нам больше не понадобится.

Теперь важно проверить правильность установки JDK. Для этого открываем командную строку, в случае работы на Windows, или терминал для MacOS. Вводим следующую команду: java -version Если вы все сделали правильно, вы увидите версию установленного JDK. В ином случае вы, скорее всего, допустили где-то ошибку. Советую внимательно пройтись по всем этапам установки.

Установка IDE

Теперь нам нужно установить среду разработки, она же IDE (Integrated development environment). Что собой представляет среда разработки? На самом деле она выглядит как текстовый редактор, в котором мы можем вводить и редактировать текст. Но помимо этого, этот текстовый редактор умеет делать проверку синтаксиса языка на котором вы пишете. Делается это для того чтобы на раннем этапе подсказать вам о том, что вы допустили ошибку в своем коде.

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

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

Для начала нам нужно выбрать и среду разработки. Их довольно таки много, и самыми популярными из них являются: IntelliJ IDEA, NetBeans, Eclipse. Для себя я выбираю IntelliJ IDEA. Она является самой удобной на мой взгляд, и хоть она и платная, на официальном сайте можно найти бесплатную версию которая называется Community. Этой версии будет вполне достаточно для изучения основ Java. Вообщем будем работать в IntelliJ IDEA.

Итак, открываем браузер, в поисковой строке вводим "Download IntelliJ IDEA Community" или переходим по этой ссылке. Выбираем версию ОС и качаем версию Community.

В установке IntelliJ IDEA нет ничего военного. На крайний случай на ютубе есть множество видео о том, как установить эту программу.

Первая программа

Теперь мы готовы создать нашу первую программу. В окошке запустившийся IDE нажимаем New Project.

В новом окошке в левой панели выбираем Java.

Обратите внимание! В верхнем окошке, справа, возле надписи "Project SDK:" должна находится версия Java, которую вы установили вместе с JDK. Если там пусто, то вам нужно будет указать путь к вашему JDK вручную. Для этого в выпадающем списке нажмите "Add JDK..." и укажите путь к вашему JDK, который был предварительно установлен.

Теперь можем нажать на кнопку Next. В следующем окошке, вверху, поставьте галочку Create project from template и выберите Command Line App. И снова нажимаем Next.

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

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

После указываем путь к проекту программы.

Далее, нам нужно указать базовый пакет нашей программы. О пакетах я расскажу вам позже, обычно компании используют свое имя Интернет-домена в обратном порядке, но вы можете написать, например, свои имя и фамилию через точку в нижнем регистре (маленькими буквами), тоже латиницей. Я же использую псевдоним. Когда все поля будут заполнены - нажимаем Finish.

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

Это окно, то что вы будете видеть 80-90%, а иногда и 100% времени, работая программистом.

Для того чтобы закончить ваше первое приложение, останется добавить строчку кода System.out.print("Hello world!"); как показано на скриншоте.

Чтобы скомпилировать и запустить на выполнение вашу программу, вам нужно нажать кнопочку с зеленым треугольничком на верхней панели справа, или в меню найти пункт Run -> Run Main. И внизу на нижней панели, под окном редактора, в консоли, вы увидите результат выполнения вашей программы. Вы увидите надпись Hello World! Поздравляю, вы написали свою первую программу на Java.

Разбираем первую программу

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

Пройдемся по порядку:

В начале мы видим package com.zephyr.ventum; - это объявление пакета, и это постоянный атрибут файлов с исходным кодом в Java. Простыми словами, это локация вашего файла в проекте и любой .java файл должен начинаться с подобной строки.

Ниже, public class Main { - это стандартное объявление класса в Java, где public - это модификатор доступа который дает программисту возможность управлять видимостью членов класса, class - является ключевым словом объявляющим класс, Main - это имя класса. Все определение класса и его членов должно располагаться между фигурными скобками { }. Классы мы рассмотрим немного позже, только скажу что в Java все действия программы выполняются только в пределах класса.

Ключевое слово - это слово зарезервированное языком программирования. Например, package - это тоже ключевое слово.

Еще ниже, public static void main(String[] args) { - эта строка является объявлением метода main. Метод (или часто говорят функция) main это точка входа в любой java-программер. Именно отсюда начинается выполнение вашего кода. В проекте может быть несколько методов main, но мы должны выбрать какой-то один для запуска нашей программы. В следующих статьях мы еще вернемся к этому. Сейчас же у нас только один метод main.

Фигурные скобки {} у метода main обозначаю начало и конец тела метода, весь код метода должен располагаться между этими скобками. Аналогичные скобки есть и у класса Main.

Следующая строка является // write your code here однострочным комментарием.

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

Многострочный комментарий будет выглядеть следующим образом:

/* write  your  code here */

Мы просто располагаем несколько строк между символами /* и */

System.out.print("Hello world!"); - строка которая находится внутри метода main является командой, которая выводит в консоль строку "Hello world!"

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

Затем мы закрываем тело нашего метода main } а также закрываем класс Main }.

На этом статья подходит к концу. Автором конкретно этого материала является Егор и все уменьшительно ласкательные формы слов сохранились в первозданном виде.

В следующей статье мы поговорим о типах данных в Java.

Подробнее..

Java Core для самых маленьких. Часть 2. Типы данных

15.02.2021 14:04:42 | Автор: admin

Вступление

В этой статье мы не будем использовать ранее установленную IDE и JDK. Однако не беспокойтесь, ваш труд не был напрасным. Уже в следующей статье мы будет изучать переменные в Java и активно кодить в IDEA. Эта же статья является обязательным этапом. И в начале вашего обучения вы, возможно, будете не раз к ней возвращаться.

1998 - пин-код от моей кредитки является ничем иным как числом. По-крайней мере для нас - для людей. 36,5 - температура, которую показывают все термометры в разных ТРЦ. Для нас это дробное число или число с плавающей запятой. "Java Core для самых маленьких" - а это название данной серии статей, и мы воспринимает это как текст. Так к чему же я веду. А к тому, что Джаве (так правильно произносить, на тот случай если кто-то произносит "ява"), как и человеку, нужно понимать с чем она имеет дело. С каким типом данных предстоит работать.

Фанаты матрицы и, надеюсь, остальные читатели знают, что на низком уровне, вся информация в ЭВМ представлена в виде набора нулей и единиц. А вот у человеков, на более высоком уровне, есть высокоуровневые языки программирования. Они не требуют работы с нулями и единицами, предоставляя возможность писать код понятный для людей. Одним из таких языков программирование и является Java. Мало того, Java - это строго-типизированный язык программирования. А еще бывают языки с динамической типизацией данных (например Java Script). Но мы здесь учим нормальный язык программирования, поэтому не будем отвлекаться.

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

Примитивы

В языке Java существует 8, оскорбленных сообществом, примитивных типов данных. Их также называют простыми. И вот какие они бывают:

  • Целые числа со знаком: byte, short, int, long;

  • Числа с плавающей точкой: float, double;

  • Символы: char;

  • Логические значения: boolean.

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

Тип byte

Является наименьшим из целочисленных. 8-разрядный тип данных c диапазоном значений от -2^7 до 2^7-1. Или простыми словами может хранить значения от -128 до 128. Используется для работы с потоками ввода-вывода данных, эта тема будет рассмотрена позже.

Тип short

16-разрядный тип данных в диапазоне от -2^15 до 2^15-1. Может хранить значения от -32768 до 32767. Самый редко применяемый тип данных.

Тип int

Наиболее часто употребляемый тип данных. Содержит 32 разряда и помещает числа в диапазоне от -2^31 до 2^31-1. Другими словами может хранить значения от -2147483648 до 2147483647.

Тип long

64-разрядный целочисленный тип данных с диапазоном от -2^63 до 2^63-1. Может хранить значения от -9223372036854775808 до 9223372036854775807. Удобен при работе с большими целыми числами.

Используются при точных вычислениях, которые требуют результата с точностью до определенного знака после десятичной точки (вычисление квадратного корня, функции синуса или косинуса и прочего).

Тип float

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

Тип double

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

Тип char

16-разрядный тип данных в диапазоне от 0 до 2^16. Хранит значения от 0 до 65536. Этот тип может хранить в себе полный набор международных символов на всех известных языках мира (кодировка Unicode). То есть по сути каждый символ представляет из себя какое-то число. А тип данных char позволяет понять, что это число является символом.

Тип boolean

Может принимать только 2 значения true или false. Употребляется в условных выражениях, к примеру 1 > 10 вернет false, а 1 < 10 - true.

На этом примитивные типы данных в Java закончились. В следующей статье мы будем объявлять переменные конкретного типа данных. Поговорим о том, что такое литералы. А еще узнаем, что такое приведение типов данных. Вообщем следующая статья будет очень насыщенной и познавательной!

Подробнее..

Гайд начинающего тимлида

26.05.2021 16:17:30 | Автор: admin

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

Всё это я проговаривал на вебинаре в Хекслете тут https://www.youtube.com/watch?v=y_HkXvFovAc

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

Общий стаж моей работы в ИТ - около 14 лет. Я начинал с системного администрирования, потом перешел в разработку, поработав как в аутсорсе, так и в продукте. Несколько раз проходил путь от стажера/джуниора до тимлида.

Шаг номер 0. Зачем?

Итак, вам предложили стать тимлидом или вы сами захотели им стать. Что надо сделать в первую очередь?Хорошенько подумать, а надо ли оно вам.

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

Я общался с многими состоявшимися специалистами в этой профессии и все они говорят примерно одно и то же:

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

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

Ложные цели, на которые не надо вестись:

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

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

  • Повышение уровня ЧСВ. Ничего особо крутого в этой должности нет. Это просто очередная должность чуть выше рядовой. Как ефрейтор или сержант в армии. Вроде лычка есть, но хвалиться особо нечем, и вокруг куча таких же.

Второе, на что надо обратить внимание при рассмотрении данной должности: тимлиды бывают разные.

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

Советую заранее узнать, что же именно от вас требуется.

Спойлер: 80-90% вакансий на российском рынке -полуменеджер-полуразработчик. Формально говорится, что 60-70% времени надо писать код, а 30-40% менеджерить. При небольших размерах команды и порядочном работодателе это может неплохо работать. Лично у меня где-то сейчас 40 на 60 получается делить код с менеджементом. Хотя я чувствую, как при разрастании команды код отодвигается от меня всё дальше и дальше.

Однако при недобросовестном или просто непонимающем работодателе, от вас будут ожидать примерно 100% менеджмента и 100% написания кода. Постарайтесь узнать об этом как можно раньше, чтобы СБЕЖАТЬ.

Шаг номер 1. Знание - сила!

Если вы всё же согласились на данную позицию, то следующее (а в идеале и заранее), что надо сделать - ознакомиться с полезной информацией на эту тему.

Про тимлидство существуют сотни статей, видео, книг, курсов и т.д. Фильтровать нужно тщательно.

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

  • М. Уоткинс "Первые 90 дней".Хорошая и вдумчивая книга о том, как успешно адаптироваться к переходу на новую должность.Чем заняться в первые 90 дней.И о том, что эта адаптация, как системный процесс, нужна не просто конкретному индивиду, а всей компании в целом.

  • Дж. Ханк Рейнвотер "Как пасти котов". Книга для начинающих или будущих управленцев вполне хороша и толкова (пусть и немного стара). Однако для людей с опытом, наверное, будет немного кэпской.

  • Ф. Брукс "Мифический человеко-месяц".Расскажет об управлении проектами: как надо, как не надо, и почему 9 женщин за 1 месяц не смогут родить ребенка. Есть мнение, что книга несколько устарела, тем не менее, если вы в этом не очень разбираетесь, то она обогатит вас полезными идеями.

  • Э. Голдратт. "Цель. Процесс непрерывного совершенствования".Классический художественный роман, объясняющий на разных примерах теорию ограничения систем. Чтиво интересное и полезное.

  • Д. Ким, К. Бер, Д. Спаффорд."Проект "Феникс". Роман о том, как DevOps меняет бизнес к лучшему".Очень интересная и поучительная книга, которая в художественном формате рассказывает о том, как в ИТ подразделении улучшают процессы работы, приходят к DevOps идеологии и спасают бизнес.

  • Т. ДеМарко "Deadline. Роман об управлении проектами". Еще одна книга в художественном формате. Легкое и интересное чтение об управлении ИТ проектами.

  • Т. ДеМарко, Т. Листер "Вальсируя с Медведями".Порекомендовал бы эту книгу для средних и крупных проектов. Излечивает от наивности, открывает глаза на происходящее. Показывает, что случиться может много чего и рассказывает, как с этим жить и работать.

  • М. Дорофеев "Джедайские техники. Как воспитать свою обезьяну, опустошить инбокс и сберечь мыслетопливо".Книга не про программирование, но программистам, тимлидам, менеджерам точно пойдёт на пользу. Очень толковая книга по личной эффективности, организации задач и т.п.Всем настойчиво рекомендую.

  • М. Ильяхов, Л. Сарычева "Новые правила деловой переписки".Замечательная книга. Смело её рекомендовал бы и разработчикам, и менеджерам, и вообще примерно всем.О том как в переписке быть толковым, уважительным, приятным и эффективным. Очень многим этого не хватает.

  • А. Орлов "Джедайские техники конструктивного общения". Коротко, по делу, с примерами.Однозначно рекомендую. И в работе пригодится, и в быту.

  • М. Гоулстон "Как разговаривать с мудаками". Книга придаёт понимание того, что не все проблемные отношения и коммуникации можно разрешить рациональными доводами, и что делать в таких случаях. Ну и о себе можно задуматься тоже:)

  • Роадмап тимлидаhttps://tlroadmap.io/Очень полезный инструмент, который поможет разобраться, какие бывают требования к тимлидам, понять, что с ними делать и как подтягивать свои знания. Также подойдет как хороший инструмент для того, чтобы обговорить со своим руководителем на начальном этапе работы, что же конкретно от вас ожидается.

  • Курсерный курсhttps://www.coursera.org/specializations/product-managementДолгий и основательный курс, который покрывает всё про управление проектами. Выявление требований, план рисков, декомпозиция и распределение задач, аджайл техники и прочее. Вы справедливо можете заметить, что этот курс нужен менеджерам проектов, а не тимлидам. Теоритечески - да, а на практике возможно, что если у вас менеджер проекта и есть, то в каких-то деталях он может не очень разбираться. Тогда понадобится ваше участие.

  • Регулярные двухнедельные тимлидские конференции от ребят из подкаста Podlodkahttps://podlodka.io/tlcrewТам много хороших докладов и душевное отзывчивое комьюнити, с которым можно порой пообсуждать в деталях то, за что обычно деньги берут на платных индивидуальных консультациях.

Шаг номер 2. Общий план первоначальных действий

От теории переносимся к практике.

Первым делом необходимо разобраться: кто руководитель, кто заказчики, кто кому подчиняется, а кто нет. Желательно всё записать, а еще лучше составить визуальную схему а-ля mindmap, глядя на которую будет видна общая картина всех отделов и действующих лиц.

Далее, когда вы поняли официальную часть, надо погрузиться в неофициальную.

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

Какие назначить первые встречи, чтобы во всё это погрузиться?

Первым делом встретьтесь 1 на 1 с руководителем и, используя роадмап тимлидаhttps://podlodka.io/tlcrew, обговорите конкретные ожидания от вашей позиции. Главное помнить, что в роадмапе указано не "всё, что должен знать и делать тимлид", а "всё, что могут требовать от тимлида в разных компаниях", т.е. это объединение подмножеств хотелок из разных компаний. Так что, когда вам начальник скажет: "Ну, вроде выглядит норм, давай-ка всем занимайся," - вашей задачей будет ему объяснить, что всем заниматься невозможно физически и нужно проанализировать конкретную ситуацию, проект, команду, выделить наиболее важные области, которые вы и возьмете на себя.

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

  • взглянуть на текущую ситуацию с разных сторон;

  • узнать какую-то историю, которая творилась еще до вас;

  • проанализировать самих людей;

  • понять ожидания этих людей от вас.

Шаг номер 3. Распространенные проблемы. Предупрежден - значит вооружен

Здесь я коротко рассмотрю типичные проблемы и как с ними бороться.

Проблема с внешними коммуникациями

  • Авторитет и субординация в команде.

    Если вы становитесь тимлидом в старой команде, то вам повезло - это довольно легкий вариант. Раз вас поставили на эту позицию, значит, у вас уже есть какой-то авторитет и доверие к вашей работе. Остается развивать и поддерживать это. Лично я стараюсь работать даже простым разработчиком так, чтобы это было профессионально, качественно и без халтуры. Требую этого от себя и призываю к этому коллег. Так что, становясь тимлидом в такой команде, по сути ничего не меняю и всё это дальше нормально работает.

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

  • Отношения с руководством.

    Есть такая штука, как матрица доверие-прозрачность.

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

  • Общение с заказчиками.

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

Проблема с самим собой

  • Синдром самозванца.

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

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

    Даже если вдруг окажется, что у вас не получается быть тимлидом, вы всегда можете (обговорите этот момент с руководством заранее) откатиться обратно, и в этом нет ничего плохого или стыдного. Хуже - совсем не попробовать, боясь неудачи, чем попробовать и зафейлиться. Даже негативный опыт будет очень ценным для вас, ведь только так вы сможете понять, точно ли вам надо работать на этой позиции. Сейчас мне сложно вспомнить, где именно и кем проводился опрос, но вроде статистика была такова, что около 30% тимлидов откатывается обратно в разработку. Так что искать себя, пробовать, заниматься тем, к чему душа лежит - это нормально.

  • Меньше пишешь код, теряешь позиции на рынке среди технарей.

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

    Тут надо понять, что ценность этой позиции не в том, чтобы быть самым крутым технарем (хотя хороший технический бэкграунд, безусловно, важен). Ценность в том, чтобы быть на стыке разработки и бизнеса, людей и процессов, хард и софт скиллов. Хороших разработчиков, на мой субъективный взгляд, больше, чем хороших тимлидов. Поэтому, теряя позиции на рынке труда разработчиков, вы можете открыть для себя новый, менее насыщенный кандидатами, рынок тимлидов.

Проблема с объемом работы

  • Неумение и страх делегировать.

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

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

  • Микроменеджмент ичайка менеджмент.

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

  • Остается мало времени на повышение квалификации.

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

  • А чему учиться-то, хардам, или софтам?

    Замечательный вопрос. Конечно, как начинающему тимлиду, я бы рекомендовал окунуться в бескрайний океан софт скиллов и менеджмента, потому что это именно то, чего у вас было мало, как у разработчика, и то, чего от вас ждёт работодатель.

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

Проблемы со здоровьем ментальным и физическим

  • Гигиена труда и образ жизни.

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

    - Постарайтесь поменьше овертаймить. Всю работу не переделаешь. Делайте сначала важную, а что-то менее важное уже можно будет перенести, отложить, или даже отменить. Не повторяйте моих ошибок. Однажды я так овертаймил, что на пару месяцев от нервного напряжения перестал ощущать вкус (это было задолго до коронавируса). Или 3 месяца работал по 260 часов в месяц, а потом целый год не хотелось не то что работать, а вообще ничего в жизни не хотелось.

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

    - Помните, что за пределами монитора и работы тоже существует жизнь. Иначе можно в какой-то момент понять, что в последние N лет кроме дедлайнов, тасок в жире, проектов и заказчиков вы ничего и не видели, хотя мечтали (возможно) о чем-то другом.

  • Важность рефлексии, что в работе, что в быту.

    Очень важно думать о том, что и как вы делаете, что в рабочих моментах, что в бытовых. И неплохо бы делать это не стихийно, а систематически. Порой нас так затягивает рабочая и бытовая рутина, что мы барахтаемся в этом болоте, даже не замечая его. А регулярность подходов к рефлексии заставят систематически вытаскивать голову из болота, глядеть по сторонам, понимать, что мы делаем, зачем и как, а также насколько мы этим всем удовлетворены.

Шаг номер 4. Полезные качества для тимлида

Полезные качества, которые надо в себе взращивать:

  • Умение не сойти с ума при многозадачности.

    Обычно у тимлидов очень много разных задач по всем фронтам. Например, утром нужно встретиться с заказчиком, в обед обсудить задачу с командой, на полдник написать 100500 писем, на ужин пообщаться с глазу на глаз с начальником, а еще хотелось бы кой-чего и самому подкоммитить. И это еще легкий день. Заказчиков обычно много, так же как и задач, встреч и всего остального. Так что умение сохранить разум в режиме многозадачности - важное умение.

    Тут поможет умение выделять приоритетные задачи, а менее приоритетные делегировать и правильно контролировать.

    Умение разговаривать на языке собеседника.

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

    Умение говорить "нет".

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

    Дисциплина.

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

  • Эмпатия.

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

Шаг номер 5. Что делать дальше?

  • Продолжайте учиться.

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

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

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

  • Продолжайте (или начинайте) общаться с разными людьми в индустрии.

    Я поработал и пообщался с довольно большим количеством программистов и тимлидов из разных (десятки) компаний, и оказалось, что многие из них не высовывают нос за пределы своей работы, своего отдела. Люди не знают, как обстоит с технологиями, процессами, общением, условиями труда в других компаниях. Это незнание толкает их на переизобретение одних и тех же велосипедов, а также не позволяет хоть сколь объективно оценить положение дел в своей компании.

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

  • Всегда критически мыслите.

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

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

Дополнительные материалы

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

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

Успехов!

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

Подробнее..

Медведи, хомяки, человекоподобные. Хомяк или медведь брат человеку с точки зрения биоинформатики?

27.01.2021 18:04:51 | Автор: admin

Чтобы ответить на этот вопрос, в научном исследовании необходимо определиться с целью, задачами и методами, и изучаемыми материалами. Для этого нужно постараться предварительно поставить гипотезу, которая облегчит нам понимание того, чего мы хотим, а следовательно, позволит нам выбирать материалы исследования. В качестве гипотезы можно опираться на ваши знания в области классификации групп животных. Однако, если у Вас нет таких знаний и Вы не хотите страдать в поисках этих знаний в полях, лесах и лабораториях, то Вы можете стать продвинутым пользователем интернета и воспользоваться удобном сайтом lifemap [1], который отображает филогенетическое древо всех животных. Если же вы не продвинутый пользователь, то Вы можете просто воспользоваться википедией. Стоит отметить, что для учёного сайт Lifemap является таким же примитивным, как и википедия, но не бойтесь начать с малого, ведь википедия может послужить толчком к эволюции от простого к сложному. Поэтому пойдёмте эволюционировать на вики вместе. Для этого зайдём в поисковик и посмотрим информацию о нужных нам группах, с которыми в будущем нам предстоит работать, на данном сайте. Первые в списке у нас медвежьи. На странице сайта нам не нужно досконально изучать строение, размножение и образ жизни медведей. Нам нужны три вещи:

1) Раздел научной классификации.

2) Раздел филогенетики.

3) Краткая сводка классификации, которая отображена в верхнем правом углу под картинкой с научной классификацией.

Переходим в раздел научной классификации и смотрим список родов в семействе медведей, предварительно выписав название этого семейства на латыни (Ursidae). Нам понадобятся названия всех родов на латыни, которые есть в семействе. Их лучше также выписать (рис.1).

(рис.1)

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

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

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

Теперь переходим в раздел краткой сводки научной классификации (рис.3). Находим вкладку отряд хищные и переходим по ней.

(рис.3)

Во вкладке отряда переходим в раздел 4.1. Внешняя систематика. Там необходимо найти надотряд, к которому принадлежат медведи (рис.4). Он указан на филогенетическом древе в виде гиперссылки, нажимаем на неё и переходим в соответствующий раздел.

(рис.4)

В разделе нам нужно узнать отношение приматов к этому надотряду. Для этого мы переходим во вкладку классификация и как не странно мы не обнаруживаем в нём приматов (рис.5) Получается, что медведи по версии википедии вообще не близкие родственники приматов. Может это так и есть, но кто же по версии википедии примату будет братом?

(рис.5)

Для этого проводим аналогичные манипуляции с семейством хомяковые и в конечном итоге попадаем в отряд грызуны. Переходим в раздел систематики и ищем надотряд (рис.6).

(рис.6)

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

1) Выбрать генетические последовательности представителей родов изучаемых групп в качестве внутренней группы в базе NCBI [2].

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

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

4) Выровнять выбранные последовательности правильным методом в зависимости от выбранных последовательностей.

5) Выбрать модель вычисления попарных расстояний и метод построения эволюционного дерева.

Чтобы уже начинать определяться с методами нам нужно выбрать внешнюю группу, а также определиться с генетическими последовательностями. Внешняя группа нам нужна для определения положения корня дерева, так сказать, его основы. В качестве внешней группы обычно используют одну или несколько клад, отпочковавшихся от общего дерева заведомо раньше (но желательно ненамного раньше) анализируемых последовательностей. Поскольку мы изучаем филогенетические отношения между плацентарными млекопитающими, то в качестве внешней группы можно использовать сумчатых млекопитающих [4]. Пусть это будут опоссумы. Я люблю опоссумов. Это котики мира сумчатых, а котиков любят все.

Далее определяем материалы. В качестве необходимых материалов я решил взять рибосомальные гены 18S рРНК у двух представителей разных родов из каждых изучаемых групп. Маркер 18S рРНК используется с конца 70-х годов прошлого столетия и является универсальным для систематических построений. Ген, кодирующий 18S рибосомную РНК, есть в геноме всех известных эукариот и является удобным маркером для их идентификации; он отсутствует у вирусов, бактерий и архей. Ген 18S рРНК содержит как консервативные участки, одинаковые у всех прокариот, так и вариабельные. Консервативные участки служат для первого этапа полимеразной цепной реакции присоединения праймеров к исследуемой ДНК-матрице, вариабельные участки для идентификации видов. Степень сходства видоспецифичных вариабельных участков отражает эволюционное родство разных видов [3].

С материалами более-менее определились, теперь их необходимо скачать в генетической базе данных. Переходим на сайт ген банка и в поисковой строке вбиваем название семейства латинскими буквами и ищем генетические последовательности родов, которые мы записывали ранее. Последовательности должны быть приблизительно равной длины и ни в коем случае не короткие, ибо короткие последовательности несут мало информации, а информация в нашей работе это золото, где филогенетическое древо Зиккурат. А всем мы знаем, что для строительства Зиккурата нужно больше золота. Поэтому для удобства в графе Sequence length выставим необходимую длину последовательностей (1600-2500) и нажмём кнопку Search (рис.7).

На рисунке выше мы видим, что я начал с медведей, к сожалению ген банк выдал мне всего три результата и все одного вида (рис. 8). Ничего страшного, ведь медведя мы всё равно скачаем, а запасной вариант в виде ластоногих у нас имеется и к счастью в генбанке необходимые последовательности по ним есть.

(рис. 8).

Таким образом мы скачиваем все необходимые нам последовательности в формате fasta. Cкаченные последовательности закидываем по одной (или несколько, если Вы скачали всё одним форматом) в программу MEGA 10 для объединения в один формат fasta в будущем (рис.9)

(рис.9)

Итак, в мою выборку исследования попали 8 видов. Я не буду пугать Вас латынью как делаю это обычно, а перечислю всех избранных товарищей по-русски матом. Первые два вида в моём списке будут представлять этакую не существующую в реальном

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

Теперь нам надо начинать определяться с методами. Первым важным методом будет выравнивание генетических последовательностей. Выравнивание является важным биоинформатическим методом, основанным на размещении двух или более генетических последовательностей позволяющим увидеть сходные участки в этих последовательностях. Их сходство может отображать структурные и эволюционные связи, которые без выравнивания не построить [5]. Выравнивание мы не будем производить в MEGA 10, так как для рибосомальных последовательностей лучше воспользоваться мафтом [6]. Перед этим мы объединим все последовательности в меге в одну и экспортируем в любую папку на рабочем столе в формате fasta (рис.10).

(рис.10)

Сохранённый файл мы загружаем на сервер мафта в браузере (рис. 11) и изменим один стандартный параметр, выбрав тот, который показан на рисунке 12. Далее нажимаем кнопку Submit и получаем результат, который необходимо реформировать в формат fasta, как показано на рисунке 13.

(Рис.11)

(Рис.12)

(Рис.13)

Полученный формат необходимо загрузить обратно в мегу и уже работать в ней. Поздравляю мы это сделали! (рис.14)

(рис.14)

Теперь перед построением уже самого дерева нам необходимо проверить выравнивание трансляцией нуклеотидом в последовательности. Это позволит нам проверить правильность нашего выравнивания. Наличие звёздочек в последовательности, покажет нам наличие в ней антикодонов, что будет означать ошибку. Устранять эту ошибку можно выравнивая последовательности вручную, отодвигая последовательность вправо на один квадрат. К счастью этого делать нам не придётся, ибо у нас всё получилось хорошо (рис.15.)

(Рис.15)

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

Данная модель различает скорость различных точечных мутаций и учитывает не равные базовые частоты, которые не учитываются простыми моделями [7]. В меге эту модель можно выбрать сразу при построении дерева в методе максимального правдоподобия, там же заранее выставим проверку в 1000 реплик (так называемый бустрэп анализ). Данный анализ позволяет посмотреть статистическую поддержку ветвей, чем она выше, тем будет лучше. Высокая поддержка большинства ветвей более 70% позволяет сказать, что дерево построено правильно (рис.16). Поддержка ниже 70% для

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

(рис.16)

К сожалению, посмотреть эту модель отдельно инструментал меги не позволяет, но наглядно она бы выглядела примерно таким образом (рис.17).

Рис (17).

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

Метод максимального правдоподобия, говоря примитивным языком, позволяет определить неизвестное число параметров на основании известных результатов эксперимента. Скажем, если известно число граней правильного многогранника (т.е. число параметров), то можно определить, чему равны вероятности различных исходов бросков этого многогранника. Так, для шестигранной игральной кости вероятность любого исхода броска будет равна 1/6. Однако если взять за гипотезу, что число граней некой игральной кости нам неизвестно, данный метод позволяет предположить путём многократных повторных экспериментов в виде бросков этой игральной кости, число граней этой кости и определить правдоподобие этого предположения. Так, многократно подбрасывая некую игральную кость с неизвестным числом граней и наблюдая, что число различных исходов бросков кости равно шести, можно сделать предположение, что это кость шестигранная [4]. Именно поэтому этот метод в данном случае я считаю одним из лучших для ответа на заданные мной вопросы.

В качестве дополнительных плюшек мега позволяет воспользоваться функциями уточнения выводимого дерева, что даёт нам возможность вывести исходное дерево для эвристического поиска, который в свою очередь используется для оценки лучшего состояния нашего дерева. Подробно, что такое эвристический поиск можно прочитать в IT сообществе хабр [5]. Итак, в дополнительных параметрах меги меге мы можем выбрать метод максимальной экономии, который является критерием оптимальности, для которого наилучшим считается самое короткое дерево, которое объясняет данные. Этот метод работает по канонам Бритвы Оккама (рис 18). В принципе в дополнительных параметрах можно выбрать ещё кучу всего, но я думаю и этого вполне хватит.

(Рис.18)

Собственно, теперь у нас всё готово, чтобы проверить википедию на подлинность и заодно нашу гипотезу. Строим дерево! (Рис.19) ;(Рис.20)

(Рис.19)

(Рис.20)

Вуаля чувствую себя доктором ВУ, когда дерево строится успешно!

Теперь давайте взглянем, что у нас получилось, а получилось у нас практически всё идеально!

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

Примечание :

Материал был написан мной 26.01.2021 года и опубликован 27.01.2021 в научно-популярном сообществе фанерозой (http://personeltest.ru/aways/vk.com/phanerozoi).

Источники:

1)http://lifemap.univ-lyon1.fr

2)https://www.ncbi.nlm.nih.gov/nuccore/?term=Phocidae+18S+ribosomal+gene

3) Соловьева В.В. Молекулярно-генетический анализ беспозвоночных животных по нуклеотидной последовательности гена 18S рибосомной РНК: учебное пособие / Соловьева В.В., Моров А.Р., Ризванов А.А., Сабиров Р.М.- Казань: федеральный ун-т, 2011 52 с.

4) Молекулярная эволюция и филогенетический анализ/ В.В. Лукашов М.БИНОМ. Лаборатория знаний, 2009. с.256. с.92-123.

5)Mount DM.Bioinformatics: Sequence and Genome Analysis. 2nd. Cold Spring Harbor Laboratory Press: Cold Spring Harbor, NY., 2004.

6)https://mafft.cbrc.jp/alignment/server/

7) Hasegawa M., Kishino H., and Yano T. (1985). Dating the human-ape split by a molecular clock of mitochondrial DNA.Journal of Molecular Evolution22:160-174.

8) http://personeltest.ru/aways/habr.com/ru/company/mailru/blog/217839/

Подробнее..

Выступления и презентации в стиле Apple на примере WWDC20

23.06.2020 22:21:05 | Автор: admin
К нам часто приходят клиенты с запросом Хотим в стиле Apple, и теперь на один такой запрос станет больше он будет касаться презентаций для онлайн-конференций. Сооснователь студии дизайна информации VisualMethod сделала подробный разбор, на каких элементах строился сценарий вводного дня #WWDC20. Разбор состоит из трех блоков: цель, контент и дизайн. Полезен всем, кто делает презентации и выступает публично.

image

Иллюстрация VisualMethod

Меня зовут Виктория. Я сооснователь студии дизайна информации VisualMethod и тренер по публичным выступлениям. Мне всегда интересно смотреть презентации крупных компаний и анализировать их сценарии. 22 июня на #WWDC20 компания #Apple не только представила свои обновленные продукты, но и задала тренд публичных выступлений в новом формате.

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

Разберем презентацию Apple от начала до конца


Подготовка любой презентации или выступления начинается не с запуска программы #PowerPoint и даже не с запуска #KeyNote Она начинается с ответов на вопросы на бумажном или электронном листе. Если говорить языком маркетинга, нужно заполнить план коммуникаций.

image

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

Давайте предположим, как могли звучать ответы на эти вопросы у Apple, исходя из того, что озвучивали спикеры с экранов всех форматов на #WWDC20.

1. Цель. Что зритель должен знать, думать или делать после WWDC20?


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

image
Интересный жест занять место зрителя

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

Поэтому если сформулировать цель кратко, то она прозвучит примерно: жить с Apple.

2. Аудитория. Кто должен совершить целевое действие после WWDC20?


Хотя всемирная конференция Apple и обозначена как мероприятие для разработчиков, на деле это PR-событие, и вторая (если не первая) его аудитория пресса, блогеры и общественные институты. Именно поэтому CEO компании Tim Cook начал Всемирную конференцию разработчиков с мнения о событиях, которые в настоящее время влияют на мир: движения Black Lives Matter и всемирной эпидемии коронавируса.

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

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

image
Обратите внимание на символы позади Кука все они со смыслом о важных событиях в обществе.

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

Смотрите, два супер-важных повода и два аргумента в пользу Apple. Вот она работа с репутацией. И эта работа нацелена не на разработчиков. Акции Apple также выросли во время основного доклада и закрылись на 2,6% до 358,87 долл. Это является признаком того, что инвесторы были довольны новостями о программном обеспечении и компании.

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

3. Сообщение. Какие аргументы и контент?


Ключевые сообщения для инвесторов и СМИ мы разобрали в блоке выше они про социальную ответственность и экосистемность Apple. Что же компания хотела сообщить разработчикам?

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

Еще для разработчиков были фоновые сообщения об удобстве работы именно в этой экосистеме. Для этого, предполагаю, были собраны самые массовые запросы и детально освещены в обзоре от организации иконок до трансформации надписи стилусом в текст. Ведь разработчики прежде всего люди, поэтому новости об измерениях сна, физической активности через часы, открытие машины с помощью телефона, возможности персонализации и установки фото ребенка на рабочем столе это жизненно и интересно.
Сообщение это не только слова, а еще интонация и внешний вид того, кто говорит. Это тоже часть коммуникационной стратегии и называется Tone of voice (ToV), то, с какой интонацией и в каком стиле говорят спикеры бренда и звучат сообщения от имени компании.

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

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

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

image
Ценности Apple

Финальные наблюдения в этом блоке. У Apple есть прописанные ценности на сайте, в материалах о компании. Ценности нужны в том числе для имиджа, чтобы создавалось цельное представление о компании, но они работают, если подтверждаются примерами. Поэтому в каждом программном выступлении и на мероприятиях представители Apple называют свои ценности и то, как они воплощены в жизнь. Это об универсальном доступе, окружающей среде, конфиденциальности. Заметили, как эти ценности были вшиты в выступления спикеров? Обычно это самая скучная часть, и у Apple этот блок тоже был затянут и спокоен так, что хотелось взять в руки iPhone, но при многократном повторении все же работает прекрасно, создавая нужное впечатление о компании.

4. Канал. Откуда аудитория получит сообщение?


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

Блогеры и авторы статей отметили перемещение камеры из театра в офис, я зафиксировала для себя важный нюанс с представлением продуктов Apple там, где они используются на рабочем месте, в спортивном зале, гараже, квартире. Это погружает в нужную атмосферу. Единственное, что не смогли показать это перемещение по городу, но вместо этого был симпатичный ролик в 3D.

image
Тайная лаборатория Apple тоже была среди локаций

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

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

Про локации я уже написала выше, спикеры подбирались так, чтобы говорить узко о своем предмете разработки. Это создает ощущение профессионализма. Из склеек были использованы в общем-то стандартные схемы переход через мобильный телефон (пример: Крейг Федериги берет в руки телефон и дальше начинается следующий эпизод презентации с демонстрацией экрана), пролеты вдоль здания, устная передача слова от спикера к спикеру, склейка через презентацию. Хорошие рабочие инструменты.

Логика выступлений строго по цели


  1. Сделать заявление компании о важных событиях в мире. Это нужно, чтобы обозначить позицию компании и задать тон.
  2. Подстроиться под аудиторию и привлечь внимание. Презентацию начали с простых изменений, которые интересны всем зрителям. Например, виджетов. Организация приложений была зудящей проблемой, о которой часто писали на форумах. Решение простое, охват аудитории максимальный, тема вызывает доверие и затягивает.
  3. В середине конференции дали новые продукты, которые еще недостаточно популярны это подписки на ТВ и прочие электронно-развлекательные продукты. Тизер Foundation|Apple TV+ разбудил немного заснувшую аудиторию и дал возможность отдохнуть от спикеров.
  4. В конце конференции поставили самые важные анонсы, например, о постепенном отказе использования чипов Intel. Это давняя уловка ставить в конце самое интересное, чтобы удержать внимание зрителей до конца.
  5. Кук отпустил аудиторию чуть раньше, чем закончились 2 часа. Это хороший прием, чтобы оставить ощущение недосказанности и заинтересовать зрителя подумать о том, что он услышал и заставить действовать.

Все вместе было собрано с помощью красивого монтажа.


Тизер Foundation|Apple TV+

О дизайне скажу отдельно


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

image

Текст на слайдах


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

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

image
Текст это отдельный объект на слайде, если спикер зачитывает текст, то его нет в кадре.


Анимация


Это тренд в дизайне презентаций 2020 года, и он останется с нами и дальше. Что отличало анимацию в презентации Apple? Естественность. Текст, иконки, объекты появлялись ровно так, как мы ожидаем этого в жизни, а точнее, как мы привыкли это видеть на своих экранах в приложениях и на сайтах. Возьмите этот пункт во внимания, работая в PowerPoint. Анимация снова в моде, но она должна быть ненавязчивой.

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

Градиент


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

image

Прозрачные плашки


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

image

3D-модели


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

image

5. Активация. Конференция закончилась что дальше делать?


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

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

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

Что было интересно Вам?
Подробнее..

13 облачных учебных ресурсов для .NET-разработчиков

30.03.2021 10:05:43 | Автор: admin

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

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

  • 3 ресурса с гайдами

  • сайт с учебными модулями

  • 8 книг

  • ресурс с примерами архитектуры

Все это под катом!

Начало работы с облачными приложениями .NET

Если вы новичок, начните создавать простые микросервисы с помощью веб-API ASP.NET, Docker и разверните их в Azure Kubernetes Services (AKS).

Практические модули обучения Microsoft

У Microsoft есть бесплатная онлайн-платформа для обучения под названием Microsoft Learn. Вы можете получить больше навыков с помощью контента, который в то же время веселый, управляемый, практический, интерактивный и соответствует вашей роли и целям. Мы создали серию модулей, которые помогут вам научиться создавать микросервисы .NET с облачными технологиями, такими как Docker, Container Registry, Kubernetes, Helm и многими другими. Единственная программа, которая вам понадобится на вашем компьютере для запуска этого модуля, - это браузер. Вся магия выполняется за кулисами с помощью Azure CLI, поэтому вы можете полностью сосредоточиться на обучении и забыть про проблемы с инфраструктурой.

Попробуйте их сейчас!

Бесплатные электронные книги по архитектуре

Dapr для .NET разработчиков

Форматы:PDF|Read online

Руководство для разработчиков .NET по пониманию и использованию всей мощи распределенной среды выполнения приложений Microsoft с открытым исходным кодом (Darp). Dapr помогает решать проблемы, возникающие при создании микросервисов, и делает ваш код независимым от платформы.

Cloud-native

Форматы:PDF|Read online

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

.NET микросервисы

Форматы:PDF|Read online

Мы написали это руководство для разработчиков и архитекторов решений, которые плохо знакомы с разработкой приложений на основе Docker и архитектурой на основе микросервисов. В этой книге рассматриваются такие шаблоны, как Domain-Driven Design(DDD), Command Query Responsibility Segregation (CQRS), Database per service, API Composition.

Бессерверные приложения

Форматы:PDF|Read online

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

DevOps: жизненный цикл приложения Docker

Форматы:PDF|Read online

Это руководство содержит общие сведения о Azure DevOps для реализации конвейеров CI/CD, охватывает реестр контейнеров Azure (ACR) и службы Azure Kubernetes (AKS) для развертывания.

Модернизация существующих приложений .NET

ASP.NET Core gRPC для WCF-разработчиков

Форматы:PDF|Read online

Мы написали это руководство для разработчиков, работающих в .NET Framework или .NET Core, которые ранее использовали WCF и стремятся перенести свои приложения в современную среду RPC для .NET 5. В целом, если вы обновляете или рассматриваете возможность обновления до. NET 5, и вы хотите использовать встроенные инструменты gRPC, это руководство поможет.

Миграция приложений .NET в Azure

Форматы:PDF|Read online

В этом руководстве основное внимание уделяется начальной модернизации существующих веб-приложений или сервис-ориентированных приложений Microsoft .NET Framework. Это означает перенос рабочей нагрузки в новую или более современную среду без значительного изменения кода приложения и базовой архитектуры. Кроме того, ознакомьтесь с другими ресурсами по миграции на странице Migrate your .NET app to Azure.

Перенос существующих приложений ASP.NET на .NET Core

Форматы:PDF|Read online

В этом руководстве представлены высокоуровневые стратегии миграции существующих приложений, написанных для ASP.NET MVC и веб-API (.NET Framework 4.x), в .NET Core. В нем также рассматриваются стратегии миграции больших решений на примере проекта.

Примеры архитектуры

eShopOnContainers - один из наших популярных эталонных образцов микросервисов. Это кроссплатформенное контейнерное приложение, работающее на платформе .NET 5. Ознакомьтесь с этим примером для подробной реализации некоторых шаблонов микросервисов, таких как CQRS, DDD, Database per service, API Composition. Не забудьте проверить другие примеры, в том числе "Модернизация ваших приложений .NET" здесь.

Подробнее..

Это реальность, детка. Как проводить маркетинговые исследования и почему 92 стартапов не взлетают

08.04.2021 16:21:10 | Автор: admin

Если хотите вести интернет проекты эффективно, то хотя бы примите это к сведению.

Информация сугубо практическая. В основе знания от бизнес-практиков в купе с Теорией Вероятностей и Математической Статистикой.

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

Зачем нужны исследования

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

Например,

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

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

Антон запускает рекламную кампанию. Чтобы узнать, где сидит покупатель, он проводит исследование смотрит поисковую выдачу по тематике, статистику, советуется с экспертами и т.п.

И другие примеры, коих 1 000 000+

Как исследовать

Типовое исследование происходит по следующей схеме:

Рис 1. Схема маркетингового исследования.

H это гипотеза (hypothesis, англ.).

Тогда исследование проводится в 2 этапа.

  • Сначала мы формулируем гипотезу #1 (Н1, предположение, MVP),

  • Потом проверяем ее доказываем или опровергаем -> в результате получаем гипотезу #2 (H2=+Н1 изначальное предположение верно или H2=-Н1 изначальное предположение ошибочно).

Если H1 ошибочна, то нужно вносить корректировки в продукт до тех пор, пока H2 не подтвердит H1.

Как правильно исследовать

Собрать информацию для H1:

  • Провести мозговой штурм,

  • Изучить потенциальных конкурентов,

  • Посмотреть статистику в Интернете.

Затем Н1 нужно проверить ее и получить Н2 подтверждение или опровержение первоначальной гипотезы.

Как получить H2?

  • Либо поговорить с потенциальными покупателями (организовать фокус-группу),

  • Либо обсудить предмет исследования с экспертом,

  • либо поставить эксперимент (протестировать).

В результате получаем ценную информацию, которая ошибочна с минимальной вероятностью.

Например, Олегу нужно выяснить, в каких соц.сетях зависают его покупатели.

Для этого он делает вот что:

1. Находит статистику по посетителям социальных сетей.

2. Выясняет у своих покупателей, сидят ли они в сетях, обозначенных в исследовании.

Так он получает информацию, приближенную к действительности.

Я сказал, что вероятность ошибки минимальна?! Увы и ах, но ошибка может произойти все равно.

Что такое Статистическая ошибка (или ошибка выжившего)

Статистическая ошибка погрешность при проведении исследования.

По правилам статистики избежать ошибки нельзя. Хотя бы в 0,000000000001% случаев ошибка случится, и это нельзя предотвратить.

Но есть и хорошая новость: можно уменьшить вероятность появления ошибки. Собственно, ради этого и затевается история с проверкой гипотез.

Не для того, чтобы быстрее узнать хотя бы что-то, а для того, чтобы реально выяснить наиболее эффективное решение.

Как делать не надо

Исследовать в 2 этапа это правильно, по науке. 1: формулируем предположение (кабинетная часть исследования), 2: проверяем его (полевая часть).

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

Игнорирование второго этапа может привести к проблемам.

  • Результаты будут ошибочными,

  • Результаты будут не полными.

Но он догадался обсудить информацию с друзьями. Они сказали ему, что сидят во Вконтакте.

Таким образом он понимает, что нужно акцентировать внимание на 2-х сетях Вконтакте и Instagram.

Возвращаясь к примеру выше. Олег увидел по статистике, что интересная ему аудитория сидит в Инсте.

Если бы Олег просто посмотрел статистику по социальным сетям, он бы никогда не узнал про Вк и потерял половину прибыли.

Кстати, я думаю, что именно поэтому сдуваются 92% стартапов из-за недоисследований. Типа мы запустились, добились определенных успехов и мы лучше знаем, что понравится покупателям. Но нет, увы. И мечты о дальнейшем успехе разбиваются об скалы реальности.

Теперь несколько практических рекомендаций по проведению исследований.

Где искать статистику

Статистика по РФ

  • Сайт Федеральной службы государственной статистики rosstat.gov.ru

  • Сайт Министерства Экономического Развития old.economy.gov.ru

  • Сайт ВЦИОМ wciom.ru

  • Фонд Общественного Мнения fom.ru

  • НАФИ, аналитический центр nafi.ru

  • Wordstat Яндекса - wordstat.yandex.ru

  • Огромное количество региональных сайтов, форумов и др.

Международная статистика

Теперь поговорим про подтверждение гипотезы.

Как проверить гипотезу онлайн

Полевую часть исследования лучше проводить оффлайн (нужно объяснить, почему?), но ведь не всегда есть возможность сделать это. Именно для таких случаев существуют следующие онлайн-инструменты.

  • Google Forms удобный сервис для опросов, доступный бесплатно. Гибкие и интуитивно-понятные настройки.

  • Яндекс.Взгляд Конкурент Google. Но платный, потому что к анкете прилагается база из 15 миллионов подписчиков Яндекса.

  • Tiburon-research это Специализированный сервис для маркетологов. Им пользуются около 80% российских исследовательских компаний.

  • Anketolog еще один сервис для опросов онлайн. Простой в использовании, с возможностью удобными отчетами и, ВНИМАНИЕ поддержкой живого маркетолога.

Как проходят исследования на практике? Я попросил рассказать реального специалиста.

История предпринимателя, который проводит маркетинговые исследования

Попросил рассказать кейс о его работе. Вот что узнал.

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

Денис Загребиль, маркетолог, специалист по маркетинговым исследованиямДенис Загребиль, маркетолог, специалист по маркетинговым исследованиям

Как я работаю:

  1. Сначала определяю задачу получил заказ, осознал, сформулировал задачу и определил фронт работ (цели, план и пр).

  2. Далее я собираю информацию, которая так или иначе может помочь в решении поставленной задачи.

  3. Затем обрабатываю информацию структурирую, архивирую, анализирую.

  4. В итоге презентую результаты работы и распределяю информацию среди заинтересованных лиц.

Результаты исследований обычно разные. В зависимости от задач проекта.

Например, я работал с одним заказчиком и сэкономил ему 3 млн .У заказчика - глубинная экспертиза => он предполагал развитие там-то - разрабатывал сайт и планировал потратить на развитие 3 млн рублей.

Как все проходило это исследование:

  1. Мы изучили рынок. Тренды, аналогичные проекты и их развитие, потенциальных конкурентов.

  2. Я нашел нескольких отраслевых экспертов и взял несколько экспертных интервью.

  3. На выходе получилось множество цифр и графиков, выводы и предложения, которые мы разбирали с заказчиком в течение 2 недель.

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

Так он сэкономил 3 млн руб, которые планировал потратить на развитие проекта.

Денис Загребиль

Маркетолог, специалист по маркетинговым исследованиям

Резюме

  • Маркетинговые исследования это сила,

  • Маркетинговые исследования проводятся в 2 этапа,

  • Существует куча сайтов с информацией и несколько крутых сервисов для проведения маркетинговых исследований.

А вы уже исследуете или только планируете исследовать? Расскажите об этом в комментариях.

Если понравилась статья, ставьте +.

Не согласны с чем-то? Го в комментарии!

Спасибо за внимание!

Подробнее..

Nextcloud на VirtualBox с хранилищем в общей папке

17.01.2021 18:05:05 | Автор: admin

Идея иметь собственное домашнее облако у меня была давно. Рассматривал варианты NAS на основе бесплатных дистрибутивов типа FreeNAS, NAS4Free, OpenMediaVault и пр. Но хотелось, чтобы был мобильный клиент, простой и красивый webUI. Раньше как-то баловался с разными решениями и понравился проект ownCloud. Но на текущий момент у него платное мобильное приложение. Сейчас стоит около 30 рублей, но хотелось иметь что-то более бесплатное. Вспомнил про хороший форк ownCloud Nextcloud. Мобильное приложение бесплатное (+ для есть и дополнительные приложения) и есть декстопные клиенты (Win, Mac, Linux). Сам Nextcloud имеет множество настроек, интеграций, а также возможность установки расширений (приложений).

Распространяется Nextcloud несколькими вариантами:

  1. Архив серверного приложения для web-сервера;

  2. Web-инсталлер;

  3. Образами для VirtualBox, Docker и Snap-пакет.

Я решил реализовать схему на VirtualBox, с подключением общей папки, как хранилища.

Предусловие: На сервере должен быть установлен VirtualBox (далее VB) и VirtualBox Extension Pack (далее VBEP).

Импорт виртуальной машины

1. Скачиваем образ виртуальной машины Nextcloud-VM.ova.

Другие варианты образов представлены на сайте Hansson IT.

2. Двойным кликом запускаем скаченный образ, после чего откроется импорт VirtualBox.

В настройках можно указать для создаваемой виртуальной машины (далее ВМ) Имя, Описание и Папку. Характеристики железа уменьшать не стоит, иначе при установке Nextcloud могут появиться ошибки о недостаточности ресурсов. Все настройки ВМ, в т.ч. общие папки, лучше настраивать после завершения установки Nextcloud.

3. После нажимаем Импорт и ждём завершения создания нашей ВМ.

4. После успешного импорта, ВМ отобразиться в списке ВМ VB.

Первоначальная настройка Nextcloud

Образ ВМ основан на Ubuntu Server 20.04.1 LTS в котором предустановлены скрипты разворачивания Nextcloud.

1. Запускаем ВМ.

2. После запуска ВМ появляется приглашение авторизации. По умолчанию пользователь (админ) сервера ncadmin, с паролем nextcloud.

Смена пароля будет предложена после завершения конфигурации Nextcloud.

3. Авторизовываемся на сервере.

4. После авторизации появляется приветственное сообщение первого запуска с прделожением запустить скрипт установки. Для запуска необходимо ввести пароль пользователя ncadmin.

Вводим пароль, нажимаем Enter и запускается процесс установки Nextcloud.

5. После проверки конфигурации ВМ будет отображено сообщение о выборе варианта хранения данных. В образе ВМ подключено 2 жестких диска (динамические по 40 Гб):

  • disk1 диск с ОС, файловая система ext4.

  • disk2 диск с файловой системой ZFS.

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

Ознакомившись с сообщением, нажимаем Ок.

6. Открывается окно выбора жесткого диска для хранения.

Стрелками встаем на позицию 1 Disk, активируем её пробелом.

Клавишей Tab переходим к блоку кнопок, выбираем Ok и нажимаем Enter.

7. На следующем шаге открывается окно выбора DNS сервера:

  • Quad9

  • Cloudflare

  • Local локальный сервер (по DHCP)

Я предпочитаю использовать Cloudflare. Выбираю его и нажимаю Ok.

8. Следующее окно сообщение о выборе зеркала обновлений.

Ознакомившись с сообщением, нажимаем Ок.

9. Следующее сообщение информирует о текущем сервере обновлений http://archive.ubuntu.com/ubuntu.

Ознакомившись с сообщением, нажимаем Ок.

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

Я решил остаться на стандартном, хотя по тестам есть зеркала и получше (выше скорость, меньше пинг, шире канал). Поэтому на этом шаге выбираю No и нажимаю Enter.

После чего начнется установка Nextcloud (+PostgreSQL, PHP, Apache).

11. По завершению установки будет предложено изменить пароль ncadmin

Нажимаем любую клавишу. Вводим новый пароль, нажимаем Enter, подтверждаем новый пароль ещё раз и нажимаем Enter.

12. После смены пароля появляется сообщение что текущий админ в Nextcloud ncadmin. И его нужно заменить на нашего.

Нажимаем любую клавишу. Вводим имя пользователя, нажимаем Enter, вводим пароль, нажимаем Enter, подтверждаем пароль ещё раз и нажимаем Enter.

13. Далее появляется окно с выбором местоположения

Выбираем Europe, и нажимаем Ok.

14. В следующем окне необходимо выбрать город. Выбираем необходимый и нажимаем Ok.

15. Может появиться следующее сообщение о том, что существует обновленная версия файла '/etc/sysemd/resolved.conf' и нужно принять решение что делать:

Y или I установить обновленную (основную действующую) версию;

N или O оставить текущую установленную версию;

D показать изменения между версиями;

Z запустить shell

Я решил установить обновленную версию: ввожу Y и нажимаю Enter.

После обновления файла ВМ будет перезагружена.

16. После перезагрузки ВМ необходимо авторизоваться (на этом этапе можно пользоваться PuTTY). После авторизации будет приветственное окно, которое сообщит, что мы все установили и это окно можно отключить удалив файл /home/ncadmin/welcome.sh (иначе оно будет постоянно появляться).

Нажимаем Ok. Nextcloud установлен.

Настройка ВМ

Для работы расширений VB установим соответствующий пакет sudo apt install virtualbox-guest-utils

После установки выключим ВМ для её настройки sudo shutdown -h now

После того, как ВМ будет выключена, в VB зайдем в настройки.

1. Можно включить двунаправленный буфер обмена (но лучше пользоваться PuTTY)

2. Я уменьшил оперативную память до 1024 Гб и отключил гибкий диск

3. Установил использование одного ядра процессора

4. Создал общую папку (folder): указал путь и включил авто-подключение

Сохраняем настройки и запускаем ВМ.

Изменение папки хранения данных

Основной гайд для этого блока взял отсюда https://enk2x.ru/2019/09/21/datanew/

После запуска ВМ, авторизуемся.

1. Проверяем наличие общей папки

cd /media

ls

Должно отобразиться наименование sf_folder (на гостевой машине у общей папки префикс sf_), где folder имя общей папки на хост машине.

2. Включаем в группу vboxsf (группа-владелец общей папки) пользователей ncadmin и www-data (пользователь Apache).

sudo usermod -aG vboxsf ncadmin

sudo usermod -aG vboxsf www-data

После включения в группу перезагружаем ВМ

sudo shutdown -r now

3. После перезагрузки авторизуемся и переводим приложение nextcloud в режим обслуживания

sudo -u www-data php /var/www/nextcloud/occ maintenance:mode --on

Папка nextcloud расположена в корне папки www, а не внутри html

4. Копируем файлы настроек и пользовательские файлы в общую папку

sudo cp -R /mnt/ncdata /media/sf_folder

5. Убеждаемся что всё скопировано

cd /media/sf_folder/ncdata

ls

Так же можно проверить на хост машине в общей папке

6. Изменяем путь к папке данных в конфиг-файле

sudo nano /var/www/nextcloud/config/config.php

Откроется файл config.php, где для параметра 'datadirectory' необходимо изменить значение '/mnt/ncdata' на '/media/sf_folder/ncdata' (где folder имя общей папки)

После внесения изменений нажимаем Ctrl+X, на вопрос о сохранении изменений вводим y и нажимаем Enter.

7. Выключаем режим обслуживания

sudo -u www-data php /var/www/nextcloud/occ maintenance:mode --off

Результат

Проверим работоспособность.

1. Авторизуемся на сервере Nextcloud через web-интерфейс под пользователей admin и добавим картинку в папку Photos

2. Проверим наличие файла в общей папке на хост-машине

3. Проверим наличие файла в мобильном приложении.

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

4. Обратный порядок копирования

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

sudo -u www-data php /var/www/nwxtcloud/occ files:scan all

После сканирования, добавленный файлы отобразятся в приложении.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru