Обновить
51
0.6

Architect | Lead | Senior Developer

Отправить сообщение

Хмм, у второго упомянутого чувака в бложике есть ссылка на его книгу «почему все плохо в Ит» https://github.com/sgoedecke/gatsby-blog/blob/master/content/book/book.pdf

https://vaz-rabota.ru

Водитель погрузчика
55 887 — 75 732 руб.

Инженер-конструктор
38 100 — 59 700 руб.


Инженер-программист
38 100 — 59 700 руб.

Нижняя планка водителя погрузчика на уровне верхней планки инженеров.

И это 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)

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);
}

Слой INFRASTRUCTURE (InventoryLevelRepository)

public Task<int> AllocateAsync(string idempotencyKey,
    string? reason, string itemsJson,
    CancellationToken cancellationToken)
{
    return _dbContext.Database.ExecuteSqlRawAsync(@"
        CALL AllocateInventoryLevels(
            {0}, -- pIdempotencyKey
            {3}, -- pReason
            {4}  -- pItems (JSON)
        );",
        [
            idempotencyKey,
            reason ?? (object)DBNull.Value,
            itemsJson
        ],
        cancellationToken);
}

А ну и собственно я не могу разместить нативный SQL в application слое. Это специфика хранилища, а абстракция над хранилищем - это репозиторий.

У меня в голове отложилось, что логика сущности должна быть внутри сущности, а application слой - это когда нам надо координировать работу двух сущностей, ну например

var бабло = счет1.Списать();
счет2.Пополнить(бабло);

Возможно я прав или не совсем прав.

А когда речь идет про одну сущность, все должно быть внутри нее и application слой получается тонким. Собственно у меня так и получилось. Точнее один агрегат и две сущности в нем - InventoryLevel и InventoryOperation (отражает историю списания или пополнения). У InventoryLevel есть метод Reserve, который делает все что нужно.

В смысле это "все что нужно" делается в памяти сервера. А потом, когда выходит из application слоя - оно же там обернуто в unit of work и транзакцию - вот там все и сохранятся в БД.

В противном случае, если я в конкретно своем примере вытяну бизнес логику из сущности в application слой - внезапно сущность станет анемичной. А это опять не DDD.

Так изначальное утверждение было - что DDD это вообще не про код, а чисто про проектирование. Я решил перепроверить по книге. Какие примеры там были таки и привел.

Да, там я могу переложить нативный SQL из хранимки в репозиторий и целиком его отправить в БД за один поход через сеть. Но в анемичной модели это как раз позволительно, чего не скажешь о DDD.

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

1
23 ...

Информация

В рейтинге
2 114-й
Откуда
Россия
Зарегистрирован
Активность

Специализация

Backend Developer, Software Architect
Senior
C#
.NET Core
SQL