Настройки без страха и упрека
#backend #db #models #structures
При разработке портальных решений с личными кабинетами посетителей мы сталкиваемся с необходимостью реализации как персональных, так и общих настроек сайта.
Модель данных Entity-Attribute-Value позволяет для любой сущности создавать неограниченное количество свойств и заполнять их значениями нужных типов.
Например, пользователь в разделе «Профиль» может выбрать удобный для него формат даты или запретить показ рекламы на сайте. Тогда настройка «Формат даты и времени» будет иметь тип select — одиночный выбор значения из списка. А параметр «Показывать рекламу» будет хранить значение «Да» или «Нет» и иметь тип boolean. Можно реализовать и другие типы: number, string, text и даже multiselect.
Сложные типы настроек, такие как select и multiselect, имеют предустановленные списки значений, которые хранятся в таблице
Для конкретной настройки есть возможность указать классы валидаторов и параметры их конфигурации. Информация о каскаде валидаторов хранится в поле
В некоторых случаях можно пренебречь нормализацией БД в угоду удобства. Как альтернативное решение хранения вариантов выбора можно рассматривать упаковку их в JSON-поле таблицы
EAV дает возможность разработчику гибко выстраивать CRUD для управления настройками, соблюдая поддержку целостности данных на уровне СУБД. Такая модель хранения легко ложится в реализацию слоя приложения практически любого современного фреймворка и покрывается абстракциями ORM для удобства работы.
#backend #db #models #structures
При разработке портальных решений с личными кабинетами посетителей мы сталкиваемся с необходимостью реализации как персональных, так и общих настроек сайта.
Модель данных Entity-Attribute-Value позволяет для любой сущности создавать неограниченное количество свойств и заполнять их значениями нужных типов.
Например, пользователь в разделе «Профиль» может выбрать удобный для него формат даты или запретить показ рекламы на сайте. Тогда настройка «Формат даты и времени» будет иметь тип select — одиночный выбор значения из списка. А параметр «Показывать рекламу» будет хранить значение «Да» или «Нет» и иметь тип boolean. Можно реализовать и другие типы: number, string, text и даже multiselect.
Сложные типы настроек, такие как select и multiselect, имеют предустановленные списки значений, которые хранятся в таблице
config_variant. Установленные значения настроек хранятся в таблице config_value. Таблица config содержит информацию об атрибутах сущности, которые представляют собой непосредственные настройки. Для их группировки применяются категории, которые хранятся в таблице config_category.Для конкретной настройки есть возможность указать классы валидаторов и параметры их конфигурации. Информация о каскаде валидаторов хранится в поле
validators и имеет тип JSON.В некоторых случаях можно пренебречь нормализацией БД в угоду удобства. Как альтернативное решение хранения вариантов выбора можно рассматривать упаковку их в JSON-поле таблицы
config.EAV дает возможность разработчику гибко выстраивать CRUD для управления настройками, соблюдая поддержку целостности данных на уровне СУБД. Такая модель хранения легко ложится в реализацию слоя приложения практически любого современного фреймворка и покрывается абстракциями ORM для удобства работы.
Need for speed
#frontend #css #animation #stylus
Мы давно знаем, как управлять плавностью анимации в CSS. Но бывают ситуации, когда изинг невозможно реализовать по двум точкам на кривой Безье.
Например, необходимо реализовать поведение стрелки спидометра на чистом CSS. Стрелка разгоняется от начального положения до заданного значения и колеблется вокруг него, постепенно замирая.
Динамика движения стрелки описывается функцией с плавным ростом и затухающими колебаниями возле целевого значения. Построить примерный график такой функции можно на клетчатом листе бумаги, рассчитав ее значения для нескольких ключевых точек. По оси
Построить интерполированный график и получить промежуточные значения координат поможет сервис кубической интерполяции. Чтобы получить достаточное количество точек установим Step X Output, равный 1. Модифицировать график в интерактивном режиме можно с помощью опции «Интерактивный график JSXGraph».
На основе полученных точек можно произвести расчет ключевых кадров с помощью конструкции цикла в препроцессоре Stylus. Поворот стрелки спидометра изменяется свойством
Готовую анимацию и код ее исполнения можно увидеть здесь.
💡Чтобы не «зашивать» координаты функции в CSS, можно хранить их в отдельном JSON-файле, а затем импортировать в Stylus:
#frontend #css #animation #stylus
Мы давно знаем, как управлять плавностью анимации в CSS. Но бывают ситуации, когда изинг невозможно реализовать по двум точкам на кривой Безье.
Например, необходимо реализовать поведение стрелки спидометра на чистом CSS. Стрелка разгоняется от начального положения до заданного значения и колеблется вокруг него, постепенно замирая.
Динамика движения стрелки описывается функцией с плавным ростом и затухающими колебаниями возле целевого значения. Построить примерный график такой функции можно на клетчатом листе бумаги, рассчитав ее значения для нескольких ключевых точек. По оси
x откладывается время анимации от 0 до 100 %, а по оси y — прогресс движения стрелки от 0 до 1.Построить интерполированный график и получить промежуточные значения координат поможет сервис кубической интерполяции. Чтобы получить достаточное количество точек установим Step X Output, равный 1. Модифицировать график в интерактивном режиме можно с помощью опции «Интерактивный график JSXGraph».
На основе полученных точек можно произвести расчет ключевых кадров с помощью конструкции цикла в препроцессоре Stylus. Поворот стрелки спидометра изменяется свойством
transform: rotate().Готовую анимацию и код ее исполнения можно увидеть здесь.
💡Чтобы не «зашивать» координаты функции в CSS, можно хранить их в отдельном JSON-файле, а затем импортировать в Stylus:
points = json('data.json', { hash: true }).Воркшоп в Студии
#workshop #backend #php #dbms
Студия откроет двери всем желающим посетить наш воркшоп по Backend-разработке 31 октября 2019 в 19:00. Тема мероприятия — «Обработка больших массивов данных». Формат — лайфкодинг с обсуждением происходящего и обменом опыта.
Подробную информацию об ивенте можно найти здесь.
Приходите, будет интересно и полезно.
#workshop #backend #php #dbms
Студия откроет двери всем желающим посетить наш воркшоп по Backend-разработке 31 октября 2019 в 19:00. Тема мероприятия — «Обработка больших массивов данных». Формат — лайфкодинг с обсуждением происходящего и обменом опыта.
Подробную информацию об ивенте можно найти здесь.
Приходите, будет интересно и полезно.
Когда размер имеет значение
#mobile_native #android #kotlin
Начинающий Android-разработчик рано или поздно сталкивается с задачей определения основных параметров экрана — ширины и высоты. С появлением Apple-подобной «брови» в верхней части дисплея Android-устройств задача стала неочевидной.
Stack Overflow показывает несколько ответов, предполагающих использование двух нативных методов
У Honor 10 Lite заявленная высота экрана составляет 2340 px, но нативные методы возвращают 2139 px.
Рассмотрим пример вычисления фактического размера экрана Android-устройства.
В методе
#mobile_native #android #kotlin
Начинающий Android-разработчик рано или поздно сталкивается с задачей определения основных параметров экрана — ширины и высоты. С появлением Apple-подобной «брови» в верхней части дисплея Android-устройств задача стала неочевидной.
Stack Overflow показывает несколько ответов, предполагающих использование двух нативных методов
getSize и getMetrics.У Honor 10 Lite заявленная высота экрана составляет 2340 px, но нативные методы возвращают 2139 px.
Рассмотрим пример вычисления фактического размера экрана Android-устройства.
В методе
DisplaySizeGetter.getSize определяется версия используемого SDK и устанавливается опорный тип SdkType. Для каждого типа SdkType определен свой метод getSize с реализацией алгоритма получения размеров в зависимости от версии SDK.Толстые репозитории
#vcs #git #frontend
Существуют брендинговые проекты, содержащие большое количество медийных файлов уровня дизайна веб-сервиса. У таких сайтов контент может быть неуправляемым в силу ограниченного срока их жизни или сильной разнородности и уникальности страниц. Бизнесу просто невыгодно разрабатывать уникальную CMS.
Тогда сопровождение контента ложится на frontend-разработчиков. Тяжелые изображения, видеофайлы и иные бинарные файлы сохраняются в git-репозитории. Размер репозитория возрастает, скорость его работы замедляется. Облачные сервисы управления VCS начинают умышленно замедлять скорость клонирования/скачивания «толстых» репозиториев.
Существуют различные решения для выделения больших бинарных файлов из репозитория — CDN-сервисы, сервисы хранения статики. Для хранения бинарной статики в Git мы используем Git Large File Storage, который поддерживается на популярных площадках: GitHub, BitBucket, GitLab.
При инициализации Git LFS для указанных типов файлов в репозитории формируются и хранятся ссылки на них. Сами файлы хранятся отдельно и в единственном экземпляре в специальном хранилище.
Для того чтобы начать работать с Git LFS, необходимо установить соответствующий пакет и убедиться в его поддержке на вашем хостинге удаленных репозиториев. Кстати, эта услуга может быть платной.
Например, мы хотим хранить все файлы с расширением
#vcs #git #frontend
Существуют брендинговые проекты, содержащие большое количество медийных файлов уровня дизайна веб-сервиса. У таких сайтов контент может быть неуправляемым в силу ограниченного срока их жизни или сильной разнородности и уникальности страниц. Бизнесу просто невыгодно разрабатывать уникальную CMS.
Тогда сопровождение контента ложится на frontend-разработчиков. Тяжелые изображения, видеофайлы и иные бинарные файлы сохраняются в git-репозитории. Размер репозитория возрастает, скорость его работы замедляется. Облачные сервисы управления VCS начинают умышленно замедлять скорость клонирования/скачивания «толстых» репозиториев.
Существуют различные решения для выделения больших бинарных файлов из репозитория — CDN-сервисы, сервисы хранения статики. Для хранения бинарной статики в Git мы используем Git Large File Storage, который поддерживается на популярных площадках: GitHub, BitBucket, GitLab.
При инициализации Git LFS для указанных типов файлов в репозитории формируются и хранятся ссылки на них. Сами файлы хранятся отдельно и в единственном экземпляре в специальном хранилище.
Для того чтобы начать работать с Git LFS, необходимо установить соответствующий пакет и убедиться в его поддержке на вашем хостинге удаленных репозиториев. Кстати, эта услуга может быть платной.
Например, мы хотим хранить все файлы с расширением
.jpg в директории public текущего репозитория. Для этого воспользуемся следующими командами:$ git lfs track public/**/*.jpg
$ git add .gitattributes
$ git commit -m "install Git LFS"
$ git push
Грокаем и мокаем
#mobile_native #android #kotlin
Robert Anson Heinlein «Stranger in a strange land»
В разработке сложных мобильных приложений могут протекать процессы, требующие фиктивных тестовых данных или mock-объектов. Например, процесс написания unit-тестов и запуска их в CI/CD либо демонстрация приложения в demo-режиме, где использование оригинальных источников данных невозможно или нецелесообразно.
Рассмотрим, как произвести подмену модели
Получение
Реализуем класс
Во всех фрагментах приложения мы можем использовать вызов метода
Если описать свою модель
#mobile_native #android #kotlin
Robert Anson Heinlein «Stranger in a strange land»
В разработке сложных мобильных приложений могут протекать процессы, требующие фиктивных тестовых данных или mock-объектов. Например, процесс написания unit-тестов и запуска их в CI/CD либо демонстрация приложения в demo-режиме, где использование оригинальных источников данных невозможно или нецелесообразно.
Рассмотрим, как произвести подмену модели
ViewModel на MockViewModel при реализации demo-режима приложения. Добавим в gradle-файл модуля добавим boolean-переменную, обозначив демо-сборку приложения.Получение
ViewModel во фрагменте выглядит так:ViewModelProviders.of(yourFragment).get(YourViewModel.class)
Реализуем класс
ViewModelHolder, который будет уточнять класс модели ViewModel исходя из используемого режима приложения.Во всех фрагментах приложения мы можем использовать вызов метода
getViewModel класса ViewModelHolder для получения нужной модели.ViewModelHolder.getViewModel(this,YourViewModel::class.java)
Если описать свою модель
MockYourViewModel, наследуя ее от YourViewModel, то в ней необходимо будет переопределить только те методы, которые нужно мокнуть. В gradle можно явно указать, какой тип ViewModel необходимо использовать. А использование BuildConfig.IS_DEMO не будет дублироваться по всему приложению.Самое время поставить точку
#frontend #debug #react #nodejs
Каждый современный браузер, даже IE, имеет встроенные средства отладки клиентского JavaScript. У Chrome, например, есть инструменты разработчика, которые позволяют расставлять точки останова, выводить отладочную информацию и в режиме реального времени работать с некоторыми объектами js.
У такой отладки есть минусы — вы отлаживаете уже скомпилированный js, например из EcmaScript или TypeScript. Получается, что код пишется на одном языке, а отлаживается — на другом. Иногда удобно сразу исправлять код в момент отладки.
Наши frontend-разработчики используют IDE Visual Studio Code, в которой есть удобные встроенные средства отладки кода 🐞
VS Code позволяет настраивать различные сценарии отладки — можно отлаживать и серверный, и клиентский js.
Для настройки дебагера в VS Code используется файл
Microsoft создала даже сборник рецептов настройки отладчика для различного типа приложений и языков разработки.
Например, для отладки кода на Next.js можно взять за основу вот эту инструкцию (https://github.com/Microsoft/vscode-recipes/tree/master/Next-js) и отлаживать как клиентскую, так и серверную часть вашего приложения. Не забудьте включить source-maps в настройках сборщиков для Dev-режима, чтобы отладчик показывал исходный, а не транспилированный код.
Старайтесь минимизировать использование механизмов псевдоотладки, типа console.log. Отладка в режиме runtime дает вам полностью объективную, живую картину состояния ваших переменных, объектов и текущего хода выполнения. Вы производите отладку внешними средствами, не изменяя свой код, и спите спокойно, не думая о том, что ваши
#frontend #debug #react #nodejs
Каждый современный браузер, даже IE, имеет встроенные средства отладки клиентского JavaScript. У Chrome, например, есть инструменты разработчика, которые позволяют расставлять точки останова, выводить отладочную информацию и в режиме реального времени работать с некоторыми объектами js.
У такой отладки есть минусы — вы отлаживаете уже скомпилированный js, например из EcmaScript или TypeScript. Получается, что код пишется на одном языке, а отлаживается — на другом. Иногда удобно сразу исправлять код в момент отладки.
Наши frontend-разработчики используют IDE Visual Studio Code, в которой есть удобные встроенные средства отладки кода 🐞
VS Code позволяет настраивать различные сценарии отладки — можно отлаживать и серверный, и клиентский js.
Для настройки дебагера в VS Code используется файл
./vscode/launch.json. Чтобы мы могли отлаживать браузерный js, понадобится расширение, сопрягающее работу отладчика с браузерами движка Chrome. Для отладки nodejs-кода будем использовать вот это расширение.Microsoft создала даже сборник рецептов настройки отладчика для различного типа приложений и языков разработки.
Например, для отладки кода на Next.js можно взять за основу вот эту инструкцию (https://github.com/Microsoft/vscode-recipes/tree/master/Next-js) и отлаживать как клиентскую, так и серверную часть вашего приложения. Не забудьте включить source-maps в настройках сборщиков для Dev-режима, чтобы отладчик показывал исходный, а не транспилированный код.
Старайтесь минимизировать использование механизмов псевдоотладки, типа console.log. Отладка в режиме runtime дает вам полностью объективную, живую картину состояния ваших переменных, объектов и текущего хода выполнения. Вы производите отладку внешними средствами, не изменяя свой код, и спите спокойно, не думая о том, что ваши
console.log() проявят себя на промышленном сервере или в браузере у конечного пользователя 🙃Барабаним сами
#mobile_dev #android #kotlin
Хочу такой барабан, как на iPhone
Спорить о юзабилити стандартных элементов управления мобильных ОС можно вечно. Мы не будем.
В рамках дизайна или по требованию клиента нам приходится реализовывать различного рода
На «Хабре» есть статья, которая рассказывает, как создавать
Реализуем вариант бесконечного барабана через
Для реализации эффекта барабана при прокрутке определим класс SlideLayoutManager. Метод
Пример инициализации
Реализацию XML-разметки
Оперируя различными визуальными эффектами, можно изменять внешний вид и поведение нашего барабана.
#mobile_dev #android #kotlin
Хочу такой барабан, как на iPhone
Спорить о юзабилити стандартных элементов управления мобильных ОС можно вечно. Мы не будем.
В рамках дизайна или по требованию клиента нам приходится реализовывать различного рода
Picker, которые служат основой для барабанов, слайдеров и каруселей.На «Хабре» есть статья, которая рассказывает, как создавать
Picker через Canvas. Такой подход имеет ряд недостатков. Например, сложность реализации анимированной плавной прокрутки с ускорениями и необходимость реализации метода onDraw для однотипных, но разных интерфейсов.Реализуем вариант бесконечного барабана через
SnapHelper. Picker будет оперировать списком строк List<String>, который передается в конструктор адаптера для RecyclerView. Количество элементов в этом RecyclerView будет Integer.MAX_VALUE. За счет этого мы добьемся «бесконечной» прокрутки списка.Для реализации эффекта барабана при прокрутке определим класс SlideLayoutManager. Метод
onScrollStateChanged, помимо вызова суперметода, для каждого элемента вычисляет расстояние до центра RecyclerView и возвращает позицию элемента с минимальным расстоянием. Метод scrollVerticallyBy с помощью функции scaleDownView производит корректировку визуальных составляющих элементов, например размера и цвета.Пример инициализации
Picker можно увидеть здесь.Реализацию XML-разметки
picker_item, а также размещение RecyclerView в разметке Layout оставим за кадром этой заметки.Оперируя различными визуальными эффектами, можно изменять внешний вид и поведение нашего барабана.
Останься в памяти моей
#frontend #backend #reactjs #nodejs
Даже опытный react-разработчик может не до конца осознавать, как используется оперативная память компонентами его приложения. Недавно мы обнаружили memory leak в сервисе — через N дней многопоточное приложение на стороне SSR переставало работать из-за нехватки оперативной памяти.
Оказалось, что при очередном запросе пользователя составной заголовок страницы записывался в глобальный объект, не затирая предыдущие значения.
Встречается распространенная проблема, при которой react-компонент был размонтирован, но инициализированные в нем
С ростом кодовой базы продукта увеличивается и объем хранимой информации как на стороне клиента, так и на стороне сервера. Повышается вероятность возникновения новых утечек.
На стороне клиента контролировать потребляемую браузером память и работу сборщика мусора помогают инструменты разработчика. Например, браузер Google Chrome и его DevTools позволяют делать периодические снепшоты состояния памяти в различные промежутки времени работы приложения. Снимки можно анализировать и сравнивать между собой специальными средствами.
На серверной стороне также возможно настроить мониторинг используемой памяти. Для этого необходимо запустить nodejs с флагом --inspect и открыть в Chrome специальную страницу
#frontend #backend #reactjs #nodejs
Даже опытный react-разработчик может не до конца осознавать, как используется оперативная память компонентами его приложения. Недавно мы обнаружили memory leak в сервисе — через N дней многопоточное приложение на стороне SSR переставало работать из-за нехватки оперативной памяти.
Оказалось, что при очередном запросе пользователя составной заголовок страницы записывался в глобальный объект, не затирая предыдущие значения.
Встречается распространенная проблема, при которой react-компонент был размонтирован, но инициализированные в нем
setTimeout или setInterval не были остановлены и продолжают выполняться в фоне. Сборщик мусора не будет выполнять очистку памяти от данных, используемых в этих методах, следовательно, происходит систематическая утечка памяти.С ростом кодовой базы продукта увеличивается и объем хранимой информации как на стороне клиента, так и на стороне сервера. Повышается вероятность возникновения новых утечек.
На стороне клиента контролировать потребляемую браузером память и работу сборщика мусора помогают инструменты разработчика. Например, браузер Google Chrome и его DevTools позволяют делать периодические снепшоты состояния памяти в различные промежутки времени работы приложения. Снимки можно анализировать и сравнивать между собой специальными средствами.
На серверной стороне также возможно настроить мониторинг используемой памяти. Для этого необходимо запустить nodejs с флагом --inspect и открыть в Chrome специальную страницу
chrome://inspect. Здесь настраивается интеграция с серверной частью вашего приложения для работы отладочного механизма. Затем процесс работы со снимками памяти сервера и их анализа происходит в таком же интерфейсе, как и в случае с клиентской частью.Жадный импорт
#backend #php
Разрабатывая веб-сервис для крупного застройщика, мы столкнулись с задачей импорта большого количества номенклатурных данных. Причем данные выгружались из различных корпоративных систем клиента и представляли собой файлы формата
Данные импорта содержали информацию об объектах застройки с подробными их характеристиками. Данные по каждому объекту перед сохранением в БД должны были проходить определенный препроцессинг в виде валидации, проверок существования справочной информации и определения операции вставки/изменения. Все стандартно.
Осуществляя считывание информации об объектах из различных файлов, мы накапливали информацию на промежуточных шагах в массивы. Затем обрабатывали каждый элемент этого массива — создавали промежуточные объекты для валидации и в конечном итоге модели для сохранения. Упрощенный псевдокод такого подхода можно посмотреть здесь.
При импорте большого количества данных из множества разнородных файлов потребление оперативной памяти становилось все больше. В один момент импорт съел 2 Гб.
«Хватит это терпеть», — сказал разработчик Илья и призвал на помощь генераторы. Их использование позволило избавиться от промежуточных накоплений и обрабатывать данные построчно на лету. Весь процесс импорта после внедрения генераторов стал занимать практически константное значение потребляемой RAM.
Наш псевдокод немного преобразился. Стоит отметить, что использование генераторов делает код чище и позволяет работать с нативными итераторами в PHP.
#backend #php
Разрабатывая веб-сервис для крупного застройщика, мы столкнулись с задачей импорта большого количества номенклатурных данных. Причем данные выгружались из различных корпоративных систем клиента и представляли собой файлы формата
csv и xml.Данные импорта содержали информацию об объектах застройки с подробными их характеристиками. Данные по каждому объекту перед сохранением в БД должны были проходить определенный препроцессинг в виде валидации, проверок существования справочной информации и определения операции вставки/изменения. Все стандартно.
Осуществляя считывание информации об объектах из различных файлов, мы накапливали информацию на промежуточных шагах в массивы. Затем обрабатывали каждый элемент этого массива — создавали промежуточные объекты для валидации и в конечном итоге модели для сохранения. Упрощенный псевдокод такого подхода можно посмотреть здесь.
При импорте большого количества данных из множества разнородных файлов потребление оперативной памяти становилось все больше. В один момент импорт съел 2 Гб.
«Хватит это терпеть», — сказал разработчик Илья и призвал на помощь генераторы. Их использование позволило избавиться от промежуточных накоплений и обрабатывать данные построчно на лету. Весь процесс импорта после внедрения генераторов стал занимать практически константное значение потребляемой RAM.
Наш псевдокод немного преобразился. Стоит отметить, что использование генераторов делает код чище и позволяет работать с нативными итераторами в PHP.
React: профилирование жизненного цикла
#frontend #reactjs
Среди React-разработчиков популярно браузерное расширение React DevTools, позволяющее отлаживать клиентскую часть React-приложения. Это расширение содержит полезный инструмент профилирования, который нативно поддерживается самой библиотекой React, начиная с версии 16.5.
Используя профилировщик, можно анализировать жизненный цикл и производительность вашего приложения, выявляя потенциальные проблемы оптимизации.
Рассмотрим пример уровня кода. В функциональный компонент
Такие ситуации легко обнаружить с помощью профилировщика, который покажет списки компонентов в древовидной структуре и данные по каждому компоненту: количество рендеров, текущие пропсы и затраченное время на его обновление.
В текущем примере для оптимизации повторного рендеринга компонентов применим механизм мемоизации, представленный в HOC
На Reactjs.org есть отличное введение, которого будет достаточно для базовой проверки своих проектов.
#frontend #reactjs
Среди React-разработчиков популярно браузерное расширение React DevTools, позволяющее отлаживать клиентскую часть React-приложения. Это расширение содержит полезный инструмент профилирования, который нативно поддерживается самой библиотекой React, начиная с версии 16.5.
Используя профилировщик, можно анализировать жизненный цикл и производительность вашего приложения, выявляя потенциальные проблемы оптимизации.
Рассмотрим пример уровня кода. В функциональный компонент
SomeList передается объект с данными состояния dataSource из родительского компонента App. SomeList содержит дочерний компонент SomeItem, который оперирует переданным ему dataSource-объектом. При обновлении состояния в компоненте App, даже если сам объект dataSource не изменился, производится цепной ререндер нижестоящих компонентов SomeList и SomeItem, которые отслеживают dataSource. В данном случае обновление этих компонентов является избыточным.Такие ситуации легко обнаружить с помощью профилировщика, который покажет списки компонентов в древовидной структуре и данные по каждому компоненту: количество рендеров, текущие пропсы и затраченное время на его обновление.
В текущем примере для оптимизации повторного рендеринга компонентов применим механизм мемоизации, представленный в HOC
React.memo(...). Теперь запустим профилировщик и почувствуем разницу.На Reactjs.org есть отличное введение, которого будет достаточно для базовой проверки своих проектов.
Алина и Тайный Санта
#algorithms #math #jokes
Посвящается нашему офис-менеджеру Алине
Новогодние поздравления в Студии проходят по принципу церемонии Тайного Санты. Как же офис-менеджеру Алине организовать этот процесс, сохраняя максимальную анонимность, при условии что в Студии работает 100+ человек? 😱
Каждый сотрудник должен получить адресованный ему подарок, иначе на общем вручении выйдет конфуз.
Алина берет список всех сотрудников у HR Дарьи и садится за разработку алгоритма (идет к старшему разработчику Александру).
Чтобы организовать случайность пар «дарящий — получатель», список сотрудников перемешивается и помещается в массив
Теперь в
Пары получены, но наша Алина делала все вручную, и теперь она знает все «тайны» и, что самое обидное, знает, кто подарит подарок именно ей. Исправим это с помощью HR Дарьи.
Даша и Алина делят список
З.Ы. Реализацию алгоритма оставим на усмотрение любопытного читателя. С наступающим Новым годом и Рождеством! 🎄
#algorithms #math #jokes
Посвящается нашему офис-менеджеру Алине
Новогодние поздравления в Студии проходят по принципу церемонии Тайного Санты. Как же офис-менеджеру Алине организовать этот процесс, сохраняя максимальную анонимность, при условии что в Студии работает 100+ человек? 😱
Каждый сотрудник должен получить адресованный ему подарок, иначе на общем вручении выйдет конфуз.
Алина берет список всех сотрудников у HR Дарьи и садится за разработку алгоритма (идет к старшему разработчику Александру).
Чтобы организовать случайность пар «дарящий — получатель», список сотрудников перемешивается и помещается в массив
L1. Затем элементы множества L1 циклически смещаются в любую сторону на число, не равное length(L1), и записываются в новый массив L2.Теперь в
L1[i] находится отправитель подарка для получателя L2[i]. Читателю должно быть очевидно 😂, что получившееся отображение f: L1 -> L2 биективно, а потому подарки достанутся всем. 🎁Пары получены, но наша Алина делала все вручную, и теперь она знает все «тайны» и, что самое обидное, знает, кто подарит подарок именно ей. Исправим это с помощью HR Дарьи.
Даша и Алина делят список
L1 на L11 и L12 таким образом, что Даша находится в одном списке, а Алина — в другом. Каждая из девочек выбирает себе половину списка, в котором нет ее фамилии/имени. Повторим процедуру перемешивания и сдвижки для списков L1j, сохраняя список со сдвигом в L2j. Теперь в L1j[i] находится отправитель подарка для L2j[i], где j = 1,2. Очевидно, что полученные отображения f1j: L1j -> L2j также биективны. Все учтено при полной секретности. 😎З.Ы. Реализацию алгоритма оставим на усмотрение любопытного читателя. С наступающим Новым годом и Рождеством! 🎄
Контент — это мы
#backend #frontend #qa #mobile
Авторы заметок канала Chulakov Dev — это реальные люди, лучшие специалисты Студии №1 в России.
Уникальный контент — это реальный опыт решения насущных и сложных задач в рамках крупнейших проектов.
Команда Студии Олега Чулакова поздравляет вас с Новым годом и Рождеством. В наступившем 2020 году мы продолжим публикации и постараемся сделать их еще интереснее.
#backend #frontend #qa #mobile
Авторы заметок канала Chulakov Dev — это реальные люди, лучшие специалисты Студии №1 в России.
Уникальный контент — это реальный опыт решения насущных и сложных задач в рамках крупнейших проектов.
Команда Студии Олега Чулакова поздравляет вас с Новым годом и Рождеством. В наступившем 2020 году мы продолжим публикации и постараемся сделать их еще интереснее.
Отлично, оптимизируем дальше
#backend #php #orm
Разрабатывая веб-сервис для крупного застройщика, мы сделали ставку на архитектуру проекта для удобства сопровождения и расширения. В прошлой заметке мы рассказали об оптимизации импорта с сохранением удобства разработки, а сегодня поделимся судьбой импортированных данных при доставке их конечному пользователю.
Первоначально, в пострелизный период, сервис хранил и обрабатывал около 300 квартир с сопутствующими номенклатурными данными. Для обеспечения реактивности интерфейсов и удобства вывода данные о сущностях и их атрибутах собирались в единую структуру. Это позволяло достаточно быстро перестраивать клиентский вывод без дополнительных REST-запросов, при этом фильтруя и сортируя данные.
Сервис развивался, и в какой-то момент нам выгрузили 1200 квартир. С учетом всех реляций количество связанных объектов стало достаточно большим — на одну квартиру приходилось около 12 связанных объектов с нетривиальной выборкой через ActiveRecord-модели. Конечный набор json-данных стал формироваться за 4 секунды.
«Хватит это терпеть», — сказал разработчик Илья и принялся оптимизировать, вооружившись профайлером и литром пива. Исходные данные профайлера: 4 секунды, 64 Мб памяти и более 140 запросов в БД. Используя эти данные, мы добавили недостающие индексы по ключам на уровне СУБД, а самое главное — мы оптимизировали реляции в ActiveRecord-моделях и сократили количество запросов к БД. После первой итерации профайлер показал следующее: 3 секунды, 32 Мб памяти и 80 запросов в БД.
Для того чтобы выборки одних и тех же данных не дублировались для каждой квартиры, все справочные данные были вынесены в отдельные запросы для единоразового выполнения.
После этой итерации мы получили следующие результаты: 1,5 секунды исполнения, 24 Мб и 54 запроса. Профайлер показал, что бОльшая часть времени тратится на манипуляции с ActiveRecord-моделями — инициализация и маппинг данных в объекты.
«Не на массивах же все это делать»
На последнем этапе оптимизации мы отказались от использования ORM. ActiveRecord-модели были заменены на заполнение простых DTO-объектов. Общение с БД и выборку данных мы реализовали через построитель запросов фреймворка Yii. Финальный результат: 0,4 секунды, 18 Мб памяти и около 32 запросов в БД.
#backend #php #orm
Разрабатывая веб-сервис для крупного застройщика, мы сделали ставку на архитектуру проекта для удобства сопровождения и расширения. В прошлой заметке мы рассказали об оптимизации импорта с сохранением удобства разработки, а сегодня поделимся судьбой импортированных данных при доставке их конечному пользователю.
Первоначально, в пострелизный период, сервис хранил и обрабатывал около 300 квартир с сопутствующими номенклатурными данными. Для обеспечения реактивности интерфейсов и удобства вывода данные о сущностях и их атрибутах собирались в единую структуру. Это позволяло достаточно быстро перестраивать клиентский вывод без дополнительных REST-запросов, при этом фильтруя и сортируя данные.
Сервис развивался, и в какой-то момент нам выгрузили 1200 квартир. С учетом всех реляций количество связанных объектов стало достаточно большим — на одну квартиру приходилось около 12 связанных объектов с нетривиальной выборкой через ActiveRecord-модели. Конечный набор json-данных стал формироваться за 4 секунды.
«Хватит это терпеть», — сказал разработчик Илья и принялся оптимизировать, вооружившись профайлером и литром пива. Исходные данные профайлера: 4 секунды, 64 Мб памяти и более 140 запросов в БД. Используя эти данные, мы добавили недостающие индексы по ключам на уровне СУБД, а самое главное — мы оптимизировали реляции в ActiveRecord-моделях и сократили количество запросов к БД. После первой итерации профайлер показал следующее: 3 секунды, 32 Мб памяти и 80 запросов в БД.
Для того чтобы выборки одних и тех же данных не дублировались для каждой квартиры, все справочные данные были вынесены в отдельные запросы для единоразового выполнения.
После этой итерации мы получили следующие результаты: 1,5 секунды исполнения, 24 Мб и 54 запроса. Профайлер показал, что бОльшая часть времени тратится на манипуляции с ActiveRecord-моделями — инициализация и маппинг данных в объекты.
«Не на массивах же все это делать»
На последнем этапе оптимизации мы отказались от использования ORM. ActiveRecord-модели были заменены на заполнение простых DTO-объектов. Общение с БД и выборку данных мы реализовали через построитель запросов фреймворка Yii. Финальный результат: 0,4 секунды, 18 Мб памяти и около 32 запросов в БД.
ViewPager2. Подглядываем красиво
#mobile_native #android #java
20 ноября 2019 года вышла в релиз стабильная версия нового инструмента для пошагового показа экранов в ОС Android —
Произведем инициализацию
Реализуем свой адаптер и сверстаем элемент, используемый в нем.
Реализацию фрагмента, содержащего
Необходимо заставить объект
В качестве объекта-трансформера страницы мы устанавливаем экземпляр класса YourPagerTransformer, который позволяет показывать часть левого и правого элемента списка при скролле.
Если ширина экрана
Стоит отметить, что с помощью различных реализаций
#mobile_native #android #java
20 ноября 2019 года вышла в релиз стабильная версия нового инструмента для пошагового показа экранов в ОС Android —
ViewPager2. Переход с первой версии облегчается преемственностью синтаксиса ViewPager. Также новый компонент использует адаптеры на основе абстрактных классов RecyclerView.Adapter или FragmentStateAdapter при работе с фрагментом.Произведем инициализацию
ViewPager2 таким образом, чтобы были видны половинки предыдущей и последующей страниц.Реализуем свой адаптер и сверстаем элемент, используемый в нем.
YourAdapter готов к работе.Реализацию фрагмента, содержащего
ViewPager2, можно посмотреть здесь.Необходимо заставить объект
viewPager игнорировать padding-ограничения. За это отвечают строки 14 и 15 класса YourFragment.java.В качестве объекта-трансформера страницы мы устанавливаем экземпляр класса YourPagerTransformer, который позволяет показывать часть левого и правого элемента списка при скролле.
Если ширина экрана
WIDTH пикселей, а контент в layout/item.xml занимает x пикселей, то величина marginPx, которая будет передаваться в YourPagerTransformer, должна находиться в пределах WIDTH - x < marginPx < (WIDTH - x) / 2, чтобы левый и правый элемент были видны. Иначе они сдвинутся недостаточно далеко, чтобы показаться, или наложатся друг на друга.Стоит отметить, что с помощью различных реализаций
PageTransformer можно применять разные эффекты прокрутки.Простая UI-локализация
#mobile_dev #ios #swift
Apple Xcode позволяет локализовывать интерфейсные статические текстовые метки, ресурсы приложения — иконки, изображения, звуковые файлы и форматы вывода даты/время/валюты/единиц измерения.
В этой заметке поговорим о работе с мультиязычными статическими текстами в коде приложения.
Первым делом в Xcode создается файл Localizable.strings, который на уровне проекта является агрегацией файлов с переводами текстовых меток на различные языки. А на уровне файловой системы для каждого языка будет создана папка <LocaleId>.lproj и файл Localizable.strings в ней.
В составе фреймворка Foundation для локализации строк предусмотрена глобальная функция NSLocalizedString.
Функция NSLocalizedString под капотом вызывает метод localizedStringForKey:value:table: объекта Bundle приложения, который возвращает локализованную строку.
Упростим себе жизнь. Чаще всего фразы переводов в рамках одного источника ресурсов можно хранить в одной таблице. Тогда можно создать свою функцию-обертку local, которая получает только параметр key.
Файлы Localizable.strings содержат пары «"ключ" = "значение"», где ключом выступает параметр, переданный нашей функции local(), а значением — языковая вариация строки.
Например, этот код демонстрирует процесс получения значений заголовка, сообщения и текста кнопки для системного алерта.
Языковые фразы, например, для русской локализации будут извлечены из этого файла.
#mobile_dev #ios #swift
Apple Xcode позволяет локализовывать интерфейсные статические текстовые метки, ресурсы приложения — иконки, изображения, звуковые файлы и форматы вывода даты/время/валюты/единиц измерения.
В этой заметке поговорим о работе с мультиязычными статическими текстами в коде приложения.
Первым делом в Xcode создается файл Localizable.strings, который на уровне проекта является агрегацией файлов с переводами текстовых меток на различные языки. А на уровне файловой системы для каждого языка будет создана папка <LocaleId>.lproj и файл Localizable.strings в ней.
В составе фреймворка Foundation для локализации строк предусмотрена глобальная функция NSLocalizedString.
Функция NSLocalizedString под капотом вызывает метод localizedStringForKey:value:table: объекта Bundle приложения, который возвращает локализованную строку.
Упростим себе жизнь. Чаще всего фразы переводов в рамках одного источника ресурсов можно хранить в одной таблице. Тогда можно создать свою функцию-обертку local, которая получает только параметр key.
Файлы Localizable.strings содержат пары «"ключ" = "значение"», где ключом выступает параметр, переданный нашей функции local(), а значением — языковая вариация строки.
Например, этот код демонстрирует процесс получения значений заголовка, сообщения и текста кнопки для системного алерта.
Языковые фразы, например, для русской локализации будут извлечены из этого файла.
Алло, мы ищем таланты!
#job #frontend #react #redux
Если ты уверенный Frontend Developer и не понаслышке знаешь про React.js + Redux, а также работаешь с Next.js, то ты именно тот человек, который нам нужен.
Сегодня мы ищем сразу несколько супергероев:
— Middle Frontend Developer в наш московский офис для работы над проектом крупнейшего банка, в офисе клиента (блек-джек, штаб-квартира и daily cash прилагаются);
— Middle+ или Senior Frontend Developer в главный ростовский офис для управления командами разработчиков и работой над лучшими проектами страны.
Звони или пиши нам:
+7 863 303-61-91
hr@chulakov.ru
https://vk.com/olegchulakovstudio
https://www.instagram.com/chulakov.ru
Ты нужен нам, а мы — тебе 😎
#job #frontend #react #redux
Если ты уверенный Frontend Developer и не понаслышке знаешь про React.js + Redux, а также работаешь с Next.js, то ты именно тот человек, который нам нужен.
Сегодня мы ищем сразу несколько супергероев:
— Middle Frontend Developer в наш московский офис для работы над проектом крупнейшего банка, в офисе клиента (блек-джек, штаб-квартира и daily cash прилагаются);
— Middle+ или Senior Frontend Developer в главный ростовский офис для управления командами разработчиков и работой над лучшими проектами страны.
Звони или пиши нам:
+7 863 303-61-91
hr@chulakov.ru
https://vk.com/olegchulakovstudio
https://www.instagram.com/chulakov.ru
Ты нужен нам, а мы — тебе 😎
Сюрпризы с UITableView
#mobile_dev #ios #swift
С помощью стандартного табличного класса UITableView из UIKit часто необходимо показать алерт-сообщение по тапу на определенную ячейку.
Если у ячейки таблицы установлен
Избавиться от такого странного поведения можно, обернув код вывода алерта в dispatch-блок так или так.
При использовании других значений для свойства selectionStyle проблема не воспроизводится.
#mobile_dev #ios #swift
С помощью стандартного табличного класса UITableView из UIKit часто необходимо показать алерт-сообщение по тапу на определенную ячейку.
Если у ячейки таблицы установлен
cell.selectionStyle = .none, то желаемый алерт будет отображен с заметной задержкой. Баг воспроизводится с iOS 8.1 и до сих пор не исправлен.Избавиться от такого странного поведения можно, обернув код вывода алерта в dispatch-блок так или так.
При использовании других значений для свойства selectionStyle проблема не воспроизводится.
QR на службе у QA
#frontend #qa
Любой веб-разработчик/тестировщик сталкивается с проблемой ввода URL в адресную строку различных мобильных устройств.
Как просматривать многостраничник на трех десктопах и пяти мобильных устройствах и не сойти с ума?
Есть ряд способов упростить задачу передачи ссылок между устройствами, которые решают вопрос частично. Можно использовать сервисы генерации коротких URL и продолжать ручной ввод полученных адресов на разных устройствах. Существуют сервисы синхронизации устройств, что не всегда безопасно, да и одним таким сервисом для зоопарка устройств не обойтись.
Мы решаем эту проблему, используя автогенерацию QR-кодов. Для браузера Google Chrome существует полезное расширение, шифрующее ссылку текущей страницы в QR-код. Далее с помощью любого мобильного устройства сканируем этот код, и вуаля — мы на нужной странице.
Мобильные устройства Apple, начиная с версии iOS 11, нативно имеют встроенный QR-ридер в приложении «Камера». Для Android-устройств используем сторонние приложения из Google Play.
С помощью QR-кодов можно шифровать не только ссылки для перехода, но и текстовые заметки, легко передавая их между устройствами.
Рекомендуем к использованию!
#frontend #qa
Любой веб-разработчик/тестировщик сталкивается с проблемой ввода URL в адресную строку различных мобильных устройств.
Как просматривать многостраничник на трех десктопах и пяти мобильных устройствах и не сойти с ума?
Есть ряд способов упростить задачу передачи ссылок между устройствами, которые решают вопрос частично. Можно использовать сервисы генерации коротких URL и продолжать ручной ввод полученных адресов на разных устройствах. Существуют сервисы синхронизации устройств, что не всегда безопасно, да и одним таким сервисом для зоопарка устройств не обойтись.
Мы решаем эту проблему, используя автогенерацию QR-кодов. Для браузера Google Chrome существует полезное расширение, шифрующее ссылку текущей страницы в QR-код. Далее с помощью любого мобильного устройства сканируем этот код, и вуаля — мы на нужной странице.
Мобильные устройства Apple, начиная с версии iOS 11, нативно имеют встроенный QR-ридер в приложении «Камера». Для Android-устройств используем сторонние приложения из Google Play.
С помощью QR-кодов можно шифровать не только ссылки для перехода, но и текстовые заметки, легко передавая их между устройствами.
Рекомендуем к использованию!
Веб тестируй без труда, на любых устройствах
#qa #frontend
Браузеры на основе Chromium по праву считаются лидерами по числу активных пользователей. Технологии этой платформы применяются даже для создания кроссплатформенных десктопных приложений, например, на фреймворке Electron.
Каждый QA-инженер мечтает об отсутствии других браузеров и движков, в реалиях же имеет целый зоопарк устройств с различными версиями обозревателей. Все это семейство разнородных платформ приходится постоянно поддерживать, следить за совместимостью, обновлять, откатывать и запускать, используя виртуальные машины.
Некоторые QA-специалисты Студии работают в офисе клиента над LTS-продуктами, иногда в другом городе. В таких условиях передача или перевозка физических устройств для тестирования веб-сервисов невозможны.
На помощь приходят облачные сервисы, которые позволяют тестировщику взаимодействовать с банком реальных и виртуальных устройств с нужными браузерами и операционными системами. Взаимодействие происходит прямо из окна вашего браузера в RDP-подобном режиме.
Для того чтобы взаимодействовать с локально развернутыми в тестовом окружении веб-сайтами, облачные сервисы позволяют устанавливать VPN-подобное соединение посредством специального клиентского софта.
Примерами таких SaaS являются BrowserStack, Sauce Labs, LambdaTest. Множество сервисов и конкурентная среда удерживают цены на достаточно демократичном уровне, что позволяет сэкономить в краткосрочной перспективе деньги на физических устройствах.
#qa #frontend
Браузеры на основе Chromium по праву считаются лидерами по числу активных пользователей. Технологии этой платформы применяются даже для создания кроссплатформенных десктопных приложений, например, на фреймворке Electron.
Каждый QA-инженер мечтает об отсутствии других браузеров и движков, в реалиях же имеет целый зоопарк устройств с различными версиями обозревателей. Все это семейство разнородных платформ приходится постоянно поддерживать, следить за совместимостью, обновлять, откатывать и запускать, используя виртуальные машины.
Некоторые QA-специалисты Студии работают в офисе клиента над LTS-продуктами, иногда в другом городе. В таких условиях передача или перевозка физических устройств для тестирования веб-сервисов невозможны.
На помощь приходят облачные сервисы, которые позволяют тестировщику взаимодействовать с банком реальных и виртуальных устройств с нужными браузерами и операционными системами. Взаимодействие происходит прямо из окна вашего браузера в RDP-подобном режиме.
Для того чтобы взаимодействовать с локально развернутыми в тестовом окружении веб-сайтами, облачные сервисы позволяют устанавливать VPN-подобное соединение посредством специального клиентского софта.
Примерами таких SaaS являются BrowserStack, Sauce Labs, LambdaTest. Множество сервисов и конкурентная среда удерживают цены на достаточно демократичном уровне, что позволяет сэкономить в краткосрочной перспективе деньги на физических устройствах.
Ты видишь LS? — Вот и я не вижу, а он есть!
#qa #frontend
Разработка frontend-части веб-сервиса на основе интерактивных макетов упрощает жизнь верстальщику, позволяя более гибко работать с примитивами. При этом можно столкнуться с некоторыми неочевидными проблемами.
Например, при копировании текста из Sketch-макета и вставке его в верстку встречается «невидимый» символ U+2028. Line Separator реализует перенос последующего за ним текста на новую строку, однако его интерпретация и поведение в обозревателе могут зависеть и от браузера, и от операционной системы. Более того, не все редакторы кода подсвечивают этот символ.
Так, при просмотре верстки в Google Chrome такие символы будут отображаться пользователю как
Мы решаем эту проблему с помощью линтера, заменяя или подсвечивая нежелательные символы в коде. Такие символы также идентифицируются при просмотре DOM в Chrome DevTools и отображаются в виде красной точки.
#qa #frontend
Разработка frontend-части веб-сервиса на основе интерактивных макетов упрощает жизнь верстальщику, позволяя более гибко работать с примитивами. При этом можно столкнуться с некоторыми неочевидными проблемами.
Например, при копировании текста из Sketch-макета и вставке его в верстку встречается «невидимый» символ U+2028. Line Separator реализует перенос последующего за ним текста на новую строку, однако его интерпретация и поведение в обозревателе могут зависеть и от браузера, и от операционной системы. Более того, не все редакторы кода подсвечивают этот символ.
Так, при просмотре верстки в Google Chrome такие символы будут отображаться пользователю как
[LSEP] в ОС Windows 10 и [x] в ОС Android. В то время как пользователям MacOS и Windows 7 с применением любых браузеров они просто не видны.Мы решаем эту проблему с помощью линтера, заменяя или подсвечивая нежелательные символы в коде. Такие символы также идентифицируются при просмотре DOM в Chrome DevTools и отображаются в виде красной точки.