Pull to refresh
-2
0.1
Алексей @posledam

Руководитель разработки ПО

Send message

Язык программирования C# (и многие другие) плохо подходит для описания объектов предметной области. Поэтому часто я вижу натягивание совы на глобус, когда с помощью классов описываются объекты реального мира: ёжики плакали, но продолжали есть кактус. В итоге мешанина где прикладной код бизнес-логики, а где особенности языка, компилятора, среды исполнения и системы типов.

DDD+MSA это ещё одна точка раздутой сложности. Там, где декларируется всё ради "борьбы со сложностью", создаётся именно сложность. Я видал проекты, которые буквально были похоронены в первую очередь из-за DDD+MSA, даже в раздутые десятикратно сроки, проекты были провалены. Цена совершенно не соответствует ожидаемому выхлопу.

У нас сервис на шарпе работает последние пол года без ребутов, держит веб-сокет коннекты от 12 часов до недели, которые разрываются только по инициативе клиента. Соединения по grpc вообще практически бесконечные. Работает в кубере (linux). Держит адовые нагрузки, отлично масштабируется, телеметрия просто божественная, я лучше не видал вообще нигде и ни у кого.

C# это и есть кросс-платформенный язык, работает на всех платформах включая ARM. Вы видимо в спячке провели последние лет 5. Сегодня dotnet это наимощнейшая платформа, с которой сложно в принципе конкурировать и мало кто это может делать в полной мере.

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

Если мы говорим про бизнес-логику, то это сложные объекты со сложными сценариями бизнес-консистетности данных. Речь не про простейшие констрейты, которые мы можем обеспечить в БД, а гораздо более сложные. Соответственно, нужно работать с объектами. БД в данном случае выступает хранилищем данных, из которых эти объекты состоят. Единственная альтернатива ORM, это доставать плоские данные и вручную распихивать их в объекты, что не что иное, как "ручной ORM", а зачем в наш век делать что-то вручную, если это довольно легко автоматизируется? Я нахожу только два ответа: старая привычка или религия.

В моей практике я не сталкивался с ситуацией, когда ORM мне мешала, всегда только помогала. Всегда. Это вовсе не отменяет требования знать SQL, как устроены СУБД, индексы, транзакции и прочее прочее.

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

Если же за холиворы считать "бросание какашками", так это не холиворы, это банальный школьный срач, который к холиворам отношения не имеет.

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

ORM не может быть злом. Это отражение плоских данных в структуру объектов ЯП. Либо это делать руками, что по сути ни что иное, как обезьяний труд. Либо всё таки положиться на компилятор/ЯП. Проблемы начинаются в отказе от SQL для написания запросов. Простые запросы и правда нет смысла фигачить руками, а что по-сложнее уже нет смысла генерировать, так как SQL самодостаточен.

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

В C# не "всё есть объект". Есть вполне себе значимые типы (структуры) и ссылочные типы (классы). Значимые типы передаются по значению, ссылочные по ссылке (указателю). При этом можно иметь ссылку на значение или указатель. И всё это разнообразие доступно, понятно и работает без звёздочек, амперсандов и стрелочек типа ->.

Какой смысл возвращаться к специальному ссылочно-значимому синтаксису, совершенно непонятно.

Т.е. sql-файлы в нужном порядке можно выполнить и без всякого GO? Выглядит, как изобретение колеса, простите :)

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

Написать плагин, кстати, совсем не сложно. Давным-давно, помню, писал плагины даже на паскале.

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

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

Многие удивляются, а зачем FAR? Если среди этих людей есть консольщики, для которых консоль -- рабочий инструмент, то собственно для удобной работы с консолью.

Я не люблю обезьяньи команды для вывода содержимого каталога, файлов, перехода по каталогам. Это дорого по времени, даже если команды сидят в подкорке, даже с автокомплитом. FAR быстрее.

Отключение панелей для отображения чистой консоли Ctrl-O, или ESC (после добавления хоткеев из стандартного комплекта).

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

edit:<some command

Можно моментально перейти к файлу или папке, с включением переменных окружения:

goto:file/or/directory/path

Все консольные команды запоминаются в истории FAR. Консольные команды можно шаблонизировать с учётом что сейчас на левой панели и на правой, там целый космос что с этим можно делать.

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

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

Вы говорите про экземпляр чего-то, что реализует IQueryable. Провайдер. Ну так одно другому не мешает. Вы можете сделать так: Array.Empty().AsQueryable(), затем наполнить полученный экземпляр предикатами, затем можно извлечь Expression и поместить в необходимую реализацию IQueryable.

Обычно, реализации спецификаций хранят в себе Expression. Так IQueryable тоже хранит :) Т.е. он перекрывает спецификацию и Query Object. Ну и плюс, можно делать не только предикаты, но и больше.

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

Если очень хочется, из IQueryable можно извлекать выражения и встраивать их в "подзапросы", чтобы можно было делать даже так:

public static IQueryable<Contract> ByDealer(this IQueryable<Contract> linq, int dealerId)
{
   return linq.Where(p => p.Dealer.Id == dealerId);
}

public static IQueryable<Contract> ByFilifal(this IQueryable<Contract> linq, int filialId)
{
   return linq.Where(p => p.Filial.Id == filialId);
}

// затем, вуаля:

var query = dbContext.Contracts.ByDealer(123).Or().ByFilial(filialId);

Такие финты можно делать, и сильно сложнее. Другое дело, что в реальности игры с LINQ, спецификациями и прочими игрушками приносят в основном вред, и совсем не приносят пользы.

Возможностей LINQ достаточно, чтобы делать простые выборки и получить до 90% типизированных запросов. Но если выйти за рамки совсем примитивных приложений, окажется, что очень нужны и часто, оконные функции, кубы, предварительные промежуточные выборки, в общем для многих задач нужен SQL. Без плясок, приколов, попытками это запихать в LINQ. И нужно оба этих мира, чтоб программист не тратил время на проектирование спецификаций, которые как окажется потом весьма слабо и плохо комбинируются, но нужны конкретные запросы и возможность без плясок использовать SQL.

Это если конечно говорить о боевых приложениях с какой-никакой нагрузкой и хоть с какой-то сложностью в логике.

Чего это не решаются? Очень даже решаются.

public static IQueryable<Contract> ByDealer(this IQueryable<Contract> linq, int dealerId)
{
   return linq.Where(p => p.Dealer.Id == dealerId);
}

Блин, IQueyrable это спецификация. Это чистая абстракция, об этом даже говорит тот факт, что это интерфейс. DbContext это репозиторий + unit of work. В чистом виде. Когда я вижу проекты, где творят какие-то generic IRepository, мне хочется плакать. Зачем нужны эти "разные репозитории"? Это для чего?

IQueryable уже сам по себе является ни чем иным, как спецификацией. Но людям нравится городить ещё 25 абстракций поверх. Никак не угомонятся :)

1
23 ...

Information

Rating
2,272-nd
Location
Москва, Москва и Московская обл., Россия
Date of birth
Registered
Activity

Specialization

Backend Developer, Руководитель отдела разработки
Lead
From 450,000 ₽
C#
.NET
Software development
Database
High-loaded systems
Designing application architecture
Creating project architecture
Design information systems
Monitoring