Imperial Orchestra — большой симфонический оркестр, организатор шоу саундтреков: Cinema Medley, Hans Zimmer’s Universe и др.
Афиша и билеты на сайтах: cinemamedley.ru www.hanszimmer.ru imperialhall.spb.ru
Last updated 4 days, 13 hours ago
Send your beautiful menfess about the beauty world right here, Beauties! <3
On Duty: Close.
KRITIK & SARAN: @.Ghiaabot (BUKAN BOT SEND PERTANYAAN!)
Partnership: @.TheBeautyBaseBot @TBBPS
Banned: @BannedTBB
Rants: @BeautyRants
Sub—Unit: @Kitchenfess
Last updated 6 days, 15 hours ago
Самый большой SALE года. Последний месяц скидок.
Интернет-магазин: only-me.ru
Чат для заказа: @onlymeconsultant
ВКонтакте: vk.com/wearonlyme
Last updated 2 months, 3 weeks ago
Смотрите под ноги, дамы и господа, ибо я собираюсь уронить немного мудрости. Когда-то давным-давно я проходил курс по тестированию. Там говорилось о 7 основных принципах тестирования. Один из них называется "Скопление ошибок", который гласит: "Ошибки часто концентрируются в небольшом числе модулей".
Этот принцип немного отдает эзотерикой, если мы обнаружили баг в какой-то фиче, то с очень высокой долей вероятности в этой фиче есть ещё баги. Не очень очевидная идея.
Однако на практике я постоянно на это натыкаюсь, вот сука, почти каждый раз. Ты делаешь какую-то фичу, в ней обнаруживается баг. Ты лезешь его чинить и по пути обнаруживаешь ещё 3 бага, а если не обнаруживаешь, тебе эти 3-4 бага прилетят от QA в ближайшее время. Ну бывало же у вас такое?
Короче, в чём мудрость: если вам прилетел баг на какую-то часть системы, приглядитесь к ней тщательнее, скорее всего, там ещё бага 3-4 рядом.
Недавно на работе возник разговор о Double check locking. Напомню если вдруг забыли. Вот представьте у вас тяжелый объект какой-то, который при создании требует кучу или памяти или времени, и вы не хотите его создавать сразу, а лениво когда понадобится. Мы можем конечно просто взять и вынести его в функцию, и потом вызвать в нужный момент:
```
private var heavy: HeavyObject? = null
fun get():HeabyObject {
if( heavy == null ){
heavy = HeavyObject()
}
return heavy
}
```
Однако, что если два потока одновременно вызовут эту функцию? Если класс действительно тяжелый, например инициализация LLM это может быть проблемой. Я уже молчу про остальные проблемы с visibility поля и прочими проблемы с многопоточкой. Тоже мне проблема, ну можно же тупо поставить синхронизацию и все, делов то.
```
private var heavy: HeavyObject? = null
fun get():HeabyObject = synchronized { … }
```
Ну вот и все, это решает все возможные проблемы. Правда теперь мы каждый раз используем Mutex даже на чтение, не особо эффективно получается.
Чтобы решить эту проблему, придумали подход называемый Double check locking, который используется в Dagger кстати. Суть проста, давай захватывать Mutex только если мы видим что объект еще не проинициализирован.
```
@Volatile
private var heavy: HeavyObject? = null
fun get(): HeavyObject {
var result: HeavyObject? = heavy
if (result == null) {
synchronized(lock) {
result = heavy
if (result == null) {
result = HeavyObject()
heavy = result
}
}
}
return result!!
}
```
Ну понимаете да, сначала чекаем на null, затем захватываем Mutex и еще раз чекаем, ведь кто-то мог захватить Mutex раньше и уже проинициализировать поле. Поэтому и double check.
В целом метод рабочий, хоть и не очень изящный. Однако, в фолиантах истории, есть еще один подход, о котором знают лишь единицы, он доступен только самым достойным (душнилам короче).
Есть у JVM одна интересная особенность, все static блоки выполняются thread safe, т.е JVM их автоматически синхронизирует потому как важно гарантировать что этот блок вызовется лишь один раз. Еще фишка static блоков в том, что они вызываются только в момент обращения к классу. Поэтому мы можем использовать эту систему, чтобы сделать ленивую инициализацию:
```
private object FieldHolder {
val field: HeavyObject = createObject()
private fun createObject(): HeavyObject = HeavyObject()
}
fun get(): HeavyObject {
return FieldHolder.field
}
```
Не особо верится, что тут действительно ленивая инициализация или что оно thread safe. Ради эксперимента попробуйте сами это проверить)
Главный вопрос тут конечно, почему тот же Dagger не использует данный подход? Вероятно потому, что если на каждую зависимость будет генериться по классу Holder, а огромное количество классов, которые существуют просто для некоторой оптимизации так себе идея.
Однако в своем коде, если хотите выебнуться на МРе можете такое попробовать. Только потом не плачьте, что с вами на обед не хотят идти. Один дурачок проверял, не будут раскрывать его личность....
После публикации поста, спустя 0.0001 секунду меня обвинили в сексизме. Поэтому приношу свои глубочайшие извинения, разумеется радикальный способ могут использовать и девочки
Под прошлым постом много кто описал как можно обосраться с мобилкой, чтобы компании финансово было больно. Не сказать, что примеры сильно пугают, однако я давно не делал полезных постов, поэтому… Разбираем инженерные практики как сделать так, чтоб если даже вы повторили путь разбов AGP (сделали на релизе полную херню) минимизировать риски и не обанкротить компанию.
Когда пользователей становится очень много (что такое много зависит от приложения) всегда нужно делать несколько уровней защиты от нелепых изменений.
Разумеется мы исходим из того, что у вас уже есть какой-то минимальный мониторинг из комбинации крашлитики и аналитики, чтобы вы могли сразу отслеживать, что что-то идет не так.
1️⃣ уровень – фича тоглы. Подход заключается в том, что новые фичи или какие-то изменения мы закрываем флагом, например тупо boolean. Этот флаг у нас периодически обновляется через API. Далее через бэк мы можем открыть функциональность, когда в ней уверены. Прикол в том, что мы можем открыть не у всех пользователей, а только у части и посмотреть как пойдет. Идет криво – быстро ее закрываем и фиксим, идет нормально – увеличиваем процент пользователей. Однако есть изменения, которые не закроешь флагом. Например, какой-то глобальный рефакторинг. Тогда на сцену выходит:
2️⃣ уровень – канареечные релизы ?. Суть омерзительно проста, мы не раскатываем новую версию приложения сразу на 100% пользователей, а используем подход фича тоглов. Раскатили на 5%, подождали, посмотрели как пошло, затем на 30%, ну далее до 100%. Если происходит какая-то херня, мы вероятнее всего ее успеем отловить на первых 10%. И даже если там что-то невероятно критичное, это заденет лишь малую часть пользователей. Да больно, но что хуже отрубить палец или голову?
3️⃣ Если же, мы совсем боимся, то добавляем третий уровень – бета. В основном этот способ используют медиа приложения, но теоретически подходит всем. Тут прикол в том, что мы сначала раскатываем приложение на ограниченную группу пользователей, которые сами захотели в этом поучаствовать. Они берут на себя риски того, что у них все может вылетать и баговать, но получают новый функционал раньше. Мы же получаем возможность протестить функционал на реальных пользователях еще до релиза. Сложность в том, что если у нас например банковское приложение и мы как-то задели бабки путь даже и пользователей беты. Регулятору будет похер и придется отвечать, поэтому с этим тоже аккуратнее.
Ну и разумеется самое прекрасное тут в том, что эти методы можно комбинировать. Что значит, если хотим спать по ночам как младенцы, мы можем раскатывать приложение на бету постепенно. Пока раскатываем на бету, открываем фича флаг только для части пользователей и все время мониторим.
Можно ли при таком подходе проебаться? Разумеется да, проебаться можно во всем, уж поверьте мне, я в этом профи! Однако вероятность этого снижается настолько, насколько это возможно.
Еще одна мысль касательно разницы в подходах разработки фронта и бэка. На фронте крайне мало риска. Смотрели же Кремневую долину? Там один из персонажей когда рассказывал про себя, упомянул что его ценность в том, чтобы кривой конфиг не разорил всю компанию. И как оказалось это не просто пафосные слова.
Вот например история одного разраба, который пилил свой open source и никого не трогал. По стечению обстоятельств, он в своей тулзе по умолчанию указал свой приватный бакет в S3. Если вдруг не знаете что такое, S3 – то можно представить что это огромных размеров директория, куда можно складывать файлы через API. Когда его программа начала пользоваться популярностью, все клиенты дружно начали стучаться в этот закрытый бакет. Оказывается AWS вполне непрочь, взять за тебя бабки, даже за неавторизованный доступ.
Еще раз, бакет закрытый, доступ есть только у конкретного пользователя, однако если в этот бакет кто-то начинает ломиться, Amazon все равно списывает за такие запросы бабки. В итоге чуваку выставили счет 1500$. Справедливости ради, AWS решили пофиксить эту проблему, а то теоретически узнав бакет конкурентов, можно задешево скушать их бюджет.
Вот другая история, в которой гугл случайно удалил облако целой блять компании, вместе со всеми бэкапами. Благо разрабы компании оказались достаточно умны, чтобы не доверять гуглу и хранили бэкапы в другой системе, благодаря чему быстро восстановились. Там еще ответ гугла был в стиле: "Мы дичайше просим прощения, это повторится!" Представьте если бы разрабы доверяли гуглу полностью? Это же все, это конец бизнеса!
На фоне таких новостей я подумал, а чем мы рискуем на мобилке? Ну теоретически если мы используем firebase как базу данных, то да, при косяке можем быстро слить бюджет. Хотя кто вообще его использует, обычно все всегда делают свой бэк.
Самое опасное, что я смог придумать, это либо если из-за вашего бага бабки отправятся не туда, куда нужно и не столько сколько нужно. Или у вашего пользователя спиздят токен и что-то нахуевертят за эту минуту пока токен не обновится.
В этом случае да, тут нужно прям тщательно все тестировать. И то если у нас все на фича тоглах, то даже такую проблему можно быстро откатить.
Может у вас есть истории когда ваша ошибка на мобилке привела к финансовым потерям?
Вот это одна из причин, почему не каждый готов регулярно вести свой блог. Однако меня это пиздец как забавляет. Я пишу: "в мобилке не так много дичи, потому что она появилась позже всех". В пример аналогии привожу автопром Германии, финтех в России, либы для ML. В посте можно доебаться практически до всего, но разумеется я получаю: "Ты че пес, схерали в России лучший финтех?" и срач про регулятов.
Ладно, хорошо, давайте так, дабы снизить температуру ваших кресел я перефразирую: "В России один из лучших финтехов". Разумеется я не пробовал финтех всех стран и это лишь мое мнение. Однако у меня есть приложения 2-х Казахских банков, Американского брокера, Грузинского банка. Помимо этого я видел интерфейсы нескольких Германских банков и честно сказать, ребятам пока еще есть над чем работать. Но пост то про другое!
Касательно того, что во фронте все делают кто как хочет, а вот в мобилках есть вендор и все такое. А ничего что любой фронт выполняется в браузере, который по сути своей та же экосистема? Да этих браузеров больше чем операционок, но все они также закручивают гайки, и ты уже там не сделаешь как раньше все что тебе вздумается. Другими словами, то что на фронте куча вариантов сделать хрень, а в мобилке меньше, никак не опровергает то, что я написал. Потому как вполне возможно (я лишь предполагаю), что те кто стоял у истоков мобильной разработки как раз таки сразу смекнули, что не нужно идти по пути вэба и поэтому у нас есть вот эти гайдлайны, один UI фреймворк вместо огромной кучи и т.д.
Есть такое понятие как когнитивное искажение – шаблонные отклонения в мышлении, которые возникают из-за особенности работы нашей психики. Самое ужасное в них тот факт, что знание этих искажений не спасает от негативного влияния.
Вот например, я знаю что не нужно оверинженирить в своих pet-проектах. Ведь в таких проектах счет идет на часы пока тебе интересно, и если ты не уложился – проиграл. И важно эти часы потратить на важные вещи. Я это осознаю, да я даже пост про это писал.
Однако решил я сделать бота для телеграма, который бы ходил в chat gpt и генерил тупые шутки и лютый кринж в чате друзей. Да, по сути делал бы то, что сейчас делаю я. Разумеется я начал делать его на python, ибо рот топтал возиться с системами сборки и компиляцией, на работе этой херни хватает.
Казалось бы, что могло пойти не так? А то, что вчера я потратил 2 часа на выбор самой лучшей либы для работы с конфигами. Чтобы все было красиво, можно было задавать конфиги как твоей душе угодно, и в дебаге было удобно. Прям по заветам 12 факторов приложения.
И знаете что, я либу так и не выбрал! А знаете сколько там конфигов внутри? Один! Только токен бота телеграмма. Казалось бы, просто задай через env и все, я это понимаю, но ничего не могу с собой поделать. Прям как главный герой из фильма прочь, вроде все вижу и понимаю, но ничего не могу с этим поделать…
Пока я пишу посты, хочу поделиться с вами интересным наблюдением того, как работает самопрезентация и реклама в нашей сфере. Последнее время я пытаюсь где-то выступать, знакомится с людьми и вообще переставать быть воробушком социофобушком. Когда я рассказываю о себе, своем канале и работе, основным тезисом всегда является моя ненависть к gradle. И я это делаю не в ироничном контексте, я правда рот топтал задачи связанные с gradle и стараюсь держаться от него подальше.
Однако что слышат люди вокруг: "ооо, этот парень смешно психует про gradle, наверняка профи". Два рандомных человека пришли ко мне с консультацией по gradle, да вы чо блять? С одной стороны такая заметность приятна, с другой, я не прям мега гуру по gradle, чтобы решить любую проблему, так еще по gradle. Это буквально самая последняя вещь в программировании в которую я бы хотел погружаться. И самым крутым достижением при работе с gradle, я считаю тот факт, что еще не разбил свой рабочий ноут.
Это финальный пост про чистый код. Возможно вы уже подустали от этой темы, но я вынужден довести ее до конца. Последняя глава книги, которую я бы хотел обсудить это глава про тесты, в книге она самая потешная. Я даже тут не буду накидывать тираду про данную, главу, достаточно одного только примера. Вот пример теста который автору кажется максимально всратым:
```
@Test
public void turnOnLoTempAlarmAtThreashold() {
hw.setTemp(WAY_TOO_COLD);
controller.tic();
assertTrue(hw.heaterState());
assertTrue(hw.blowerState());
assertFalse(hw.coolerState());
assertFalse(hw.hiTempAlarm());
assertTrue(hw.loTempAlarm());
}
```
На самом деле я не вижу особых проблем в этом тесте, да много assert смущает, но тест по крайней мере читабельный и можно понять, что в нем происходит. Как же нужно исправить этот тест, спросите вы? Вот так:
@Test
public void turnOnLoTempAlarmAtThreshold() {
wayTooCold();
assertEquals("HBchL", hw.getState());
}
Ну как вам идея придумать свой птичий язык для проверок? Язык который мало того что абсолютно не читаемый, так еще его самого нужно тестировать. Я вообще не понимаю как относится к этому примеру? Возможно автору нужно было сдать быстрее книгу, а идеи кончились, либо Мартин таким образом расписался в собственном неумении писать хоть сколько-то вменяемый код.
Как нужно было сделать в данном случае? Да просто использовать конечный автомат, он тут прям напрашивается и не нужно будет городить свои птичий язык или проверку десятка флагов.
В главе очень много посвящено чистоте тестов. И вот тут как по мне есть проблема, я на практике вижу, что в большинстве случаев тесты не должны быть чистыми. Чистота у нас подразумевает избавление от дублирования, или появления каких-то абстракций. Это в свою очередь усложняет код, а тесты должны быть максимально простыми и читаемыми. В противном случае на сами тесты нужно писать тесты. Потому не ссыте в тестах делать большие функции и дублировать код.
Imperial Orchestra — большой симфонический оркестр, организатор шоу саундтреков: Cinema Medley, Hans Zimmer’s Universe и др.
Афиша и билеты на сайтах: cinemamedley.ru www.hanszimmer.ru imperialhall.spb.ru
Last updated 4 days, 13 hours ago
Send your beautiful menfess about the beauty world right here, Beauties! <3
On Duty: Close.
KRITIK & SARAN: @.Ghiaabot (BUKAN BOT SEND PERTANYAAN!)
Partnership: @.TheBeautyBaseBot @TBBPS
Banned: @BannedTBB
Rants: @BeautyRants
Sub—Unit: @Kitchenfess
Last updated 6 days, 15 hours ago
Самый большой SALE года. Последний месяц скидок.
Интернет-магазин: only-me.ru
Чат для заказа: @onlymeconsultant
ВКонтакте: vk.com/wearonlyme
Last updated 2 months, 3 weeks ago