Warning: Undefined array key 0 in /var/www/tgoop/function.php on line 65

Warning: Trying to access array offset on value of type null in /var/www/tgoop/function.php on line 65
262 - Telegram Web
Telegram Web
Не пирамидой мы едины
👇
👏15😁5
Теперь подробнее про пирамиду. Это попытка создать единую модель тестирования, которая подходила бы большей части проектов. Впервые о пирамиде заговорил Mike Conh в своей книге “Succeeding with Agile”. Он и предложил делать базу тестирования на основе того, что все будет тестироваться юнит тестами. Что дает очень точечное понимание проблемы, чтобы даже QA мог по отчету тестирования понять в чем проблема, да странные представления раньше были.

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

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

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

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

Если говорить конкретно про Android разработку, вот один из вариантов как можно сделать такие тесты. Берем что-то вроде robolectric, чтобы кликать по кнопкам и при этом без эмулятора. Далее делаем какие-то действия с нашим UI, а после сравниваем State слоя презентора. Разумеется в идеале, чтобы был MVI, потому как у него мы можем получать единый State и сразу его проверять, однако и на MVVM можно такое сделать.

Очень желательно чтобы при этом не было завязки на MVVM или MVI, аля сделать специальную прослойку для получения State, таким образом, чтобы если мы начали рефакторинг на другую архитектуру тесты остались нетронутыми. Разумеется если у вас MVP, то какого хрена в 2023 у вас MVP, переходите на что-то другое!

Разумеется вовсе не обязательно брать именно robolectric, тут я описываю идею концептуально. Все базируется на идеях бережливого тестирования. Нам не нужно покрывать все что можно тестами. Нужно писать минимальное количество тестов, чтобы они покрывали максимальное количество кода.
👍22😁5
Действительно TDD работает, или это как коммунизм?

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

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

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

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

Все начинают изучать TDD по Кенту Бэку с его книги. В ней максимально упрощенный пример для системы работающей с валютами. Вся эта книга это и есть тот самый sample для библиотеки. Аля вот супер простой пример, чтобы вы поняли суть, однако на практике все немного по-другому. И все начитают использовать TDD вот прям как в книге.

Разумеется TDD в чистом или теоретическом виде, когда мы перед написанием любого кода пишем тесты совершенно неработающая вещь. У нас есть куча кода на который тесты не нужны: конфиги, инициализация DI, аналитика и этот список можно увеличивать до бесконечности. Попробуйте перед тем, как начать делать верстку на Compose, сначала написать UI тест который не проходит, так как нужного UI еще нет. Правда удобно?) Поэтому когда вы видите человека, который утверждает, что весь код пишет по TDD, вероятно всего он не до конца честен, или у него в голове другое понятие про "весь код".

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

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

Вывод, как и с пирамидой тестирования, не нужно фанатично следовать за одной практикой, всегда стоит подбирать лучшее для вашей конкретной ситуации. Где-то лучше начать с кода и потом накидать тесты, где-то наоборот быстрее будет начать с теста и только потом накидать реализацию. Единого рецепта тут нет, а как где лучше может подсказать ваш скилл и опыт, поэтому чем раньше начнете писать тесты, тем лучше.
👍43🔥3
Как еще можно обеспечить качество без тестов?

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

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

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

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

Помимо инварианта есть много проверок которые за нас может сделать компилятор. В kotlin ярким примером является when с sealed class. Когда добавляем новый подкласс, не нужно писать тест, что мы обрабатываем все варианты, за нас это сделает компилятор.

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

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

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

🎛️ Фичатоглы
В одном из постов я уже указывал что фичатоглы довольно существенно ускоряют разработку так как позволяют выключить функционал если в нем обнаружились ошибки.

Сами по себе фичатоглы не про качество, а скорее про A/B тестирование. Однако они транзитивно связаны с качеством. Фичатоглы позволяют не так сильно парится о том, есть ли у нас баг или нет, мы можем в любой момент выключить фичу. Разумеется это, работает только с грамотным мониторингом, иначе как понять нужно ли выключать фичу?
👍34
Один из вариантов как можно обеспечить тестирование в android
👍8
После всего выше сказанного в воздухе витает вопрос, а как правильно тестировать то епт? Плохая новость – никто не знает, каждый проект по своему уникальный. Хорошая – у меня есть концепция, используя которую, вы с меньшей вероятностью наплодите хрень.

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

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

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

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

Затем у вас Store начинает выдавать поток State, через Flow или LiveData тут значения не имеет. И вы в тесте, просто проверяете этот самый State. На этом все, никаких страданий с мокито и проверкой, что нужный аргумент вызвался с нужными данными, никаких дурацких непонятных проверок. Максимально просто, вот мы нажали на кнопку, вот проверили состояние.

Чего имеем с таким подходом? Да в начале придется поебаться с настройкой либ, общего кода, и моковым локальным сервером, но лишь один раз и в начале. А какие плюсы всего этого?

👉 Первое. Любой тест будет очень близко повторять сценарий пользователя. Вы что-то делаете на экране, а затем проверяете объект State или Single Live event для показа диалогов и т.д. Вы тестируете то, как реально ведет себя ваша программа, а не абстрактные вещи в вакууме.

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

👉 Третье. Такие тесты будут (на самом деле не обязательно, уж как настроите) медленнее чем Unit, но при этом в десятки раз быстрее UI и при этом не будут требовать инфраструктуры с эмуляторами.

Разумеется от unit и ui тестов не нужно отказываться, но их должно быть меньше тех, про которые описал в посте.

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

Тут я описал лишь концепцию, а вот уже конкретную реализацию я возможно как-нибудь оформлю на github и скину сюда. Ставь ❤️ если хочется увидеть код.
55👍6
Хочу оформить главные, можно назвать их заповедями тестирования или постулатами, называйте как хотите. Я уже в разработке почти 6 лет и вот весь мой опыт, который есть на данный момент можно оформить так:

Зачем тесты?

👉 Тесты не избавляют от багов, не делают программу надежнее и не заставляют тебя писать чистый код. Тесты нужны лишь убедится, что ты новым кодом не сломал предыдущий, позволяют не оглядываться назад на каждом шагу
👉 Тесты имеют смысл только в том случае, если они постоянно запускаются на CI и блокируют МРы, иначе это бессмысленная трата времени, плавали знаем
👉 Тест плох, если он падает постоянно, на него перестают обращать внимания и забивают
👉 Тест плох если всегда проходит, значит он нихрена не тестирует
👉 Тест пишем только тогда, когда уверены, что нет другого механизма обеспечить качество (см. прошлые посты)
👉 Флакающие/мигающие тесты, от таких тестов нужно избавляться также быстро как гугл отказывается от проектов. Мигающие тесты приносят целый ворох проблем: не дают никакой информации, нагружают систему т.к приходится их перезапускать, и увеличивают вероятность оказаться вне поля зрения.

Как не нужно тестировать?

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

Как лучше тестировать?

👉 Тесты не должны ломаться при рефакторинге, и быть обузой. Иначе разрабы просто будут боятся рефакторить код, а это приведет к протуханию кода
👉 Тесты должны писаться также легко как и основной код
👉 В тестах может быть дублирование, так как избавление от дублирование это уже абстракция, абстракция это сложно, а сложность ведет к багам. Вам нужны баги еще и в тестах?
👉 Ассинхронность. Как показывает практика лучше ничего не подменять и тестировать в условиях реальной работы. Иначе в тестах на одном потоке все прекрасно, а в проде гонка и плавающие баги (см. подход из предыдущего поста).
👉 Тесты могут потребовать изменения в архитектуре или инфраструктуре, это ок так и должно быть. Однако внутри кода проекта не должно быть упоминаний о тестах: @visiblefortesting или idling в коде проекта это сигнал о том, что вы профакапились с архитектурой
👍2812🔥6🤔1
Итак, я уже писал свою критику разрабов, которые любят делать проксирующие интеракторы и теперь хочу обсудить, пожаловаться на проблему, которая стоит очень рядом.

Я свою карьеру начинал как backend разработчик на java. Первой моей работой была небольшая Томская конторка, которая делает медиакомплексы для общественного транспорта. Для управления этой системой был целый бэк с довольно симпатичным UI.

Вся система разрабатывалась на фреймворке spring. И вот в таких системах в коде есть одна практика, призраки которой мы можем видеть сейчас в Android разработке. Там каждому классу с логикой создавался интерфейс, а внутри уже клался класс с реализацией логики: PizdosService и внутри PizdosServiceImpl.

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

Даже в текущем проекте когда я на код ревью задаю вопрос про интерфейсы в интеракторах, мне отвечают привычное: "А вдруг там нужно будет реализацию подменить" – ядрена мать!

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

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

Еще один пример Авито. Дико успешный продукт, знаете сколько у них было инстансов БД на 2018 год, когда проекту уже был почти 10 лет? Один! Один сервер всего, ну и еще одна реплика естественно. Они тоже понимали, что если начнут шардирование раньше времени, то проебутся. Через 10 лет проекта они уже точно знали как именно им нужно растаскивать данные по разным БД.

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

Если понадобится переехать на другую базу, то возьмете и переедите, появится вторая аналитика, засучите рукава и добавите. Когда у вас четко будет стоять задача, вам будет это сделать в 100 раз проще, чем предугадать туманное будущее.
👍56🔥7🤔2🤯21
Я сейчас работаю в команде инфры и большая часть задач у меня связана с тем, чтобы другим разработчикам было удобно пилить фичи. За последние пару месяцев я в основном занимался разработкой cli инструментов.

У большинства CLI программ всегда есть два варианта как передать ключи короткий "-o" и длинный "--output". Ну так вот, сделал я CLI который в 90% случаев будет вызываться только на CI. И я подумал, ну хорошая же идея прописать ключи одной буквой, будет очень минималистично, удобно и в одну строку.
Вот что получилось в итоге:

java -jar /tia-cli.jar report -t $BRANCH_NAME -o ./tia-git -b tia-coverage -a $REF_NAME

очень понятно не правда ли?

Благо до меня сразу же дошло, что человек который после меня полезет это редактировать с ума сойдет, чтобы что-то тут поменять. Ему придется как минимум или найти доку этой проги или скачать ее себе локально и вызывать с флагом -h. Пытаясь уместить команду в одну строку, я создал гемморой другому разработчику на ровном месте. Это же и не загуглишь никак и выглядит как что-то на эльфийском.

А теперь второй вариант:

java -jar /tia-cli.jar report \
--output-dir=./tia-git \
--auto-fetch \
--bucket=sme-android-tia-coverage \
--target-branch=$BRANCH_NAME \
$REF_NAME


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

Поэтому совет в общих скриптах, CI и т.д. всегда используйте длинные версии ключей. Берегите нервы других разрабов. Короткие версии используйте только если запускаете программу локально.
👍55👎1
Так как я стал уже гуру CLI, в голову мне пришла идея, а не оформить ли список best practice по этой теме. Да в канале про android разработку! Ну а чего, все вы рано или поздно станете, или лидами, или тех лидами так или иначе, вам придется сделать парочку задач связанных с инфраструктурой.

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

👉 Не делайте CLI на java. JVM для сервера – круто, JVM для мобилки – сомнительно, но окэй, вроде работает, JVM для CLI – проклятие. Часто jar получается огромный, плюс сама jvm весит нефигово и жрет дохера ресурсов. В итоге ты это чудо не добавишь в докер образ, ибо последний разбухнет до невероятных размеров. Делайте CLI на java только в том случае, если у вас есть либа на java и вообще нет никаких других вариантов.

👉 Какой язык использовать? Если не важно как быстро должен работать скрипт берите Python, важно чтобы работал быстро – Go, если нужно еще и системные вызовы использовать и супер перфоманс – Rust. Держите в голове что в 99% случаев скорость работы будет ограничена сетью, а не CPU, поэтому берите Python и не выебывайтесь.

👉 Если не читали про unix way, то перед разработкой CLI тулзы идите и почитайте. Кратко – лучше делать несколько CLI которые хорошо делают что-то одно, чем одну CLI, которая делает все. Даже если она это делает хорошо. Атомарные CLI можно связать вместе через pipe и вообще запускать как угодно, это дает гибкость и избавит от гемора в будущем. Наверное...

👉 Не пишите обработку аргументов сами. Совет скорее для совсем начинающих, тем не менее. Охренеете это делать вручную, всегда сначала погуглите инструменты для вашего языка. Для примера, в python из коробки есть ArgumentParser который позволяет это делать в две строки.

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

👉 Не завязывайтесь на окружение. У нас есть внутренний инструмент, который завязывается на переменную окружения CI. Другими словами, работает эта CLI только на CI, и чтобы протестировать ее локально, нужно делать приседания с переменными окружения. Не делайте так, всегда должна быть возможность протестировать CLI локально.

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

👉 Про ключи писал в прошлом посте, но напомню, длинные версии на CI, короткие локально.

👉 Для всех CLI есть один негласный контракт, если много ключей, то их можно записать в файл, а вызывать CLI следующим образом: ./program @path_to_file. Таким образом можно ключи, которые меняются редко вынести в файл и сделать вызов лаконичнее.

👉 Gradle или CLI? Это тянет на отдельный пост, но давайте так. Сначала ответьте на эти вопросы: Вам нужно знать про граф зависимостей? Вам нужно как-то использовать сторонний gradle plugin? Если на один из этих вопросов вы ответили четкое "Да", делайте задачу через gradle плагин, если же сомневайтесь, лучше сделайте скрипт на python. Поверьте так будет быстрее как в разработке скрипта, дебажить gradle плагин это то еще удовольствие, так и в производительности, python скрипт в отличие от gradle не тратит время на конфигурацию или скачиванию самого себя.
👍431👎1
Ну что ребятишки, пришло время для откровенного разговора, садитесь в круг. В прошлом году я делал один такой backstage пост, больше про некоторую рефлексию, нежели про технологию. Я пишу этот пост отчасти для того, чтобы вы не подумали что я куда-то пропал, хотя это не далеко от правды. Скорее просто набор мыслей касательно канала. И да выкладываю его прям вечером, че вы мне сделаете я в другом городе!

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

Помимо этого я начал замечать в себе зачатки самоцензурирования. Это нельзя сказать – я тиммейтов оскорблю, это нельзя сказать – ведь меня сразу засмеют, это нельзя – тимлид читает меня часто, а это нельзя сказать – это небезопасно🕊️. Это к тому что я немного завидую тому же Филу из "Мы обречены", который вообще в космос улетает в своих высказываниях на ракете похуизма. У меня пока так не получается, хотя это бы сделало контент более острым что-ли, все таки я позиционирую этот канал как underground.

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

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

Что будет дальше? Сфера моих интересов просто сдвигается с углубленного погружения в Android на разработку под мобилки в целом. Это не значит, что теперь про Android я ничего писать не буду, это значит, что конкретно про Android и библиотеки для Android постов будет меньше, а больше будет про подходы, инженерные практики и computer science.
👍11226🔥6👎2
Теперь вернемся к набросам на пост про CLI. Самый интересный коммент был про то, что docker с jar можно сделать мелким и вообще jdk образы довольно минималистичные. Я пошел в docker, не поленился и скачал три образа: jdk, go и python. Скачал самые дефолтные образы, я не стал погружаться в то, на чем они основаны, вероятнее на каком-нибудь дистрибьюторе вроде ubuntu, который помимо нужных вещей, тянет за собой еще кучу всякого дерьма.

Оказалось что да, jdk самый минималистичный образ из всей троицы, тут вы меня уели ничего не скажешь: jdk – 500mb, python – 875mb, go – 850mb. Однако, и у go и у python есть alpine версия образа, т.е образ базирующийся на легковесном дистрибутиве, чтобы точно не тащить ничего лишнего. И вот тут уже go и python весят по 100mb от силы. Официальной alpine версии образа для jdk нет, так же как и нет jre версии (начиная с 11 java) в которой был бы только runtime – увы и ах.

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

Помимо этого, я все же говорю про CLI в рамках работы на CI, причем речь идет о CI для мобилок. Вот тут вообще начинаются преколы, когда узнаешь что на iOS Job гоняются не на виртуалках, а на реальных конкретных apple устройствах. И не факт, что там вообще jre есть, а вот python там будет 100%. Ну тут еще есть фактор, что когда iOS разработчики слышат сочетание букв JVM у них пена из рта начинает идти.

Касательно косяков с либами в CLI написанном на python это да, больновато. Тут go и правда выглядит более привлекательным, если CLI будет запускаться на разных устройствах у клиентов. Однако если CLI будет запускаться только на CI как часть какой-то автоматизации, то тут вы полностью контролируете все пакеты через docker образ, тем самым нивелируя эту проблему.
👍161😁1
Хочу рассказать еще одну наболевшую вещь про Gradle, про которую почему-то не принято говорить. В Gradle максимально ебанутая система логирования.

Начнем с того, что при каждом запуске любой таски в gradle, он начинает дико срать в консоль про все этапы конфигурации и порядок выполнения тасок. И я каждый раз задаюсь вопросом, нахера? Предвещая ваш вопрос: "а что делать если есть проблема, или я хочу понять выполняется ли вообще нужная мне таска", так для этого можно сделать отдельный флаг. Сами подумайте, когда вам нужна эта инфа о порядке выполнения? Только в тот момент, когда вы ищете проблему. Захера она включена по умолчанию. Я от gradle как от системы сборки по умолчанию хочу в консоли видеть только две строки: либо все хорошо и сборка успешная, либо все плохо и причину косяка, все ничего более. Однако нет, он насрет в лог 30 строк даже если сделал целое ничего.

Если кто-то пробовал разрабатывать плагин, то должен знать что gradle в каждой таске позволяет получить логер. В gradle используется интерфейс slf4j для логирования. И казалось бы, раз это slf4j который славится возможностью подсунуть свою реализацию, то писать лог можно куда угодно, да? Пизда! Gradle позволяет писать лог только в консоль, хочешь лог в файл перенаправляй поток.

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

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

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

В тему про это есть отличный доклад где разраб из Яндекса рассказывается как они избавились от всех дебажных логах у себя на бэке, и предпочли другие системы для мониторинга. В кратце, стоит всегда задумываться для чего тебе нужен конкретный лог, в каких ситуациях он тебе понадобится, и если ответ "На всякий случай", этот лог тебе не нужен!
👍27🔥6
У меня есть друг с которым мы в былые времена, когда были начинающими мидлами горели тем, чтобы сделать какой-нибудь крутой pet или open source проект. Как и подобает мидлам мы страдали страшным перфекционизмом касательно автоматизаций. Сейчас вспоминать это смешно, но тогда это казалось невероятно важным.

Для примера, перед разработкой проекта мы тратили дичайше много времени, чтобы настроить плагин, который автоматически будет отгружать релизную сборку в maven central, далее настроили линтер, но почему-то сложным путем через создание собственного плагина, эээх молодеж... Затем настроили CI для сборки и прогона тестов, затем сделали даже автоматическую проверку на то, действительно ли либа корректно отправилась в maven. Очухались только когда кореш предложил и таски в трелло автоматически двигать после мержа...

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

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

Когда вас пара человек или ты вообще один(одна) то вообще не нужно запариваться на этот счет. По одной просто причине, топливо для pet проекта дичайше ограничено и его нужно растратить очень грамотно. Если не успел потратить грамотно выгоришь и проиграешь – суровая правда жизни. В самом начале проекта все что нужно это доехать до первой заправки аналогом которой будут реальные пользователи, деньги или присоединение других разрабов. Только после первой заправки можно думать про автоматизации.

Как я делаю сейчас при подобной разрабоке, которой к слову очень мало сейчас у меня. Я кладу болт на всю автоматизацию, делаю самый минимум насколько это возможно: CI – только сборка на МР, все остальное лесом, автоматическая отправка в Maven – либо руками, либо с готовым плагином без кастомной разрабоки, тесты – смотри мой пост про тесты выше, код ревью – только самый минимум по архитектуре. Даже несмотря на это далеко не всегда хватает энергии, чего уж говорить про автоматизации выше.
👍52🔥95
У меня на кухне, как у многих, стоит Алиса. Как голосовой помощник она естественно используется только для двух вещей: включить нужную мне музыку или засечь таймер. Мне нужные только две эти функции, ничего более. Однако последнее время, каждый раз, попросив, засечь таймер, она также начинает мне предлагать либо подкаст, либо книгу, либо оформить "супер выгодную" подписку.

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

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

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

Почему так? Да потому что agp, который использует под капотом jacoco, решил что ему виднее какой код нужно модифицировать для сбора Coverage, а какой нет. Как я только не пытался заставить его модифицировать код тестов, все четно.

Вот в чем причина, Jacoco изначально был как сторонний плагин, если хочешь собирать Coverage, подключаешь его, настраиваешь как тебе нужно и он работает. Однако разработчики agp решили нам "упростить" жизнь и запихали работу с jacoco к себе внутрь и теперь как бы сами конфигурируют его как нужно. Для типичного флоу хватает более чем, но как только ты пытаешься отойти от базового использования – пожалуйте нахуй.

И вот казалось бы, ну нахера, нахера они полезли куда их не просят? Я сам разберусь как мне нужно настроить JaСoСo, чтобы он вызывался как нужно мне, а не как нафантазировали себе разрабы agp. У Gradle есть система Input Output для Task, которую они (gradle) сейчас очень активно форсят и это круто. Мне кажется каждый плагин, каждая Task в Gradle так и должна работать. Вот я что-то ей даю на вход, и вот я что-то ожидаю на выходе. В какой момент Gradle вызовет эту таску пофиг, пусть сам разбирается, мне важен только результат.

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

Если вы делаете решения для разрабов, то делайте инструменты, которые делают что-то одно хорошо. Не пытайтесь сделать инструмент который дофига на себя берет. Хороший пример либы Вортона, у него в первой версии же тоже все под капотом само конфигурировалось и даже была завязка на Gson. Однако Жека то умный, он сразу понял что это путь в никуда и теперь у того же Retrofit куча настроек на входе. И что имеем теперь? Либы Вортона использует вся индустрия, потому что они не делают ничего лишнего, а что нужно делают настолько хорошо насколько возможно.
21👍9🔥4😁3👎2
А все тут страдают синдромом самозванца? Или вы себя считаете недостаточно прокаченными, чтобы считать, что у вас синдром самозванца? Я сам частенько ловлю это ощущение, когда читаю какую-нибудь крутую статью или смотрю доклад крутых ребят. Возникает ощущение, что они все поголовно гиганты мысли, гуру программирования, а я тут такой название функции не могу 20 минут придумать. Или вот у меня друг есть, который никак не может уйти со своей галеры, потому что считает себя недостойным компании получше. Разумеется все попытки его переубедить тщетны.

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

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

NDK, C/С++. Очень базово, что-то делал в универе, но не сложнее связного списка. Когда вижу код на плюсах почему-то хочется убежать. Не ну вы видели вообще код на плюсах, он же даже выглядит пугающе.

Все что касается 3D графики. Вот это вообще ни разу не трогал, до сих пор нервничаю когда кто-то упоминает слово "шейдер". Короче, для меня шейдер это тип, который что-то не поделил с крысой.

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

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

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

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

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

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

Мультиплатформа. Казалось бы, нам android разработчикам крайне легко вкатится в это. Уже даже Compose без пяти минут как будет мультиплатфомерменным. Но чет как-то впалду с этим возится в свободное время, чтобы понять эти actual, expect и фризы, хотя вроде последние уже не нужны и они переписали мемори модель. Короче я перестал следить за новостями на этапе, где корутины вот-вот должны были сделаться многопоточными на iOS. Ну и во Flutter я только запускал Hello World. Просто после kotlin тяжело воспринимать язык, где есть ключевое слово new.
👍9721🔥9😁5
И все перечисленное выше касается только мобилки, а сколько всего я не знаю если говорить про фронтенд и бэкенд, даже подумать страшно)
👍377
Давненько не делал постов, правда в этот раз по уважительной причине. Вы не поверите, но меня очень сильно увлек compose, видимо я соскучился по UI работая в платформенной команде.

Есть у меня сторонний пет проектик, и в нем одной из кор фичей это функционал с тиндоровскими карточками. Это не приложение для дейтинга, ну, пока что... И вот значится, решил я сделать такие карточки на Compose, он же позиционируется как супер просто фреймворк для UI. Историю про то, как я делал эти карточки, зачем и почему не взял готовые, я сделаю отдельным постом, после того как выложу реализацию на github. Пока лишь напишу вывод, нихера он не простой этот ваш Compose.

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

Что я подразумеваю под сложными вещами? Это те штуки, которые выходят за рамки типичных кейсов: для gradle это будет работа с плагином jacoco как нужно мне, для корутин это сложные операторы с параллельными стримами, которые были в RxJava, но их нет во flow, для compose это кастомные ленивые списки, которые жуть какие сложные по сравнению с RecyclerView.

Тенденция у нас следующая, уровень задач, которые мы делаем каждый день остается прежним, однако порог вхождения в эти задачи становится ниже. В 90% случаев мы пилим приложения, которые отправляют какие-то запросы на бэк и рисуют какой-то UI. Если раньше нужно было посвятить концепции RxJava какое-то время, чтобы делать запросы нормально, то сейчас для обычных запросов особо не нужно напрягаться, корутины за вас все это сделают. Если раньше для кастомных UI нужно было погружаться в устройство работы View, то с Compose это в 90% не нужно и все можно сделать из стандартных компонентов. Ну и Gradle, разработчики AGP делают все, чтобы начинающим вообще не приходилось разбираться для решения задачи, главное повторить как сделано в доке.

Хорошо это или плохо? На самом деле я не знаю, возможно и в стародавние времена кто-то говорил что-то подобное про верхнеуровневые языки программирования, когда все писали на ассемблере. Удручает только факт того, что API становится проще, однако за это мы платим производительностью. Если насчет корутин и RxJava еще можно поспорить что из них лучше, то Compose пока все еще проигрывает View. Оно и понятно View оптимизировали 10 лет, а Compose в релизе без году неделя. Про Gradle я вообще молчу, для большого проекта кажется уже нужно будет сервер домой покупать.

В детстве у меня был комп с 512 mb ОЗУ под Windows XP, на котором я мог запустить GTA Vice City и еще кучу всего. Сегодня же мы имеем то, что Android 13 требует минимум 2GB ОЗУ. Минимум блять, т.е он скорее всего еще и зависать при этом будет. И вот начинаешь думать, а мы точно с этими удобными фреймворками в нужную сторону двигаемся?
👍46🔥11🤔9
Перечитал пост и понял что немного размазана получилась главная идея. Суть такая – простые задачи стало делать еще проще, сложные задачи стало делать сложнее, потому как нужно разбиратся в устройстве фреймворков, которые предоставляют удобный API, но становятся переусложнеными внутри. И при всем при этом мы еще и в производительности проседаем.
👍46👎1
Когда я начинал учить программирование, мне было не особо понятно, что это за возня со всякими переменными окружения типа JAVA_HOME. Я же скачал JDK, пусть она сама настроит себя как нужно. Тем более, idea же умеет сама билдить и запускать проекты, зачем еще нужны какие-то системы сборки и что это вообще такое?

Потом чуть повзрослев ты понимаешь, что хорошему бы не завязываться на конкретную IDE. Другие разрабы могут использовать что-то кроме idea(хотя для java проектов это странно, но такие бывают), или использовать разные версии которые будут конфликтовать, много гемора крч.

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

После, обретя уже какой-то опыт, научившись работать с системами сборки, jdk я всегда использовал тот, который идет вместе с IDE. И в этом случае у нас тоже получается зависимость от IDE, фиг знает может есть JDK быстрее и стабильнее? В этот момент тебя озаряет, а так вот зачем это мозгоебство с JAVA_HOME.

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

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

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

Да Android Studio охренительно удобная, правда все эти крутые миграции заложенные в нее больше похоже на попытки залатать архитектурные проебы в AGP, тем не менее, она умеет много чего, что еще не умеют другие IDE. И несмотря на это, чем старше становишься, тем больше пытаешься не то, чтобы отказаться от IDE и пересесть на VIM, а скорее диверсифицировать инструменты. Чтобы отказ в одной тулзе не блокировал твою работу, а для этого стоит хотя бы минимально разобраться как работают системы сборки, как студия запускает тесты и как это можно было бы использовать без студии.

Я периодически балуюсь с GO, и когда ты уже в своей экосистеме все поделал вручную, без помощи IDE, оказывается что поработать с другой экосистемой становится дико просто, ведь концептуально используются одни и те же подходы для зависимостей, билда и т.д
👍46🤔6🔥5😁21
2025/07/08 20:13:25
Back to Top
HTML Embed Code: