И там и там есть пассажиры, согласен. Но на курсах не дают фундамент в виде высшей математики, теории вероятности, реляционной теории, системного и бизнес-анализа.
А потом такие люди с курсов не знают, что такое обязательные поля на форме и как они должны работать, а задачи, где надо в голове построить схему связей и принять решение, вызывают проблемы.
Сколько себя помню - атмосфера при поиске работы в ИТ всегда была токсичной.
Игноры, отказы через 5 минут после отклика, hr - проверяющие ответы по листочку, компании - мнящие себя Гуглом с его люками, шариками в автобусе и алго-собесами (недавно в статье от Яндекса аналитик признался, что это именно они оптимизируют алгоритмы, а не программисты - зачем тогда по 7 раз спрашивать алгоритмы у программистов?), тестовыми заданиями «нам некогда проверять, вы нам не подходите».
Просто раньше это решалось откликом на следующую вакансию. Сейчас такого нет.
Плюс толпа страждущих после курсов. Чую надо возвращаться к старинным способам - искать джунов в вузах (ничего личного, вас, кто закончил только курсы, слишком много на текущее количество вакансий) и ходить на собесы пешком.
Я когда пытался стать фрилансером в давние времена - просил часовую ставку моей текущей зп на тот момент (24 тыс руб в месяц). И так и не получил ни одного заказа.
А среди «заказчиков» попадались дятлы, которые хотели за 10 тыс руб получить полную копию одноклассников.
Так что всеми этими расчетами можно разве что подтереться. Они не имеют ничего общего с реальной ситуацией других людей.
У нас SaaS, у клиентов по 200-300-500 тыс заказов в день, и SLA на обработку в течение 2-3 часов. 20 rps это прям на грани, нужен запас, 50-100 rps хотя бы. И вообще конкретно эти нагрузочные тесты - слишком изолированы. Думаю в реальности там не будет 420, потому что сервер БД будет занят еще много чем другим.
public async Task ExecuteAsync(AllocateInventoryLevelRequest request, CancellationToken cancellationToken)
{
if (request is null)
throw new ArgumentNullException(nameof(request));
request.Validate(new AllocateInventoryLevelRequestValidator());
var inventoryLevelIds = request.Items
.Select(e => e.InventoryLevelId)
.Distinct()
.ToArray();
var inventoryLevels = await _inventoryLevelRepository.GetByIdsAsync(
inventoryLevelIds, cancellationToken);
foreach (var item in request.Items)
{
var inventoryLevel = inventoryLevels.FirstOrDefault(e => e.Id == item.InventoryLevelId);
if (inventoryLevel is null)
{
throw new InvalidOperationException($"Inventory not found with Id: {item.InventoryLevelId}");
}
inventoryLevel.Allocate(
item.Quantity,
item.ShipmentId,
item.ShipmentLineId,
request.IdempotencyKey,
request.Reason);
}
await _unitOfWork.SaveChangesAsync(cancellationToken);
}
DOMAIN слой (InventoryLevel)
public void Allocate(int quantity, long shipmentId, long shipmentLineId, string baseIdempotencyKey, string? reason = null)
{
var operation = new InventoryLevelOperation(
Id, baseIdempotencyKey, OperationType.Allocate,
quantity, shipmentId: shipmentId, shipmentLineId: shipmentLineId,
reason: reason);
CheckIdempotencyKey(operation.IdempotencyKey);
if (quantity <= 0)
throw new ArgumentException("Quantity must be positive.");
if (Available < quantity)
throw new InvalidOperationException("Not enough available inventory.");
Allocated += quantity;
Available -= quantity;
ValidateNonNegative();
AddOperation(operation);
}
А стало так
APPLICATION слой (AllocateInventoryLevelUseCase)
public Task ExecuteAsync(AllocateInventoryLevelRequest request, CancellationToken cancellationToken)
{
if (request is null)
throw new ArgumentNullException(nameof(request));
request.Validate(new AllocateInventoryLevelRequestValidator());
return _unitOfWork.DoRetryAsync(
ct => _inventoryLevelRepository.AllocateAsync(
request.IdempotencyKey, request.Reason,
request.Items.Serialize(), ct),
ct => Task.FromResult(true),
IsolationLevel.RepeatableRead, cancellationToken: cancellationToken);
}
У меня в голове отложилось, что логика сущности должна быть внутри сущности, а application слой - это когда нам надо координировать работу двух сущностей, ну например
var бабло = счет1.Списать();
счет2.Пополнить(бабло);
Возможно я прав или не совсем прав.
А когда речь идет про одну сущность, все должно быть внутри нее и application слой получается тонким. Собственно у меня так и получилось. Точнее один агрегат и две сущности в нем - InventoryLevel и InventoryOperation (отражает историю списания или пополнения). У InventoryLevel есть метод Reserve, который делает все что нужно.
В смысле это "все что нужно" делается в памяти сервера. А потом, когда выходит из application слоя - оно же там обернуто в unit of work и транзакцию - вот там все и сохранятся в БД.
В противном случае, если я в конкретно своем примере вытяну бизнес логику из сущности в application слой - внезапно сущность станет анемичной. А это опять не DDD.
Так изначальное утверждение было - что DDD это вообще не про код, а чисто про проектирование. Я решил перепроверить по книге. Какие примеры там были таки и привел.
Да, там я могу переложить нативный SQL из хранимки в репозиторий и целиком его отправить в БД за один поход через сеть. Но в анемичной модели это как раз позволительно, чего не скажешь о DDD.
И насчет усложнения поддержки - всегда, когда заходит речь об оптимизациях это приводит к снижению простоты читаемости кода.
Хмм, у второго упомянутого чувака в бложике есть ссылка на его книгу «почему все плохо в Ит» https://github.com/sgoedecke/gatsby-blog/blob/master/content/book/book.pdf
https://vaz-rabota.ru
Нижняя планка водителя погрузчика на уровне верхней планки инженеров.
И это 2025 год и скорее всего надо еще отнять 13%. У меня в 2007 в начале моей карьеры было 28 до вычета. Почти 20 лет прошло 😅
Вот вам и ИТ на заводах.
От заводов сложилось впечатление неадекватного руководства, на фоне отношения к итшникам как к обслуге и как результат мизерным зп.
И там и там есть пассажиры, согласен. Но на курсах не дают фундамент в виде высшей математики, теории вероятности, реляционной теории, системного и бизнес-анализа.
А потом такие люди с курсов не знают, что такое обязательные поля на форме и как они должны работать, а задачи, где надо в голове построить схему связей и принять решение, вызывают проблемы.
Ощущение что в статье описывают довольно токсичного типа, который только спорит, но не предлагает решения.
Да… кто сталкивался с локализацией знают что это боль.
Вот со второй статьи и надо было начинать. Несколько раз слышал про проблемы в орг структуре и процессах, но тему до конца не раскрывали.
Заходит тестировщик в бар и заказывает -1 кружку пива 🙃
Сколько себя помню - атмосфера при поиске работы в ИТ всегда была токсичной.
Игноры, отказы через 5 минут после отклика, hr - проверяющие ответы по листочку, компании - мнящие себя Гуглом с его люками, шариками в автобусе и алго-собесами (недавно в статье от Яндекса аналитик признался, что это именно они оптимизируют алгоритмы, а не программисты - зачем тогда по 7 раз спрашивать алгоритмы у программистов?), тестовыми заданиями «нам некогда проверять, вы нам не подходите».
Просто раньше это решалось откликом на следующую вакансию. Сейчас такого нет.
Плюс толпа страждущих после курсов. Чую надо возвращаться к старинным способам - искать джунов в вузах (ничего личного, вас, кто закончил только курсы, слишком много на текущее количество вакансий) и ходить на собесы пешком.
Пора прикручивать чат гпт в окно диалога с девушкой/парнем, чтоб подсказывал что написать
/s
Господи как они все задолбали. Только хотел комп поменять, ждал скидок.
Я когда пытался стать фрилансером в давние времена - просил часовую ставку моей текущей зп на тот момент (24 тыс руб в месяц). И так и не получил ни одного заказа.
А среди «заказчиков» попадались дятлы, которые хотели за 10 тыс руб получить полную копию одноклассников.
Так что всеми этими расчетами можно разве что подтереться. Они не имеют ничего общего с реальной ситуацией других людей.
Если что есть роман 1960 года - Бегство Земли за авторством Франсиса Карсака.
Я прочитал в свое время, меня впечатлил.
Озон спрашивает четыре медиум задачи с лит кода??? Это не опечатка?
И почему макет из фигмы для алиэкспресс выглядит как студенческая подделка-кровь-из-глаз?
У нас SaaS, у клиентов по 200-300-500 тыс заказов в день, и SLA на обработку в течение 2-3 часов. 20 rps это прям на грани, нужен запас, 50-100 rps хотя бы. И вообще конкретно эти нагрузочные тесты - слишком изолированы. Думаю в реальности там не будет 420, потому что сервер БД будет занят еще много чем другим.
Вот тут https://habr.com/ru/articles/955714/comments/#comment_28961570 я писал детали. Там были еще другие оптимизации и с тех пор я еще кое-что подкрутил. Стало стабильно 400-420 даже с проверкой остатка в конце
Кидайте логин github в личку, дам доступ.
И собственно выше в своих коментах я опубликовал часть кода. Как было (20rps) и как стало (400 rps)
Вот у меня было так
APPLICATION слой (AllocateInventoryLevelUseCase)
DOMAIN слой (InventoryLevel)
А стало так
APPLICATION слой (AllocateInventoryLevelUseCase)
Слой INFRASTRUCTURE (InventoryLevelRepository)
А ну и собственно я не могу разместить нативный SQL в application слое. Это специфика хранилища, а абстракция над хранилищем - это репозиторий.
У меня в голове отложилось, что логика сущности должна быть внутри сущности, а application слой - это когда нам надо координировать работу двух сущностей, ну например
Возможно я прав или не совсем прав.
А когда речь идет про одну сущность, все должно быть внутри нее и application слой получается тонким. Собственно у меня так и получилось. Точнее один агрегат и две сущности в нем - InventoryLevel и InventoryOperation (отражает историю списания или пополнения). У InventoryLevel есть метод Reserve, который делает все что нужно.
В смысле это "все что нужно" делается в памяти сервера. А потом, когда выходит из application слоя - оно же там обернуто в unit of work и транзакцию - вот там все и сохранятся в БД.
В противном случае, если я в конкретно своем примере вытяну бизнес логику из сущности в application слой - внезапно сущность станет анемичной. А это опять не DDD.
Так изначальное утверждение было - что DDD это вообще не про код, а чисто про проектирование. Я решил перепроверить по книге. Какие примеры там были таки и привел.
Да, там я могу переложить нативный SQL из хранимки в репозиторий и целиком его отправить в БД за один поход через сеть. Но в анемичной модели это как раз позволительно, чего не скажешь о DDD.
И насчет усложнения поддержки - всегда, когда заходит речь об оптимизациях это приводит к снижению простоты читаемости кода.