Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Как Oracle Problem, граничные значения, закрытые экосистемы, MQM и сама цель тестов отличают задачу тестирования конвейеров данных от тестирования традиционного программного обеспечения.
Программное обеспечение просто перемещает данные внутри компьютеров. Конвейеры данных также просто перемещают данные внутри компьютеров. Итак, насколько тестирование конвейеров данных может отличаться от тестирования любой другой формы программного обеспечения? Разве все практики, подходы и накопленный опыт, полученные при тестировании традиционного программного обеспечения, не должны применяться и к конвейерам данных?
К сожалению, всё сложнее. Да, тестирование конвейеров данных и тестирование традиционного программного обеспечения частично пересекаются. Однако существуют уникальные характеристики и особенности разработки конвейеров, которые создают особые сложности при тестировании, которых опытный инженер по качеству может не знать. Игнорирование этих особенностей и подход к конвейерам данных так, как будто они ничем не отличаются от любого другого типа программного обеспечения, приведет к разочаровывающим результатам. В этой статье я рассмотрю несколько наиболее интересных проблем и предложу альтернативные подходы, подходящие для конвейеров данных.
Хотя эта статья будет посвящена этим различиям, она не будет исчерпывающим руководством по тестированию конвейеров данных. Тестирование конвейеров данных — это широкая тема, которая не может быть полностью раскрыта в одном посте. Однако понимание этих проблем будет полезно всем, кто работает с конвейерами данных.
Во-первых, немного контекста конвейеров данных: я использую этот термин в широком смысле для описания широкого спектра систем, включая процессы ETL и ELT, а также все типы архитектур Data Lake, Data Mart и хранилищ данных. Неважно, обрабатываются ли данные батчами, микро-батчами или потоком — все здесь по-прежнему применимо. Эти приложения часто преобразуют данные во время обработки, но не всегда. Конвейеры данных обычно работают с большими объемами данных, но не все должно быть Big Data, поскольку даже небольшие конвейеры могут страдать от проблем, которые мы подсветим ниже.
Если то, что я описал выше, кажется правильным, то это потому, что так оно и есть. Применение одного термина, такого как конвейер данных, ко всем этим приложениям неизбежно упрощает их многообразие. Однако я считаю, что перечисленные ниже проблемы являются общим, даже если их конкретное проявление уникально для конкретной архитектуры или компании.
Data Quality “Tests”
Давайте начнем с разговора о тестах и о том, как даже этот простой термин может сбивать с толку в контексте конвейера данных. Вот гипотетическая ситуация:
Вы присоединяетесь к команде, расширяющей существующий конвейер данных. Эта команда, как и многие команды разработчиков конвейеров данных, традиционно не использовала инженера по качеству, поэтому они не совсем уверены, что вам следует делать. Вы спрашиваете о написанных ими автоматических тестах, и, к вашему облегчению, они говорят, что их у них много. Отлично!
Они показывают вам некоторые тесты, написанные в PyTest, которые обеспечивают соответствие данных определенным правилам. Например, есть проверки на null, некоторые проверки целостности и некоторые другие проверки «количеств и сумм», как они это называют. Однако вы не уверены, как именно используются эти тесты. Это юнит тесты или что-то другое?!
Вы спрашиваете, когда выполняются эти тесты. «О, они работают вместе с конвейером», — говорят они. Что ж, отлично, здесь есть автоматизированные конвейеры CI/CD. Вы спрашиваете об их запусках, но получаете… пустые взгляды.
— «Тесты, которые выполняются в конвейере, выполняются ли они при мерже в мастер или после развертывания в тестовой среде, что-то в этом роде?»
Еще более растерянный вид.
Это подводит нас к первому большому различию между тестированием конвейера данных и тестированием стандартных приложений: конвейеры данных часто имеют «тесты», встроенные в сам конвейер данных, которые выполняются по мере обработки данных для обеспечения качества данных. Эти проверки являются частью функциональности конвейера. Обычно они определяются data stewards или data инженерами и обеспечивают выявление неверных данных, а затем их блокировку, очистку, исправление или логирование во время работы конвейера. Эти проверки необходимы, поскольку данные, поступающие в конвейеры данных, часто поступают из ненадежных систем и имеют низкое качество. Эти тесты не те, о которых мы обычно думаем, когда используем этот термин в контексте традиционного программного обеспечения, и термин «тест» часто вызывает путаницу.
Ближайшей аналогией этого в традиционном программном обеспечении является проверка ввода, которая происходит в отношении входящих сообщений в общедоступном API. Если я создаю службу REST, которая принимает POST запрос от внешних потребителей, мне нужно проверить содержимое этого запроса перед его обработкой. Если запрос недействителен, система должна ответить HTTP 400 (неверный запрос) или сообщением об ошибке на уровне приложения. Эту проверку входящих данных можно рассматривать как runtime тест — часть системы, которая выполняется каждый раз при получении POST запроса для проверки (или «теста») правильности ввода. Однако мы не будем рассматривать этот входной тест на валидацию как тест в том смысле, в каком этот термин используют QA инженеры.
Подобно службе REST, конвейеры данных получают данные из внешних, ненадежных источников. Они должны проверять данные и реагировать соответствующим образом при обнаружении неверных данных. Эта проверка типа часто называется «тестированием» для обеспечения «качества данных», которое выполняется в «конвейере» (конвейере данных!), но, как и REST, она не выполняет ту же функцию, что и функциональный тест. Проблемы с качеством данных настолько распространены в конвейерах данных, что термин «тест» обычно подразумевает валидацию во время выполнения, а не тот тип тестирования или автоматизации, с которыми мы знакомы.
Часто помогает визуализировать конвейеры данных как два ортогональных пути. Горизонтальный путь (синие стрелки) — это поток данных через конвейер данных. Вертикальный путь (оранжевый) — это исполнение кода и логики в средах конвейера CI/CD по мере разработки нового кода или функций. Данные проходят горизонтально через каждую из этих сред, а код или другие изменения конвейера проходят вертикально между средами. Тесты качества данных, также известные как runtime тесты, выполняются в горизонтальном потоке для валидации качества данных, а проверка преобразования или другие обычные тесты выполняются в вертикальном потоке для проверки кода и логики перед переходом в следующую среду.
Путаница между проверками качества данных во время выполнения и проверками качества кода усугубляется тем фактом, что два типа тестов могут быть написаны в одной и той же среде, и один тест может выявить как проблему качества данных, так и проблему логики, в зависимости от того, как он используется. Кроме того, тесты качества данных во время выполнения сами по себе являются функциональностью, поэтому их следует проверять с помощью логических тестов.
Необходимость как обширных проверок качества данных во время выполнения, так и стандартных тестов проверки кода, а также дублирование терминов, используемых для каждого из них, является источником путаницы при тестировании конвейеров данных. Зрелые команды разработчиков конвейеров данных используют как автоматические проверки качества данных, так и автоматические логические тесты, гарантируя, что только качественный код попадет в прод, а данные имеют максимально возможное качество.
Ключевой вывод: четко определите, что тестируют ваши тесты, и убедитесь, что вы достаточно хорошо тестируете как качество данных, так и логику. Найдите и используйте точные термины для каждого случая, который имеет значение для вашей команды.
GUI Tools и Walled Gardens
Корпоративное программное обеспечение бывает разных видов. С одной стороны, у нас есть современные архитектуры, построенные на открытых инструментах, платформах и языках. С другой стороны, у нас есть все формы устаревших и проприетарных систем. Проприетарное не обязательно означает устаревшее (например, SAP, Salesforce и т. д.), но все же усложняет современные методы автоматизации тестирования и непрерывного развертывания. Эти системы часто обеспечивают функции управления instance, настройки, развертывания и тестирования из “walled gardens”, что требует использования их инструментов и процессов. Хотите новой instance? Заплатите еще 50 тысяч долларов в месяц за экземпляр и разверните его с помощью этого проприетарного инструмента с графическим интерфейсом! А если вы хотите настроить ephemeral environments, развернутые с помощью существующих конвейеров GitHub Actions или Jenkins, это может стать проблемой.
Конвейеры данных страдают от закрытых экосистем и сфокусированности на управлении через GUI. Инструменты ETL часто ориентированы на разработчиков баз данных — людей, хорошо разбирающихся в SQL и данных, но не в разработке приложений. Попросить этих людей писать на Python, C# или подобном языке было бы проблематично, поэтому поставщики инструментов создали мощные графические интерфейсы с drag-and-drop, чтобы избавить разработчиков SQL от написания кода. Эти инструменты отлично подходят для написания преобразований данных, но их невероятно сложно интегрировать во внешние современные конвейеры разработки. Создание конвейеров с полностью настраиваемыми автоматическими quality gates между средами часто невозможно.
Например, допустим, у меня есть конвейер данных с преобразованиями, реализованными в Informatica. Informatica предоставляет инструмент с графическим интерфейсом для реализации преобразований, так что именно здесь работают разработчики. Конвейер данных становится все более сложным, одновременно работает больше разработчиков, поэтому я хочу настроить модель на основе feature branch, которая позволит разработчикам разрабатывать и тестировать в изолированных средах перед объединением с мастером. Слияние должно автоматически развертываться в общей тестовом окружении запускать дополнительные тесты более высокого уровня. Если какие-либо тесты не пройдены, сообщение об ошибке в сборке должно быть отправлено по соответствующим каналам.
Это было бы легко настроить DevOps-у и QA инженеру, если бы мы создавали что-то вроде веб-приложения на React и разворачивали его на AWS. К сожалению, нет собственного способа «ветвления» разработки внутри instance Informatica. Все разработчики, работающие в одном instance, технически используют одну и ту же учетную запись и могут наступать друг другу на пятки. Очень сложно реплицировать экземпляры так же, как реплицировать среды AWS, чтобы получить ту же функциональность, что и наше гипотетическое приложение, развернутое на AWS.
Из-за преобладания проприетарных закрытых экосистем и инструментов разработки, ориентированных на графический интерфейс, часто бывает сложно или невозможно реализовать подходы разработки и автоматизации тестирования, которые мы используем в традиционной разработке приложений.
Ключевой вывод: поймите ограничения ваших инструментов. Если ваша организация переходит от устаревшей разработки ETL к современной обработке данных, используйте инструменты, ориентированные на код (например, dbt), а не инструменты с графическим интерфейсом, независимо от того, насколько хорошо он выглядит.
Аспекты качества
Конвейеры данных — это… данные. Данные извлекаются из разных исходных систем, данные преобразуются и обрабатываются, а также сохраняются, экспортируются или иным образом «выводятся» туда, где они будут применены. «Качество» данных измеряет, насколько эти данные пригодны для предполагаемого применения. Есть много критериев, согласно которым данные могут быть некачественными, и это не так часто встречается в обычном программном обеспечении.
Многие дата-инженеры пытались определить «параметры качества данных», которые вы можете найти с помощью быстрого поиска в Google. Однако нет универсального списка. Дело в том, что данные в конвейере данных не просто верны или неверны, а скорее имеют более высокое или более низкое качество, а низкокачественные данные могут быть низкокачественными по целому ряду причин. Часто данные низкого качества на первый взгляд неотличимы от данных высокого качества.
Вот список, который я использую. Опять же, то, как именно вы перечисляете и определяете эти критерии, сильно зависит от ваших личных предпочтений.
Полнота(Completeness): когда целые записи в наборе данных или значения в записи, которые должны присутствовать, отсутствуют (например, пустые столбцы в строке БД).
Уникальность(Uniqueness): когда данные дублируются. Дублирующиеся или избыточные данные распространены в конвейерах, которые извлекаются из различных вышестоящих источников, и дедупликация часто является важным компонентом обработки конвейера данных.
Валидность(Validity): чтобы данные были достоверными, они должны быть представлены в формате, который соответствует области значений. Например, в атрибуте даты, который предполагает формат ММ-ДД-ГГ, любая дата в формате ГГГГ-ММ-ДД будет недействительной, даже если дата действительно точна.
Непротиворечивость(Consistency): когда данные, которые, как ожидается, будут эквивалентны, не эквивалентны. Например, в записи о клиенте из биллинга указано, что адрес Боба — 123 Main St, а в записи учетной записи CMS указано, что это 489 James St.
Ссылочная целостность(Referential Integrity): Когда данные ссылаются на другие данные через внешние ключи или другие менее явные отношения, но эти данные отсутствуют. Это связано с концепцией управления мастер-данными (MDM).
Точность(Accuracy): значения данных, которые неверны. Возможно, они были получены из неправильного источника, повреждены или просто неправильно введены в исходную систему.
Соответствие(Compliance): данные могут соответствовать всем вышеперечисленным критериям, но не соответствовать требованиям. Кажется, это не так важно? А что если у вас есть номер кредитной карты в виде открытого текста(необфусцирован), который проходит через ваш конвейер данных, записывается в файлы журналов и т. д. Здорово, да?
Своевременность(Timeliness): когда проблемы с доступностью или задержкой не позволяют использовать данные по назначению. В зависимости от варианта использования ожидаемая своевременность может варьироваться от нескольких минут до бесконечности.
Проблемы с данными в указанных выше критериях могут быть вызваны как проблемами входящих данных, так и логическими ошибками в самом конвейере. Тесты, которые проверяют данные по этим критериям, могут выполняться как часть горизонтального конвейера, или как часть вертикальных проверок, или и того, и другого. Независимо от причины, мы должны обеспечить максимальное качество данных, предоставляемых нашим пользователям, по всем параметрам качества.
Ключевой вывод: продумайте все способы обеспечения качества ваших данных и разработайте способы проверки этого качества.
Oracle Problem
(нет, не компания)
Каждый инженер по качеству знаком с Oracle Problem, даже если не знает ее под таким названием. Вы выполняете проверку и получаете какой-то результат, это ваш «фактический» результат. Что вы ожидали получить? В некоторых случаях на это легко ответить, либо получив доступ к данным, либо руководствуясь здравым смыслом. Вы ожидали получить ответ HTTP 200 (ОК). Вы ожидали, что не получите страницу с ошибкой. Вы ожидали, что ваша корзина будет опустошена, и будет отправлено электронное письмо с подтверждением заказа в соответствии с критериями приемки. Однако во многих случаях определение «ожидаемого» результата может быть проблемой — это проблема Oracle. Вы входите в тестовую среду AcmeTravel.com. Вы ищете рейс из Сиэтла в Нью-Йорк и получаете 302 результата. Вы должны были получить 302 результата? Это были именно те 302 результата, которые вы должны были получить? Без полного доступа к базовым источникам данных или полного контроля над точками интеграции этой поисковой системы ответить на этот вопрос, вероятно, невозможно. Опять же, это проблема Oracle: каждый тест представляет собой сравнение двух результатов, ожидаемого и фактического, и определение ожидаемого результата часто является проблемой.
Конвейеры данных - это сложный кейс этой проблемы. Конвейер данных извлекает данные из многих исходных систем. Он объединяет эти данные, преобразует их, очищает, а затем сохраняет в некотором обработанном состоянии для использования нижестоящими системами, аналитическими платформами или data scientists. Эти конвейеры часто обрабатывают данные из сотен или даже тысяч источников. Если вы запустите свой конвейер, получите несколько миллионов новых строк, как вы узнаете, что всё прошло успешно? Сколько строк вы должны были получить? Верно ли каждое значение в каждом столбце каждой строки? Это хуже, чем описанная выше проблема с поиском рейса!
Если вы не знакомы с конвейерами данных, вы, вероятно, предложите имитировать исходящие источники данных. Имея полный контроль над источниками данных, вы точно знаете, какие данные попадают в конвейер, поэтому вы должны точно будете знать исходящие данные. Чем это отличается от традиционного тестирования программного обеспечения?
Иногда это можно осуществить, но специфика конвейеров данных может сделать это сложным или даже невозможным. Часто исходные данные состоят из неструктурированных данных (сообщения в блогах, отчеты клиентов, файлы журналов и т. д.), а не строк в реляционной базе данных, и часто сложно получить репрезентативные фиктивные данные из неструктурированных данных. Даже если все исходные данные представляют собой красиво структурированные таблицы базы данных, эти таблицы часто исчисляются тысячами и имеют сложные зависимости между ними. Попытка настроить даже один согласованный набор тестовых данных может занять невероятно много времени. Еще одна проблема: эти исходные данные часто весьма разнообразны (третья «V» больших данных), так что вы не можете заранее предсказать все перестановки, которые вы должны учитывать в своих тестовых данных. Стратегия всё “замокать”, столь полезная при тестировании обычных программ, часто оказывается бессильной в конвейерах данных.
Хотя mock-и не всегда является решением, проблема Oracle не является непреодолимой. В зависимости от архитектуры конвейера и применения данных существуют решения, которые могут помочь. Например, сравнение «до и после», эвристическая проверка, репликация набора “продовых” данных, анализ трендов и профилирование и т. д. Что применимо к вашей задаче тестирования (как валидация качества данных, так и тестирование логики) будет зависеть от конкретных характеристик конвейера.
Ключевой вывод: заранее подумайте о том, как вы получите ожидаемые результаты тестов — как о качестве данных, так и о логике обработки — поскольку это может стать вашей самой большой проблемой. Для проверки качества данных используйте Data Stewards или других экспертов по обработке данных для разработки статистических методов выявления проблем с данными.
"Достаточно хорошие" данные
Мы привыкли к высоким стандартам качества при производстве традиционного программного обеспечения. Дефект, обнаруженный в проде, считается очень плохим показателем и может привести к изменению процесса, пересмотру архитектуры или переоценке приоритетов тестирования и инвестиций в автоматизацию.
Во многих приложениях конвейеров данных предполагается, что данные несовершенны, даже в проде. Источники данных настолько неструктурированы, изменчивы и беспорядочны, что невозможно добиться «полностью очищенных» данных. Кроме того, пользователи могут даже не нуждаться в полностью чистых данных, поэтому любые ресурсы, вложенные в их достижение, будут потрачены впустую.
Например, может случиться так, что ваш конвейер данных преобразует неструктурированные данные отзывов клиентов из нескольких систем. Аналитики ищут информацию о том, какие клиенты больше всего выиграют от проактивных обращений в службу поддержки (eww). Из миллионов клиентов аналитики просто создают общий список. И если клиент окажется немного выше или ниже в списке, чем должен быть, потому что часть данных была некорректной, это не окажет существенного влияния на бизнес.
Этот подход «достаточно хорош для этой цели» может раздражать опытного QA инженера, но это то, что необходимо понять, чтобы успешным в тестировании конвейеров данных.
Ключевой вывод: Знайте свои ожидания в отношении качества данных и соответствующим образом инвестируйте в обеспечение качества.
Data Stewards и другие роли
Вы, вероятно, понимаете роли и обязанности людей вокруг вас в традиционных проектах программного обеспечения. В мире конвейеров данных существует совершенно новый набор ролей, и некоторые из этих ролей могут даже иметь термин «качество» в своем названии. И это может сбивать с толку, поэтому важно знать, кто эти новые роли и как они влияют на качество.
Типичным примером этого является Data Stewards или Data Quality Stewards. Этот человек не обязательно входит в состав команды конвейера, но играет решающую роль в обеспечении качества данных. Data Stewards играют важную роль в определении того, кому данные принадлежат, как они передаются и используются.
Все компании разные, поэтому я не могу перечислить все роли и то, как вы должны с ними взаимодействовать. Тем не менее, вы должны знать, что как инженер по качеству (как и в обычной разработке приложений) ваша роль предполагает тесное сотрудничество, и вам нужно будет взаимодействовать с большим количеством других людей, чтобы быть эффективным. В проектах конвейера данных появятся новые роли и новые должности, с которыми вы не были знакомы.
Ключевой вывод: узнайте, как эти новые для вас роли в компании связаны с качеством и постарайтесь установить с ними хорошие отношения.
Вывод
Это было введение в некоторые уникальные проблемы тестирования конвейеров данных. Оно не является исчерпывающим, и многие интересные проблемы были опущены просто для того, чтобы эта статья была удобочитаемой. Однако конвейер данных — это программное обеспечение, и, несмотря на новые термины, понятия и инструменты, любой инженер может успешно перейти на работу с ними. Помня об указанных выше рисках, вы упростите себе работу, применяя качественные инженерные знания в области конвейеров данных.