StepOne | Степан Минин – Telegram
StepOne | Степан Минин
3.42K subscribers
247 photos
35 videos
6 files
312 links
StepOne by Степан Минин @ststphn

Твой первый шаг к успеху в программировании

Закрытый тг канал https://news.1rj.ru/str/tribute/app?startapp=slOA

По вопросам рекламы @Spiral_Yuri

Ютуб https://www.youtube.com/@steponeit
Download Telegram
StepOne | Степан Минин
Внедрение конкретной реализации в стандартном контейнере Допустим, у нас есть некоторый интерфейс, который имеет несколько реализаций: public interface IDependency {} public class DependencyImplOne : IDependency {} public class DependencyImplTwo : IDependency…
ASP NET 8 наконец-то добавит многообразие зависимостей 🥳

Реализовано это будет через ключи (например строковые).

Возвращаясь к старому примеру, он преобразится следующим образом:

public interface IDependency {}

public class DependencyImplOne : IDependency {}
public class DependencyImplTwo : IDependency {}

builder.Services.AddKeyedSingleton<IDependency, DependencyImplOne>("one");
builder.Services.AddKeyedSingleton<IDependency, DependencyImplTwo>("two");


Далее, использовать вот так, с помощью атрибута [FromKeyedServices]:

public class BarService : IBarService
{
public BarService([FromKeyedServices("one")] IDependency dependency) // DependencyImplOne
{
}
}

public class BazService : IBazService
{
public BazService([FromKeyedServices("two")] IDependency dependency) // DependencyImplTwo
{
}
}


Для меня, как поклонника ООП, это знаковая веха в развитии платформы 🔥

Считаю, что ради этой киллер фичи можно смело планировать переезд на новый LTS релиз!
🔥24👍8🤯4😱2
Почему я всегда сообщаю рекрутеру зарплатные ожидания? 🤔

Есть распространённое мнение о зарплатных переговорах: «кто первый назвал цифру, тот и проиграл».

Однако это не совсем так.

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

Во-вторых, разработчики это такие же рядовые сотрудники, как и другой персонал: для них существует вполне конкретный ФОТ.

То есть торги - это инструмент не растяжения мешка с деньгами, а прощупывания его границ.

И вот однажды я собеседовался в дом рф, попробовав всеми правдами и неправдами скрыть цифру 💵

Изворачивался и уходил от ответа так, как никогда в жизни 🤯

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

Но когда дело дошло до оффера, меня брали по верху вилки, но оказался таким, что смысл туда идти пропал абсолютно 🥵

Сказать, что чувствовал себя тогда идиотом - не сказать ничего 😁

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

А терять время не хочет никто.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍21🔥4💯4
StepOne | Степан Минин
Немного о pet project В прошлом посте я написал про то, как опыт коммерческой разработки повлиял на мой стиль его ведения. Однако, может возникнуть закономерный вопрос: «Так чем ты там занимаешься?» Отвечаю. Сейчас мой основной open source contribute -…
Правильность архитектуры проверяется при внедрении нового функционала

Кажется, написал что-то очевидное, но столкнулся с этим лично на своём pet project.

В рамках него я пишу интерпретатор TypeScript подобного языка.

Этот проект родился, как дипломная работа в бакалавриате бауманки.

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

Год назад хотел добавить в язык аналог выражения with из C#, но столкнулся с тем, что из-за спешки сделать это будет больно.

Одно из самых неправильных решений в проекте - обработка абстрактного синтаксического дерева интрузивным методом.

Подсветить то, насколько важно перейти на паттерн Visitor, помогла моя попытка внедрить DDD и выделить домен системы.

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

При этом стали видны новые точки роста - ошибки в реализации «Посетителя», изоляция домена, изменение знания одних частей системы о других и так далее.
👍10🔥4👏21
В EF Core 8 узаконили Value Object 🤩

Одно из тех обновлений, которое не следует пропускать 😱

Например, есть следующая сущность заказа Order вместе с сущностью клиента Customer:

public class Customer
{
public int Id { get; set; }
public required string Name { get; set; }
public required Address Address { get; set; }
public List<Order> Orders { get; } = new();
}

public class Order
{
public int Id { get; set; }
public required string Contents { get; set; }
public required Address ShippingAddress { get; set; }
public required Address BillingAddress { get; set; }
public Customer Customer { get; set; } = null!;
}


Кажется, что уже существует семантика работы с типами значениями, ведь никто не отменял атрибут [Owned].

Однако, при попытке сохранить сущность, которая использует один инстанс на несколько полей возникнет ошибка:

var address = GetAddress();

customer.Orders.Add(
new Order { Contents = "Tesco Tasty Treats", BillingAddress = address, ShippingAddress = address, });

await context.SaveChangesAsync();


Кажется, что всё будет хорошо, но получим исключение InvalidOperationException с сообщением

«Cannot save instance of 'Order.ShippingAddress#Address' because it is an owned entity without any reference to its owner. Owned entities can only be saved as part of an aggregate also including the owner entity.
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.PrepareToSave()»

Теперь, достаточно разметить тип данных атрибутом [ComplexType].
При этом он может быть иммутабельным!

[ComplexType]
public record Address(string Line1, string? Line2, string City, string Country, string PostCode);


Соответственно, такое обновление сущности:

customer.Address = customer.Address with { Line1 = "Peacock Lodge" };

await context.SaveChangesAsync();


Сгенерирует следующий SQL:

UPDATE [Customers] SET [Address_Line1] = @p0
OUTPUT 1
WHERE [Id] = @p1;


То есть, это собственный тип на стероидах 💉
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11👍2🎉1🤣1🏆1
partial взрывает мне мозг 🤯

Недавно решил изучить такую возможность C#, как объявление типов данных в разных файлах с помощью ключевого слова partial.

В коммерческой практике не так часто это встречалось.

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

Например, у нас есть простенький интерфейс IConract:

public interface IContract
{
void Foo();
}


Сделаем раздробленный класс MyPartialClass:

public partial class MyPartialClass
{
// ...
}


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

public partial class MyPartialClass : IContract
{
public virtual void Foo()
{
throw new NotImplementedException();
}
}


При этом виртуальный метод Foo можно спокойно переопределять в той же манере в наследниках:

public partial class MyPartialClassDerived : MyPartialClass
{
public override void Foo()
{
Console.WriteLine(this);
base.Foo();
}
}


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

Злоупотреблять таким в командной работе конечно же не рекомендую.

Однако, подобный функционал будет полезен разработчикам решений на основе Source Generators.

Таким образом, можно докидывать компилятором различные бойлерплейты, которые не хочется писать руками.
💯9🤯3🙏2
StepOne | Степан Минин
Отлаживать код в Rider смогут даже младенцы 👶 JetBrains продолжают развивать лучшую IDE для C# разработчиков и удивлять их новыми обновлениями. В грядущей версии 2023.3 завезут, на мой взгляд, настоящую killer feature, которая называется Debugger Data Flow…
Релизнулся Rider 2023.3 😱

Завезли много всего интересного: поддержку .NET 8 SDK, одновременный запуск нескольких проектов, предиктивный дебаггинг, вытащили из превью AI ассистента и многое другое

Например, добавили отрисовку диаграм зависимостей типов 🎁

Теперь можно воочию увидеть архитектуру своего проекта, и убедиться, что её нужно переделать 😱

Короче говоря, побежали обновляться! 🏃‍♂️
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥17😁31🤯1
Лучшая статья за прошедшую неделю 👍

Невольно закралась мысль о том, что все мои последние проекты могли прекрасно существовать в виде монолитов...

"Вопрос: Может ли монолит быть также эффективен как микросервисная архитектура?

Ответ: Нет, ему никогда не стать настолько же медленным
" 👏

https://habr.com/ru/articles/779362/
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9😁8👏1💯1
Тут на днях разнесли в пух и прах первичные конструкторы в C# 12

В целом я согласен со многими поинтами, и поэтому хочется посмотреть, так сказать, bigger picture.

Подумайте: есть ли у вас такое ощущение, что последней крупной и продуманной до конца фичей была добавленная в C# 5 асинхронность?

Все последующие обновления чувствуются минорными - их спокойно можно было бы нумеровать 5.1, 5.2, 5.3 и так далее.

Даже обобщённую математику не доделали до конца!

Скорее всего, проблема в том, что Андерс Хейлсберг не занимается проектом, зато о TypeScript теперь кричат из каждого утюга 🤔

https://habr.com/ru/articles/779166/
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8💯51🙏1
Контравариантность и ковариантность 🧠

В одном из профильных чатов видел сообщение о том, что упомянутая в заголовке тема даётся чуть ли не сложнее всего, что входит в основы C#.

Иногда, кажется проще запомнить наглядно, на примерах.

Также, стоит упомянуть, что всё нижеописанное актуально именно в дженериках.

Контравариантность ⬆️

Возможность подставить более базовый тип на место формального типового параметра, которая используется для объявления аргументов функций:

interface IFooIn<in TInputType>
{
void Bar(TInputType input);
}


Пример из стандартной библиотеки - IComparable<>, где благодаря контравариантности можно сделать так:

IComparable<IEnumerable<char>> charEnumerableComparable = // ...;

// ...

IComparable<string> stringComparable = charEnumerableComparable;


Ковариантность ⬇️

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

interface IFooOut<out TOutputType>
{
TOutputType Baz();
}


Пример из стандартной библиотеки - IEnumerable<>, где благодаря ковариантности можно сделать так:

IEnumerable<Task<object>> tasksWithResults = // ...;

// ...

IEnumerable<Task> tasks = tasksWithResults;


Дополнительно 🤓

Во-первых, первое и второе можно совмещать в рамках одного типа:

interface IFooInOut<in TInputType, out TOutputType>
{
TOutputType Foo(TInputType input);
}


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

В-третьих, самый смак этой фичи в том, что кастинг, который был показан выше, в силу своей неявности по перфомансу равен отсутствию кастинга, поскольку в результирующем IL отсутствуют инструкции castclass.
🤯9🔥7👍52
StepOne | Степан Минин
Правильность архитектуры проверяется при внедрении нового функционала Кажется, написал что-то очевидное, но столкнулся с этим лично на своём pet project. В рамках него я пишу интерпретатор TypeScript подобного языка. Этот проект родился, как дипломная работа…
Visitor NET. Уникальный проект

Когда я начал рефакторинг своего интерпретатора, передо мной встал вопрос, как реализовывать паттерн Visitor.

Его нужно было применить несколько раз, поскольку задач по работе с AST немало: многоэтапный статический анализ, вывод типов, кодогенерация и так далее.

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

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

Так было принято решение выделить контракты для реализации паттерна в отдельную сборку, которая потом подключалась через NuGet.

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

public interface IVisitor<in TVisitable, out T> : IVisitor
where TVisitable : IVisitable
{
T Visit(TVisitable visitable);
}


Соответственно сам визитор выглядел примерно так:

public class TypeSystemLoader :
IVisitor<ScriptBody>,
IVisitor<AbstractSyntaxTreeNode>,
IVisitor<TypeDeclaration>
{
// ...
}


Сам посещаемый элемент должен уметь вызвать visitor.Visit(this) и для этого ему нужно знать, что у типа есть правильная перегрузка метода.

Классический ациклический вариант предлагает следующую реализацию метода Accept:

public class ScriptBody : AbstractSyntaxTreeNode
{
public override void Accept(IVisitor visitor)
{
if (visitor is IVisitor<ScriptBody> typed)
typed.Visit(this);
}
}


Однако, прибегать к явному даункастингу в такой ситуации очень не хочется, потому что это лишает код полиморфности.

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

public interface IVisitable<in TVisitor, out T> : IVisitable
where TVisitor : IVisitor
{
T Accept(TVisitor visitor);
}


Такая реализация нарушала OCP и LSP, поскольку в посещаемом элементе отсутствовала единая точка входа для любого посетителя, независимая от результата обработки.

Получается нужно было обобщить сам метод Accept, чтобы склеить несколько перегрузок в одну, за счёт изменения применяемого вида полиморфизма.

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

Всего этого удалось добиться с помощью контравариантности и паттерна CRTP:

public interface IVisitor<in TVisitable, out TReturn>
where TVisitable : IVisitable<TVisitable>
{
TReturn Visit(TVisitable visitable);
}

public interface IVisitable<out TVisitable>
where TVisitable : IVisitable<TVisitable>
{
TReturn Accept<TReturn>(IVisitor<TVisitable, TReturn> visitor);
}


Тогда, в самом посещаемом элементе приходится писать два метода Accept: первый для корня иерархии, который будет вызывать посетитель; а второй уже для того, чтобы под капотом вызвался нужный Visit:

public record Operation(
char Symbol,
BinaryTreeNode Left,
BinaryTreeNode Right) : BinaryTreeNode, IVisitable<Operation>
{
public override TReturn Accept<TReturn>(
IVisitor<BinaryTreeNode, TReturn> visitor) =>
Accept(visitor);

public TReturn Accept<TReturn>(
IVisitor<Operation, TReturn> visitor) =>
visitor.Visit(this);
}


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

Таким образом, удалось решить нетривиальную задачу по созданию ациклической, универсальной, расширяемой и типобезопасной реализации шаблона Visitor без применения явного даункастинга.

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

Поэтому, давайте поддержим мой проект звездой на гитхаб ⭐️
https://github.com/Stepami/visitor-net

Нейросеть так не сможет.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥16👍72🕊2
Как вы заработали свою первую 1000 рублей в IT?

Первые деньги мне принёс заказ на создание Telegram бота на Python!
Anonymous Poll
11%
Оплачиваемая стажировка
48%
Работа
6%
Репетиторство / наставничество / менторство
20%
Фриланс
11%
Всё ещё нищук (
4%
Другое (пишите в комментариях)
🤔2👍1🤯1😱1🙏1🐳1🌭1
Что означает «CAP» в CAP теореме?

1️⃣ Consistency, Availability, Partition Tolerance

2️⃣ Control, Allocation, Process

3️⃣ Code, Architecture, Pipeline

4️⃣ Connection Access Protocol

Правильный ответ: 1️⃣

Пояснение:

CAP теорема утверждает, что в любой распределённой системе можно добиться только 2 из 3 гарантий.

Consistency - данные между узлами системы согласованы и не противоречат друг другу

Availability - любой request к системе завершается response

Partition Tolerance - выход из строя отдельных узлов системы не влияет на её общую работоспособность


Ставь 🐳 если тебя это спрашивали на собесе
Please open Telegram to view this post
VIEW IN TELEGRAM
🐳24👍13😱41👌1
Слово вкатуна. Харды на собесе

Криминальная драма, основанная на реальных событиях, все совпадения - случайны.

Отчаявшись попасть на стажировку в 😀 после соревнования Контеста, 16-летний Андрей возвращается домой и случайно видит, как пацаны за гаражами решают литкод.

Он присоединяется к пацанами, и работяги-джейсоноукладчики знакомят Андрея с учением Назрана. Благодаря им он узнает, что учить алгоритмы не обязательно (этим занимаются только стажеры-"чушпаны") - достаточно солгать в резюме про 3 года опыта, придумать 2-3 фейковых места работы - и можно будет "вкатиться" в Сбер на наносеки 200к/месяц.

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

И когда Андрей пытается «соскочить», выясняется, что теперь он должен заплатить штраф размером в полмиллиона рублей…

#пятничное от @senior_unicorn
Please open Telegram to view this post
VIEW IN TELEGRAM
😁23🔥43🥱2👍1
Дорогие подписчики StepOne 🎄

От всей души поздравляю вас с наступающим 2024 годом!

Желаю как можно меньше красноглазить с залипанием в устройства, и как можно больше проводить времени с семьёй, друзьями и близкими ❤️

Пусть у вас всё будет хорошо!

В следующем году будет много интересного...😈
Please open Telegram to view this post
VIEW IN TELEGRAM
🎉398🥰2👍1
Программисты на Си такие:

О да, valgrind 🤩
Please open Telegram to view this post
VIEW IN TELEGRAM
😁10🍌4🤯2👍1🤩1
Backlog senior разработчика be like:
😁26🤣3🤯2💯2😢1
StepOne | Степан Минин
Visitor NET. Уникальный проект Когда я начал рефакторинг своего интерпретатора, передо мной встал вопрос, как реализовывать паттерн Visitor. Его нужно было применить несколько раз, поскольку задач по работе с AST немало: многоэтапный статический анализ,…
Casting Performance 🤖

Потихоньку влился в рабочие процессы, и наконец готов выдать первый технический пост в этом году!

Сегодня мы поговорим о производительности приведения типов в разных сценариях, касающихся ковариантности и контравариантности.

Я написал простенький бенчмарк, чтобы проверить скорость работы с типами в 5 разных сценариях:

1️⃣ Direct - полное соответствие сигнатур

2️⃣ Implicit - неявное приведение благодаря особенностям вариантности

3️⃣ Explicit - использование оператора явного приведения типов

4️⃣ As - безопасное приведение через оператор as

5️⃣ Dynamic - отключение статической типизации ключевым словом dynamic

Гипотеза: Dynamic самый медленный, Explicit и As чуть помедленнее, чем Implicit и Direct

Результаты на скрине её подтверждают!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7👍51👏1🤔1