C# Short Posts 🔞 – Telegram
C# Short Posts 🔞
250 subscribers
111 photos
4 videos
151 links
Здесь я, Дима Афонченко @Undermove1, публикую короткие заметки о разработке (и около). Я не претендую на правильность высказываний и открыт к дискуссиям, исправлениям и конструктивной критике. С любыми деструктивными вещами можно приходить в комменты)
Download Telegram
🐈 Маленький победоносный пет-проект.
Вот пет-проекты это круто, но жутко порой задалбывают. Ты их начинаешь писать, чтобы отвлечься от работы, но потом тебе уже хочтся отвлечься от самих пет-проектов, и ты заводишь новый пет-проект, чтобы отвлечься от предыдущего пет-проекта. Ну а когда тебя задолбает этот пет-проект, то понятно, что ты заведешь новый и так далее.

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

💡 Типа делаете вы там супер-пупер сервис и работы там на год. Хотите отвлечься. Ну и денек пишете генератор для названий водки. Быстренько сделали, всем похвастались, ну и дальше пошли пилить свой мега-проект.

Вот так вот просто!

P.S. Начал тут такой пет-проект, а он растянулся на неделю. Вот же сука!
🔥1
Быстрое знание: console.table()
💨 Смотрел тут сторис в инстаграмме и между фотками из чужих путешествий и чужих котов проскочила инфа, что помимо console.log() в браузере можно использовать console.table()

🅰️ Так удобнее смотреть большие объекты. Сначала не поверил. Но! Проверил – работает! Юзайте.

P.S.: Хотя может я один такой не знал 😕
🤯1
😐Ресайленс и самообучение
Расскажу сейчас про охуенную штуку для изучения ресайленса!

Год назад я думал, как нам заятнуть на работу Chaos Testing. Ничего особо не получилось. Но! Удалось посмотреть такую штуку как Simmy https://github.com/Polly-Contrib/Simmy.

Simmy это версия Polly из темной всеенной 🌚. Если в Polly вы настраиваете все так чтобы у вас ничего не упало по итогу, то в Simmy вы настраиваете рандомные падения так, чтобы все деградировало каждый раз по-разному, но чтобы эти деградации выглядели реалистично. (Наконец в этом канале хоть что-то про деградацию! Услада для тех, кто пришел деградировать)

💆 Я если честно не допер, как в итоге это применить в работе. Подумал, что пока туповат. Потом посидели с чуваками на работе, потупили в код этой штуки. Он выглядит кстати вот так:

var isEnabled = true;
var chaosPolicy = MonkeyPolicy.InjectLatency(with =>
with.Latency(TimeSpan.FromSeconds(5))
.InjectionRate(0.1)
.Enabled(isEnabled)
);

В этом коде делается так чтобы 10% ваших запросов проходили с задержкой в 5 секунд.

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

Но! Но! Память об этой штуке всплыла недавно вот в этом О-ХУ-И-ТЕЛЬ-НОМ репозитории https://github.com/bjartnes/bounded-disturbances

Что это за репозиторий такой? Это полноценный готовый к запуску курс по обучению ресайленсу! Если вы каждый раз, как и я тупите, когда думаете о том сколько ретраев вам надо впихнуть в какой-либо запрос. Или просто вы не знаете ничего про Polly, то этот репозиторий это ваш абсолютный БРО!

📶 В нем есть 10 быстрых задач, в которых вам дают ненадежный канал (настроенный как раз с помощью Simmy), дают прометей и задачу – с помощью правильных настроек ресайленса (кол-ва ретраев и правил таймаута) добиться заданного SLO!

И это прям максимально прикладная задача! Это как лабы в универе, если бы все преподы в нем вылечились от маразма!

🅰️ Итого: Быстро берите эту репу, скачивайте проходите все 10 занятий и становитесь богом ресайленса! 👼 Вы никогда больше не будете смотреть на вашего httpClient'a прежними глазами, только ресайленс, только усиление!

P.S.: Ну и въебите звезду этой штуке! Давайте. Это всего лишь клик, а авторам это будет приятно!

#ресайленс
👍2
🕐Задачка: Увеличиваем надежность канала с помощью ретраев.
Окай, я на сотку готов поспорить, что хрена с два вы пойдете смотреть репозиторий из прошлого поста. Да я бы и сам подзабил, будем солидарны в этом.🦥

Но раз уж Магомед не идет к ресайленсу, то я принесу ему ресайленс сам. В виде серии микрозадачек.

Итак первая микро-ЗАДача. РазминОЧКА, так сказать:
💡 Условие: У вас есть нестабильный кАНАЛ (ладно, обещаю, что таких КАЛамбуров больше не будет), который падает в q = 15% случаев.

Ну то есть вы обращаетесь в своем коде к какому-то сервису, и в 15% случаев он возвращает ошибку (Internal Server Error).

Вопрос: Сколько ретраев минимально нужно сделать при обращении к этому сервису, чтобы обеспечить успех работоспособности вашего кода в > 99%?
 
Ответ тут (сразу скажу, что итоговая формула простая, но путь к ней надо будет вспомнить):
Вспоминаем формулу Бернулли:
Pn(k)=Cknpk⋅(1−p)nk=Cknpkqnk.
Ckn=n!/(nk)!⋅k!. -считается вот так

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

После всех упрощений и с учетом, что нам необходимо всего одно попадание она превращается в простую:
1 - q^n, где q - это процент ошибок, а n - количество ретраев.

Итого:
Для одного ретрая вероятность успеха: 1 - 0.15^2 = 0.9775
- маловато будет!
Делаем два: P = 1 - 0.15^3 = 0.9966
- уже подходит!
Попробуем три: P = 1 - 0.15^4 = 0.9995 - ого, аж три девятки! Если ваш SLA нацелен на такое количество девяток, то выбирайте большее!

Но минимально необходимое количество ретраев будет: 2


#ресайленс
3
Задача 2: улучшаем latency своего сервиса с помощью таймаутов
Во второй задаче у нас есть запрос, который в 10% случаев выдает высокую задержку в 1 секунду.

Вопрос: Какой максимальный таймаут нам нужно выставить для этого запроса, чтобы обеспечить latncy нашего метода в пределах 200 мс на 95-ом перцентиле? При этом процентом  успешности выполнения можно пренебречь.

Ответ тут (на этот раз без тервера):
По первой прикидке тут все просто – таймаут в 200мс нам точно даст требуемое значение. И это правильное предположение! Но лучше взять с запасом, к примеру в 180 мс. Практика показывает что теоретические значения при столкновении с реальностью являются лишь опорой, а не точными параметрами.

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


#ресайленс
🤯1
🦮 Задача 3: Ускоряем тормозящий канал.
Мы научились работать с ретраями и таймаутами по отдельности. Что ж давайте
скомбинируем эти знания! 🔥

Теперь у нас все так же есть сервис, задержка до которого в 10% случаев составляет 1 секунду.

Но теперь вопрос такой: какую минимальную задержку выбрать и сколько минимально ретраев нужно, чтобы в итоге 95й перцентиль задержек был меньше 200мс и при этом чтобы > 98% запросов возвращали успех?
 
Обратите внимание, что при этом сервис не выбрасывает ошибок, просто иногда подвисает на секунду.

Моя эмоциональная ремарка: Эта задача на мой взгляд просто охуительна тем, что позволяет вам получить устойчивое качество связи, при довольно неустойчивом сервисе. Да, опустим пока что ту подробность, что мы при этом повышаем нагрузку на сервис. 🌝 Но чисто математически это звучит прям пиздатенько! Прикиньте, вы сейчас придумаете штуку, которая ускорит тормозящее говно только за счет того что вовремя отсеет лишнее!

Ответ как всегда тут:
Для начала вычислим необходимый таймаут. Это мы сделаем по методу из прошлой статьи. Получится таймаут в 180 мс
 
Этот таймаут будет отсеивать примерно 10% запросов и выбрасывать ошибку TimeoutException. А теперь нам и пригодится формула из первой статьи!
Высчитываем для одного ретрая:
q = 0.1
- процент ошибок
n = 2
- количество попыток получить ответ вовремя (один изначальный запрос + один ретрай)
1-q^n = 1 - 0.1^2 = 0.99
– вполне достаточно по нашим требованиям

P.S.:
Кстати, пока считал тут все, проверял результаты на практике и перепутал
retryPolicy и timeoutPolicy местами. Из-за этого ничего не работало. Так что не путайте политики местами, надо вот так:
Policy.WrapAsync(retryPolicy, timeoutPolicy);
А не так
Policy.WrapAsync(timeoutPolicy, retryPolicy);


#ресайленс
🤔1
🥷Задача 4: Ошибки и задержки, как в реальной жизни.
Итак, мы научились бороться с тормозами, с ошибками, научились ускорять медленный канал. Чтож, теперь мы совместим все это!

У нас есть сервис, который в 10% случаев выдает задержку в 1 секунду, а вдобавок к этому падает в 10% случаев с SocketException!

А наша задача добиться следующих показателей:
Успешность запросов > 0.999 (да! Три девятки!)
При этом 95% задержек должны укладываться в 200мс!
 
Вопрос, все тот же: Сколько ретраев, и какой таймаут?
 
Ответ:
Мы можем выбрать, как и раньше таймаут в 180 мс, что даст нам падение по таймауту в примерно 10% случаев, ну и еще в 10% случаев мы и так падаем с какой-то ошибкой, тогда формула будет выглядеть так. Итого есть две несовместимых вероятности (при наступлении одной вторая не натсупит), суммарная вероятность которых равна q1^n + q2^n

А вероятность того, что ни одна ошибка не произойдет будет выглядеть так:
P = 1-(q1^n + q2^n)
Считаем:

P = 1 - (0.1^1 + 0.1^1) = 0.8 - маловато ретраев
P = 1 - (0.1^2 + 0.1^2 ) = 0.98  - маловато
P = 1 - (0.1^3+0.1^3) =   0.998  почти
P = 1 - (0.1^4+0.1^4) = 0.9998 - вот и наше значение
 
🅰️
Итого: 180 мс и 3 ретрая будет достаточно, чтобы справиться с такой ситуацией.

#ресайленс
🔥2
📌Закрепим ресайленс.
Я тут подумал, что надо бы закрепить полученные знания коротким постом.

1️⃣ Итак, если вы хотите понять, какой тайм-аут на запрос вам нужно поставить, то исходите из своих SLO в максимальном времени ответа. Если это 200 мс, то и тайм-аут нужно выбирать примерно 170-200 мс.

2️⃣ Если вы хотите понять, сколько сделать ретраев, то вам поможет формула:
1-q^n, где q это SLA сервиса к которому вы делаете запрос, а n - это количество попыток послать запрос. Увеличивая n вы в итоге подбираете такой результат этой формулы, который будет соответствовать вашему SLO.

#ресайленс
👍1
О спорах про технологии.
🇨🇳 Какой язык программирования самый лучший? Я вот думаю, что китайский. Ладно, это шутка-минутка. Не могу без них, простите.

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

Я вот недавно узнал, что мой любимый MediatR некоторые люди считают говном! (Кстати, он скоро станет частью BCL, с чем я его и поздравляю! Точнее старину Джимми Боггарта) Мол, он усложняет чтение кода, а нормального CQRS не дает.

🤬 Сначала хотелось возразить, что это все жуткая неправда, и вы все не понимаете! Вот же есть классные репозитории, у которых не зря в названии стоит CleanArchitecture и там используется MediatR! https://github.com/jasontaylordev/CleanArchitecture

Ну я собственно и возразил! Потому что, йопт, я человек или где?!

Мне в ответ кинули этой статьей https://cezarypiatek.github.io/post/why-i-dont-use-mediatr-for-cqrs/

Разумеется я поступил с материалом, как и положено порядочному оппоненту в споре – положил на нее С ПРИБОРОМ и написал в чат, что ОБЯЗАТЕЛЬНО ознакомлюсь.

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

var result = await _smsService.Send(message, ct)

чем вот это

var result = await _mediatr.Send(message, ct);
 
Конечно, уверенный пользователь медиатра не напишет такого кода. Но у нас есть новички, которые могут всякое. Могут и не так понять, как использовать. Это как в трудностях перевода – по формке все правильно, а по факту нет.

Вот тут меня и осенило. Это сейчас будет не новая мысль, но все же. Библиотеки – это расширения для языка. А значит, люди, пользующиеся разными библиотеками, по сути говорят немного на разных языках.
 
Ну точнее не совсем на разных языках, но на разных диалектах. Поэтому код, понятный одному, написанный по всем принципам SOLID может быть непонятен другому. И это вполне нормально! А значит польза или бесполезность библиотек – это дело вкуса, как и в случае с языками программирования.
 
Я вот не люблю AutoMapper (кстати, тоже въехал в BCL). Мне кажется, что в нем есть смысл только тогда, когда названия свойств в моделях одинаковые. Если же есть хоть одно отличие, то вот эти все правила маппинга, которые ты потом еще и хрен найдешь, усложняют модификацию кода. Охренеть причем как!
 
Но при этом я видел людей, которые легко находили эти правила, и придумывали понятные DSL'ки для поиска. То есть для них понятные, для остальных это все еще был пиздец.

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

Вместо тотального отрицания, лучше постараться понять, почему что-то удобно для человека, и почему может быть неудобно для вас. Нужно порефлексировать вместе, прикинуть, какие потребности вы хотите закрыть и сделать нужный выбор. Так в коллективе сложится продуктивная среда с положительным отбором технологий, а не токсичное ебаное болото, где все разрабатывают на говеной Java с библиотеками тысячелетней давности!
👍3
⛽️Кодовый газлайтинг.
Нет ничего страшнее, как мне кажется, чем кодовый газлайтинг.

Это когда ты тратишь время на проверки, выкатываешь код на прод, а потом кто-то приходит к тебе и спрашивает: "Ну как там, раскатил изменения? А то что-то ничего не поменялось."

Ты приходишь на прод, а там реально ничего не поменялось. Идешь в репу, ищешь там код. Код есть. И работает под дебагом. Изменения видны. Кнопка отображается, нажимается. Даже тесты, сука, есть и проходят!

А на проде кнопки нет! Сидишь в замешательстве (да в каком замешательстве!? ты в чистом ахуе!), думаешь на себя, что ты чертов растяпа, не проверил что-то. Вспоминаешь, как перед выкаткой позволил себе слабость – не проверил какую-то там запятую. И понимаешь, что вот ты безответственный мудак! А потом – БАЦ!

И оказывается, что просто кто-то накатил что-то поверх и просто затер случайно твою фичу... Я так пару раз чуть кукухой не поехал. 🐦
🤯1
План – не стратегия!
Я уже говорил, что обожаю Harward Business Review. Так вот теперь я их обожаю еще и в своем любимом видеоформате! И не могу не поделиться видосом про отличие стратегии от плана, которые все часто путают. А разница просто жесть какая!

Ключевые мысли видоса:
1️⃣ Стратегия – это связанный набор решений, который позволяет вам разместиться на игровом поле в положении, из которого вы можете выиграть.

2️⃣ Стратегия – это теория! Как и всякая теория она должна быть непротиворечивой и согласованной. Отвечать на вопрос, почему мы делаем что-то на этом игровом поле (читай рынке), а не на другом? И как мы будем приносить здесь большую пользу, чем конкуренты?

3️⃣ Планирование – не имеет никакой согласованности. Это просто набор действий.

4️⃣ Лидеры чаще выбирают планирование, просто потому что это проще.

🅰️ Смотреть здесь:
https://www.youtube.com/watch?v=iuYlGRnC7J8&ab_channel=HarvardBusinessReview

P.S.: А еще там важная мысль, о том, что словосочетание Стратегическое Планирование – это вообще бессмысленная хуета.
🔥1
C# Short Posts 🔞
План – не стратегия! Я уже говорил, что обожаю Harward Business Review. Так вот теперь я их обожаю еще и в своем любимом видеоформате! И не могу не поделиться видосом про отличие стратегии от плана, которые все часто путают. А разница просто жесть какая! …
Если прикладывать чисто к программистским потребностям. Допустим, у вас есть план обучения:
1) Сначала выучу алгоритмы,
2) Потом базы данных,
3) Потом еще какое-то говно.

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

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

Выбирайте стратегию! Это сложно, но окупается.
🍚 Как сделать так чтобы RICE заработал?
Я тут прохожу курс для product ownerов https://productmindset.net, и там у них есть таблица скиллов по грейдам, где один из инструментов приоритезации, которым должен уметь пользоваться крутой PO – RICE.

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

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

И я долго рефлексировал, что же с этим всем не так?

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

🅰️Если оценивать задачи по RICE внутри одного контекста, то получится гораздо лучше!

P.S. Мне вообще в последнее время кажется, что внятная стратегия для команды разработки это что-то вроде коллективного здравого смысла. Если она есть, то вам скорее всего не понадобится никакой RICE. Ну и наоборот, если вы не можете сформулировать стратегию, то никакой ветер не будет вам попутным.
🔥4
💣 Задача 5: Идемпотентность параметров при ретраях
Если вы считаете, что не стоит закладывать бомбы замедленного действия в основы вашей системы, то я сейчас вам покажу откуда такая бомба может на вас готовиться.

Вот этот ретрай не заработает. Вопрос: как думаете, почему?

[HttpGet]
public async Task<string> Get()
{
var policy = GetPolicy();
var url = new Uri(@"http://localhost:5000/someurl");
var msg = new HttpRequestMessage(HttpMethod.Get, url);

return await policy.ExecuteAsync(() => GetForecasts(msg));
}

private IAsyncPolicy GetPolicy() {
return Policy.Handle<Exception>().RetryAsync(3);
}

private async Task<string> GetForecasts(HttpRequestMessage msg)
{
var resp = await _client.SendAsync(msg);
if (_rng.NextDouble() > 0.95) {
throw new Exception( "oops");
}

return await resp.Content.ReadAsStringAsync();
}

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

#ресайленс
💣 Задача 5: Неочевидности при ретраях. Ответ

При ретрае HttpRequestMessage выдаст ошибку:

InvalidOperationException(SR.net_http_client_request_already_sent)

Чтобы это исправить, вам нужно внести переменную msg внутрь GetForecasts.

🅰️В общем, передавая параметры в лямбду при ретраях, смотрите внимательно, а не нужно ли их создавать заново при каждом запросе. Так-то! Ну признавайтесь, ведь не думали об этом!

#ресайленс
🈴 Разбор проекта с явной (Explicit) архитектурой

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

Сделал небольшой визуальный разбор статьи
DDD, Hexagonal, Onion, Clean, CQRS, … How I put it all together


На примере репозитория

Если вы, как и я запутались в ПОРТАХ и АДАПТЕРАХ и не поняли, что это такое, то этот разбор поможет вам осознать все это.

Все для вас, дорогие радиослушатели! 📻

UPD: Fuck там на певром слайде опечатка – не АДАПТЕРЫ, а ПОРТЫ.

[Вот ссылочка на miro]
👍1
dick pic
🌭1🍌1