All streams
Search
Write a publication
Pull to refresh
-11
-0.1
Send message

Клиенту и главреду надо метаться по всем 3-м уровням (что их изматывает).

Если бы вы делали то же самое, но в стиле WaterFall (сделали N препринтов, потом N эскизов и т.д.) - нагрузка бы не ощущалась.

Переключение контекста отнимает силы.

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

Клиенты платят за "экспертность"

(т.е. они приходят, а вы делаете работу)

У вас нарисована постройка частного космического корабля.

https://www.youtube.com/watch?v=wqXelhHjNkU

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

BeforeExecution, afterExecution - да, здоро что есть логирование времени исполнения, но это лучше вынести в Debug (#if DEBUG ... #endif). Начал дебажить - смотри сколько какой метод исполняется.

Да и в общем, в VisualStudio есть профилирование, скорее всего эти отметки по времени ничего не дадут. (а метод может быть вызван и 1м раз в минуту :) )

Ну, ошибку нашли?

Как специальность называется?

Инженер-программист.

Какие пиковые загрузки? В трекере задачу передвинуть - минута дел.

Если после этого не начинается "Как задача на час?! Тут дел на 57 минут! Смотри, за 20 минут сделал!"

Не нравятся оценки в часах - делайте оценки в StoryPoint-ах.

Трекер используется для планирования, а не для "ой, а я делаю по 100 классов в день и 1к строк"!

Ну, уже писали - спасибо новому методу глобальной оптимизации

(правда, на графах из Action вы можете не инициировать новую точку, а добавлять дочерний узел)

https://habr.com/ru/companies/redmadrobot/articles/933222/comments/#comment_28650248

С этим методом и Sakana, и прочие Gemini выходят ровно на 33% в LastExam.

Кстати оригинальную публикацию заминусили на хабре:

https://habr.com/ru/articles/720592/

Продолжайте информировать нас о бесплатных "разработках" рекламных фирм.

Поздравляю, это глобальная оптимизация без бассейнов притяжения.

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

Раскрытие произвольных узлов (исследование пространства), и улучшение лучшего решения

https://habr.com/ru/articles/720592

(https://medium.com/@pushkarevvaleriyandreevich/gradient-descent-that-we-must-have-5a4542e218a0)

Оценили даже астрофизики, выдвигаемые на нобелевку, хабр не оценил )

Ого, а я тоже знаю как прикрутить NLU к SMT Solver-у )

(подсказка - все знают)

https://habr.com/ru/companies/bothub/news/921440/comments/#comment_28480890

Опять 20-200 млрд $ с рекламы утекли вникуда?

https://coub.com/view/2x2tpc

Погодите, сейчас еще с солверов подтянется чернь (они там уже свои суперПК строят)

Ну да, об этом все кто даже немного могут в machineLearning знали еще 3-5 лет назад.

Все комментарии в стиле "Знаете, я рад за BrainFloat и чудеса DeepLearning, которые позволяют делать аппраксимации всего, но вы говорите о T-9 (автозаполнение). Там даже декартов квадрат и прочие композиции\декомпозиции\данные\условия не могут разделить."

Сразу минусуются.

Ну а Bidirectional A*\Integer-linear programming есть у всех.

Да очнитесь уже, найм в IT мертв:

https://habr.com/ru/news/928888

https://habr.com/ru/articles/920084

Начинается - то красные флаги в резюме, то "вкаты на мидла":

https://habr.com/ru/articles/931200

Это был прикол.

Ну, очередной Гений, приехавший в США решил срубить бабла, и поставить антивирус всюду.

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

В результате - Meltdown Spectre еще с тех годов (гении торопились).

Это все ... О, МОНЕТКА!

Ну так есть OpenSource со всеми корректировками GPS по стационарной точке и прочим.

Убираем кабину, добавляем Lidar/камеру.

(благо Китай выпускает эти лидары по рублю ведро)

Трактор готов.

https://habr.com/ru/companies/tractorpilot/articles/880596

Это полностью электрический трактор, оснащённый литий-ионной батареей и синхронным электродвигателем с постоянными магнитами

Ого, а не дороговато?

Ждать ли версию с Генератор-Двигатель?

Хотя в обслуживании проще:

Проверьте сопротивления обмоток.

Проверьте IGBT сборку.

Проверьте батарею.

Проверьте электронику

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

Вы ошибаетесь, просто не хотите этого признавать

В общем, с базы получаем доменные сущности (богатые доменные модели).

Для агрегатов - если агрегаты используются много где - можно выделить отдельный сервис, возвращающий требуемый AggregateRoot.

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

Ну и про специфичные поля

Специфичные поля - это на уровне команд (например, у нас есть действие ОбновитьПоле. Принимаем Id и значение поля. Например, это действие может выполнять лишь какая-то роль. В UseCase достаем по Id наш AggregateRoot, выставляем поле, сохраняем. Т.е. на уровне приложения новые доменные сущности создавать не надо, все что может пригодится можно построить через свой Include к AggregateRoot.

Ограничение на то, что обновляем задано в команде.

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

Богатая доменная модель из которой вынесены правила - удобно. Всегда можно отладить поток исполнения (сразу видно, где по статусу не так перевели\не то значение записали. Если логики - тысяча преобразований, ошибки видно сразу.

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

Тогда такие поля можно пометить атрибутом и уже по атрибуту вызывать свой Include в источник данных. (Кодогенерация)

В своем Include написать - если Include типа T(Или ICollection<T>), вызываем все дополнительные Include для сущности T. IIncudeConfiguration<T>. То же самое и в источнике данных.

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

Либо часто используемый агрегат выносить в отдельный сервис (например, Весь Заказ и прочее, чтобы не копипастить).

В итоге - со слоя с данными всегда приходят полные валидные обьекты\агрегаты. Вот такой Metadata-Driven framework для DDD :)

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

Это плохая практика.

Есть доменная сущность - надо оперировать доменной сущностью. И делать из них агрегаты.

Такие проекты (где тянут необходимые поля) очень быстро разрастаются и появляется дублирование логики. Архитектура прежде всего о расширяемости и поддерживаемости.

Можно делать 2 сущности - Full и Short одна с только необходимыми пролями, и полная (с длинными текстами и т.д.)

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

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

  1. По идее даже можно сделать их несколько штук, под каждый или группу UseCase, чтобы не делать один god класс, или сделать эту штуку интерфейсом.

С валидацией мы уже разобрались - в сеттерах можно вызывать свой IValidator(с IValidationRule). в EF можно инжектить свои сервисы. Хотя у нас есть источники данных и можно инжектить все сервисы там.

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

А вся работа по созданию сущностей\агрегатов ведется через AutoMapper\FluentValidator, которые поддерживают деревья обьектов (поэтому мы можем смапить и провалидировать любую сущность\агрегат без лишних хлопот - достаточно 1 маппинга на сущность).

то же самое, что и с Seal, можно сделать и с Lock (просто отключить сеттеры).

Если не лень делать лишние обьекты можно еще

добавить 3 обьекта DomainEntity - данные, DomainEntitySealed - валидный агрегат, DomainEntityLocked - Данные с БД, не изменяемые, только в валидный агрегат, и IDomainEntityLocked - интерфейс с {get;}.

Все, агрегаты какой угодно сложности с инвариантностью готовы (спасибо AutoMapper).

Данные в закрытые свойства через конструктор, возвращать из сервиса интерфейс. Все равно DomainEntityLocked будут только в БД, можно сделать internal.

Валидацию агрегата можно делать FluentValidator-ом

Меняем поле в set, вызываем Validate(this).

Все рекурсивно валидируется (если есть в агрегате).

Можно валидировать и одну доменную сущность, и какой угодно агрегат.

Вот простейший пример

Данные для сущности

namespace Aggregate.Domain
{
    internal class DomainData 
    {
        public int Id { get; set; }

        public int Count { get; set; }
        public DomainObject Build()
        {
            var res = new DomainObject
            {
                Id = Id,
                Count = Count
            };

            res.Seal();

            return res;
        }
    }
}

Базовый класс для доменных сущностей

namespace Aggregate.Domain
{
    abstract class DomainEntity 
    {
        protected bool IsSealed = false;
        public void Seal()
        {
            IsSealed = true;
        }
    }
}

И богатая доменная модель

namespace Aggregate.Domain
{
    internal class DomainObject : DomainEntity
    {
        public int Id { get; set; }

        protected int _count;
        public int Count
        {
            get
            {
                return _count;
            }
            set
            {
                if (IsSealed)
                {
                    //Проверяем
                    if (value < 0)
                        throw new Exception("Count Должен быть больше нуля");
                }
                else
                    _count = value;
                    
            }
        }
    }
}

Пример использования:

var data = new DomainData()
{
    Id = 1,
    Count = 100
};

var item = data.Build();

var data2 = new DomainData()
{
    Id = 2,
    Count = -1
};

var item2 =  data2.Build();

Аггрегат 1 создается, Агрегат 2 нет.

В Build вызываем AutoMapper, и добавляем в конфигурацию

https://stackoverflow.com/questions/6882826/how-to-make-automapper-call-a-method-after-mapping-a-viewmodel

.AfterMap((c,s) => s.Seal());

Все, агрегаты прямо богатых доменных моделей мапятся автоматом.

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

Если вам нужно получить еще неизменяемую сущность - DomainDbData

добавляете маппинги.

Если заморочится - можно просто добавить запуск FluentValidator-а в setter-ах.

Ну и весь этот бойлерплет генерировать )

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

Если по неведомой причине смотреть на 2-3 строчки вверх в стектрейске ошибки лень -

Делайте кодогенерацию, инжектите свой сервис валидации, в set запускайте валидацию агрегата.

2) Богатая доменная модель нарушает SOLID, и доменный агрегат с 7 различными валидациями по статусу - мифический.

https://habr.com/ru/articles/931866/comments/#comment_28631840

Поэтому везде, где не Orleans, рекомендуется проверять состояние агрегата при помощи FluentValidator и проч. в источнике данных, или где вы его обновляете.

3) Сделайте единый веб-маппинг. 1 доменный обьект - 1 WebDTO

Откуда у вас появятся DTO со ста полями? Для такого должна быть доменная сущность со ста полями.

Если будете на каждый UseCase писать свое DTO для каждого агрегата -можете устать

Вы устанете создавать 100 конструкторов, в 100 агрегатах )

Или делать сто .toDomain() .fromDomain() как Автор.

И делать там проверки и фабрики.

Если речь про веб - у вас могут быть очень сложные агрегаты, деревья из 5 типов обьектов и проч. (И деревья из трех типов обьектов)

Уже 2 разных агрегата с разной валидацией, или 2 разных конструктора и 2 логики валидации(!). Сложной валидации. (Потому что у одного агрегата проверяем привязанные обьекты на 3 уровне дерева, а другого - нет).

Но это с позиции CRM, где гриды и карточки обьектов первичны.

Возможно, где-то есть use-case-ы где надо прямо валидировать в момент изменения.

Например, Orleans, где нет хранилища, и нельзя все проверять там.

Но из-за непонимания DDD/CleanArchitecture вы скорее всего услышите про Инвариантность Обязательно в get/set, так написано! Rich Domain Model!

Ну и из FP - да чистые обьекты и функции в Domain/Application! Без инфраструктуры!

Скорее ответ:

Агрегатом из доменных сущностей.

Обычно доменная сущность и связанные обьекты.

Если обойтись без нарушения SOLID:

AutoMapper поддерживает вложенные обьекты,

FluentValidatior поддерживает вложенные обьекты,

EF поддерживает вложенные обьекты.

Возможно несколько ситуаций:

1) Агрегат должен иметь связанный обьект, но его нет - обрабатываем в useCase (специфичный агрегат)

2) Агрегат имеет связанный обьект - валидируем.

3) В валидаторе - если связанный обьект есть - валидируем.

Все, не надо городить 100 классов агрегатов (100 классов агрегатов - 100 проверок инвариантности). (да, я видел такое, и UseCase-ы в стиле UpdateFieldA(id,FieldA)) Обьясняют необходимостью инвариантности (BestPractice) - надо говорить что нужна только обеспечить валидность данных в хранилище.

Но это с позиции CRM, где гриды и карточки обьектов первичны.

Огромный плюс - 90% кода можно генерировать.

Богатая доменная модель:

Если с UpdateFieldA надо постоянно еще что-то делать - тут богатая модель, чтобы логику при UpdateFieldA не переписывать.

Information

Rating
Does not participate
Registered
Activity

Specialization

Software Developer, Backend Developer
Senior
From 220,000 ₽
SQL
Python
C#
ASP.NET MVC
Windows Forms
.NET
WPF
WCF
RabbitMQ