Блоґ

Home / Думки, нариси, різні випадки

Нескінченний крокувач

Потуга крокувачів

четвер, 9 листопада 2023 р.

iterator

Comments

 
Мовний дослід
Повернення до витоків?

В цьому тексті зроблена спроба якнаймога ширшого використання українських відповідників запозиченим англійським термінам

Перелік відповідників

Коли відбувається розробка якогось великого снутку, так само як і під час будівництва великої будівлі, неминуче виникає необхідність вирішувати якісь додаткові задачі, що не є безпосередньо пов'язані зі снутком — збирання/розбирання будівельного риштування навколо будівлі, прокладування колії для журавця, побудова якихось сховищ для спорудних знадобів чи побутових приміщень для будівельників тощо. Щось подібне до цього трапилося і в одному з моїх останніх снутків, який являв собою досить великий API — якоїсь миті QA-гурт захотів мати можливість випробовувати наш API на досить великих обсягах підроблених даних. Щоб надати таку можливість, нам довелося написати окреме знаряддя для наповнення сховища даних тисячами пробних записів.

Головним клопотом, через який ми вимушені були розробити це знаряддя, була необхідність дотримуватися правильних взаємних зв'язків між різними видами підроблених записів. Наповнити підробленими даними окрему стільницю — то є доволі проста задача, якщо використовувати знаряддя на кшталт Bogus або AutoFixture. Однак для того, щоб зберегти цілісність даних в межах певного ділового терену, відносини підпорядкування в породжених записах, які зберігаються в різних стільницях, мають бути забезпечені правильними визначниками. Додатково QA-гурт висловив бажання мати можливість нарощувального додавання даних, наприклад, коли для наявних батьківсьвих записів з визначниками 1, 2, 3, залежно від пропису сутнього випробовування, в один день потрібно додати залежні записи для батьків 1 і 2, але не 3, а в інший — лише для 3, але не для 1 та 2.

Терен, під який ми розробляли той API, був пов'язаний з обліком земельних ділянок, отже, в ньому були сутності на кшталт ділянок землі, їхніх власників, відповідальних осіб, країн, районів, снутків забудови тих ділянок і різноманітних видів перемовин між всіма залученими в певний снуток учасниками, як і відслідковування стану снутку, який визначався досягнутими угодами та дозволами від власників, діл та розпорядників. Багато низькорівневих сутностей були пов'язані з 3-4 батьківськими сутностями, і цілісність даних мала забезпечуватися для тисяч підроблених записів в різних сполуках щодо того, яка частина з них породжується "на льоту", а яка бралася зі сховища даних з використанням наявних визначників.

Запит міг бути на кшталт такого: "Потрібно зродити 1000 подій перемовин типу 1, 2, 3 для будь-якої відповідальної особи, що належить до снутку 42 та пов'язана з наявними ділянками 50..80. Також необхідно, щоб вони були з країн 10 або 11". Тут ми покладаємося на те, що всі типи подій, снутки, земельні ділянки та країни вже містяться у сховищі даних. Тобто задача полягає в тому, щоби зродити частково підроблені записи перемовин, які міститимуть дійсні визначники для створення правильних зв'язків з наявними даними.

Після деяких початкових роздумів в мене виникла візія про дворівневу будову застосунку породження підроблених даних. Ядром має бути невеликий кістяк, який розбиратиме вхідні умірники та надаватиме нескінченні відмислені добірки правильних визначників верхньому рівню, який споживатиме ті добірки для породження підроблених значень полів для необхідної сутності, не переймаючись тим, звідкіля ті визначники надійшли. Таким чином, із запровадженням подібного розділення відповідальностей інші гуртівники матимуть можливість абиколи створювати нові породжувачі для сутностей, які на цей час ще навіть не існують, не занурюючись в те, яким чином ядро добуває необхідні дані (саме цю частину я розробляв самотужки).

Я міркував так — споживач АПІ ядра породжувача не має клопотатися про здобування добірки, вправляння з жеребкуванням, щоб взяти з неї якийсь визначник, навіть про те, щоби знати кількість складників тієї добірки. Споживач має просто робити виклик на кшталт .GetNextId() на наданій добірці, знаючи, що АПІ поверне складник, який точно буде в заданих межах або в заданому переліку потрібних чисел, і ці визначники дійсно існуватимуть у сховищі даних. Не істотно як багато, 10 чи 10000 складників має бути породжено — споживач просто робитиме виклики .GetNextId() стільки разів, скільки треба, і надані числа будуть випадково розподілені на заданий розкид.


for (var i = 0; i < count; i++)
{
    var projectId    = (await _projectIdProvider   .FromIds()).GetNextId();
    var statusId     = (await _statusIdProvider    .FromIds()).GetNextId();
    var salutationId = (await _salutationIdProvider.FromIds()).GetNextId();
    var titleId      = (await _titleIdProvider     .FromIds()).GetNextId();
    var countryId    = (await _countryIdProvider   .FromIds()).GetNextId();

    // ...........
	
	// Bogus stuff for individual data fields of the generated record
}

Отже, суттю тієї нескінченної відмисленої добірки стала річ, що зветься "крокувач", чи "Enumerator" в мові c#. На задум, чин .MoveNext() своєладного крокувача, що його споживатиме породжувач верхнього рівня, ніколи не досягатиме кінця. Таким чином, неважливо, чи нам потрібно породити тисячу підроблених сутностей, пов'язаних десятьма наявними ключами, чи породити десять підроблених сутностей, пов'язаних ключами з розкиду в тисячу наявних — розробник породжувача має просто написати _provider.FromIds().GetNextId() в колобігу у необхідну кількість кроків.

Чин FromIds() унаочнює початкову добірку визначників залежно від того, чи була первостать сутності зазначена, чи була вона пропущена серед умірників при виклику застосунку.


    public async Task> FromIds() =>
        (_input.ToList() switch
        {
            [] => (await _repository.GetStakeholdersAsync())							// if not specified in params, get all the entity ids from db
                .Data.Value.Select(x => x.StakeholderId).Randomize(),

            [..] ids => (await _repository.GetExistingStakeholderIdsAsync(ids))			// if specified, check provided ids for existance and use them
                .Data.Select(x => x).Randomize()
        });

Дійсний нескінченний крокувач втілено в чині Randomize().


public static class CollectionRandomizer
{
    public static IEnumerator Randomize(this IEnumerable input)
    {
        var random = new Random();
        var list = input.ToList();
        if (!list.Any()) yield break;													// Edge case — empty input collection, generator will fail fast
        while (true) yield return list[random.Next(0, list.Count)];
    }

    public static int GetNextId(this IEnumerator input)
    {
        input.MoveNext();

        return input.Current;
    }

    // When a generator needs to get several ids at once
    public static IEnumerable GetNextIds(this IEnumerator input, int count)
    {
        while (input.MoveNext() && count-- > 0) yield return input.Current;
    }
}

Таким чином і забезпечено нескінченність відмислених добірок визначників.

# Загальновживане слово Український відповідник
1 Абстрактний Відмислений
2 Артефакт Вияв
3 Архітектура Будова
4 Бізнес Діло
5 Будівельні матеріали Спорудні знадоби
6 Генератор Породжувач
7 Діапазон Розкид
8 Домен Терен
9 Елемент Складник
10 Ідентифікатор Визначник
11 Ідея Візія
12 Інструмент Знаряддя
13 Ітератор крокувач
14 Колекція Добірка
15 Конкретний Сутній
16 Менеджер Розпорядник
17 Метод Чин
18 Параметр Умірник
19 Підйомний кран Журавець
20 Проблема Клопіт
21 Проєкт Снуток
22 Сценарій Пропис
23 Таблиця Стільниця
24 Тип Первостать
25 Цикл Колобіг
26 Член команди Гуртівник

Джерело мовних гадок — Словотвір

© theyur.dev. All Rights Reserved. Designed by HTML Codex