О себе
Кто я. Меня зовут Артур, я Android-разработчик.
Образование. Образование получал тоже в Киеве, в Политехническом Институте, у меня диплом магистра по инженерии программного обеспечения - в декабре закончил это образование.
Но я бы не сказал, что это основной источник моих знаний, потому что я много времени уделяю самообразованию, это и курсы, и посещение конференций (пока в роли слушателя) - в принципе я бы сказал что больше знаний именно от этого получил и получаю.
Где сейчас живу. Сейчас я живу в Дании, в Копенгагене, у меня тут живет сестра и немало родственников которые убежали от войны.
Опыт. Вообще я уже успел поработать на 3х ролях - сначала был фронтенд (месяц), потом - бэкенд, по нему я закончил курсы и на опенсорсе участвовал в проекте, параллельно готовясь к собеседованиям. Потом в какой-то момент появилась вакансия у знакомых на Android, я подумал - почему бы и нет, предлагали хорошие условия, и я согласился.
Прошлое место работы. Компания называлась КарМани, через какое-то время разработка ушла в отдельную компанию ТехМани, и собственно я пришел туда джуном и дорос со временем до синьора и плюс уже менторил джуна.
Приложение было в сфере ФинТеха, всего примерно 200 тысяч скачиваний и несколько тысяч ежедневных пользователей.
Команда состояла из 3-4 разработчиков, по-разному было, плюс к нам были прикреплены 1-2 ручных тестировщика, тоже по-разному бывало.
Почему ушел с прошлого места. Тут все просто, я ушел в первый же день войны, фактически по двум причинам:
- чисто с юридической точки зрения, стало опасно работать
- с моральной точки зрения, я не мог больше работать на компанию, которая платит налоги в стране, которая на эти деньги убивает жителей моей страны.
- целеустремленность
- желание всегда докопаться до сути
- командный игрок
- лень (и плюс, и минус)
- перфекционизм (скорее минус)
Достижения на прошлом месте работы (КМ / ТехМани)
- поднятие оценки в маркете с 4,1 до 4,8, за счет:
- фиксов багов - crash-free rate увеличился примерно с 92 до 97-98 процентов
- новых фич
- проработки review flow (в какие моменты запрашивать оценку)
- внедрения in-app review (увеличило кол-во оценок в 3 раза)
- повышение разных бизнес-метрик, таких как:
- процент регистрирующихся пользователей
- процент пользователей которые переходят на следующий шаг в нашем основном пошаговом флоу
- процент клиентов которые покупают те или иные услуги
- повышение качества кода и легкости разработки:
- код-ревью
- работа над код-стайлом (разработка общих файлов конфигураций, в планах было добавить автоматические lint-проверки)
- рефакторинги (рефакторинг хранения локальных данных, рефакторинг самого большого адаптера)
- улучшения UI-я:
- добавление темной темы
- добавление возможности менять тему
- темизация статус бара (подстраивание его цвета под экран)
- добавление разных фичей:
Самые интересные задачи
1) Рефакторинг главного экрана
Описание: Экран состоял из большого вертикального списка, в котором отображались много разных сущностей, которые приходят из БД. И соответственно когда данные в БД меняются, нужно обновить и UI.
- за это все отвечал один адаптер, который фактически взял на себя много обязанностей, и плавно разросся до огромных размеров с огромными деревьями решений. Это привело к тому, что чтобы добавить карточку какой-то новой сущности в список нужно было потратить очень много времени чтобы разобраться куда вставлять новый код и убедиться не заденет ли он старые карточки (из-за механизма переиспользования вьюхолдеров)
- при обновлении одной из сущностей весь список полностью перерисовывался, просто потому что мы не можем делать иначе в базовой версии адаптера
- в будущем нужно было предусмотреть другие источники данных для адаптера, например чтобы по какому-то критерию показывалась определенная карточка - это тоже было довольно сложно сделать, так как адаптер был сильно завязан на конкретный источник данных.
- разбил адаптер на множество мелких адаптеров, по одному на каждую сущность, с использованием библиотеки от Ганса Дорфмана - adapter delegates
- вынес разные ответственности в разные сущности:
- вьюмодели, которые хранили данные которые будут отображаться на экране
- адаптеры-делегаты, которые знали как отрисовать конкретную вьюмодель на конкретной UI-карточке
- converter, который знал как превратить бизнес-модели во вьюмодели
- оркестратор, который всем руководил. Внутри него еще работали 2 дополнительных сущности:
Сам оркестратор делал следующее: позволял скормить ему разные источники данных, подписывался на них и при обновлении любых данных он скачивал в background-потоке данные из конкретного источника, конвертировал их во вьюмодели и кэшировал в общем списке всех данных. Делал он это все на едином потоке для того, чтобы избежать гонок. И после этого он отправлял данные на Main-поток где сетил их в адаптер.
- использовал адаптер с DiffUtil-ом, который позволил перерисовывать только те карточки, данные которых изменились
- еще какие-то мелкие оптимизации, которые не играют большой роли
- получилось больше сущностей и кода в целом
- но при этом:
- легко добавлять новые типы карточек, при этом есть уверенность что они никак не заденут старые
- легко добавлять любые типы источников данных, фактически для них надо реализовать несколько сущностей с четкими ответственностями
- при обновлении данных перерисовываются только те карточки, данные которых поменялись
- при транзишнах в background и обратно и в другие фрагменты и обратно данные не запрашиваются заново из БД и других источников так как они кэшируются
То есть фактически код стал намного более расширяемый, переиспользуемый и чистый.
Это была задача по рефакторингу главного экрана в приложении, который отображает большой список разных карточек. Проблем было 3:
- в него становилось все тяжелее и тяжелее вносить какие-либо изменения
- в нем происходило больше перерисовок, чем нужно
- в него нельзя было добавить новые источники данных
Для того чтобы устранить все эти проблемы пришлось написать больше кода, чем было до этого. Основная идея была в том чтобы создать несколько разных сущностей вместо одной, каждая из которых будет иметь свою зону ответственности. Также я использовал библиотеку которая называется DiffUtil - она помогает экономно работать со списками, перерисовывая только те элементы данные которых поменялись.
Таким образом после этого рефакторинга код стал намного более расширяемым, переиспользуемым и чистым.
2) Рефакторинг хранения пользовательских данных
Описание: Была сущность (Preferences Data Source), которая отвечала за хранение пользовательских настроек в виде примитивов - например это были таймстемпы обновлений и версии словарей, текущая выбранная тема и т.д. И соответственно этот класс позволял сохранять эти переменные и получать их обратно, и также он в нужные моменты очищал часть из этих переменных (например при логауте).
- бойлерплейт - при добавлении новой переменной нужно было писать как минимум 2 метода для её сеттинга и получения. Если же переменная была списком, то методов выходило еще больше и бывало что чтобы добавить одну новую переменную надо написать аж 40 строк. В общем в итоге код этого класса довольно прилично рос.
- можно было легко забыть дописать обнуление переменной в те методы в которых обнуляются все переменные
- неудобство API для асинхронного чтения (listener, который надо было оборачивать например в callbackFlow) и некоторые странности его работы (например при обнулении всех префов апдейт не приходил)
- основная проблема - бойлерплейт - решилась использованием делегатов - я создал их иерархию, в основе лежал базовый делегат который умел сохранять и получать свою переменную из хранилища, поверх него был делегат для работы с nullable-переменными (и flowable-делегат тоже был), и было много других делегатов, которые внутри себя использовали nullable-делегат - это и non-null, и числовой, списочный, маповый, был отдельный делегат с interop-ом для RxJava, который возвращал апдейты в виде Flowable.
- проблема того что можно забыть обнулить переменную в нужных методах решилась прокси-методами, создающими делегаты - фактически в этих методах ключ добавлялся в специальный список, и в обнуляющем методе просто мы проходили по этому списку и обнуляли все переменные.
- неудобство API решилось миграцией на DataStore - новую библиотеку от Google, которая как раз позиционируется как замена для Shared Preferences. Она: