Инженер и данные
721 subscribers
39 photos
30 links
Канал про инженерный подход к работе с данными


Автор: Андрей Демидов - lead data engineer.
Связаться: @andrewdemidovv
Download Telegram
Json внутри sql базы данных

Json классный и очень удобный формат для передачи данных и, в ряде случаев, для хранения тоже, например, для хранения логов или событий. 👌

Но что насчет json колонок?

Я считаю json колонкам не место в DWH или, тем более, в мастер данных. Они дают обманчивую простоту хранения данных, а по факту туда закидывают все, что не удалось понять и внести в правильное место в модели. ☹️

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

Так что если поймали себя на мысли создать json колонку, подумайте ещё немного о том, что это за данные и как они должны быть встроены в модель. ☝️
👍15🔥3💯2
Извлечение внешних данных vs подготовка данных как продукта

📝 В обоих случаях есть некий пайплайн, который берет данные где-то и складывает куда-то. Но разница существенная. К техническому решению применяются требования. Инженерные требования. О них вам не скажет заказчик. Вот парочка случаев с разными требованиями к пайплайну.

✳️Данные как продукт. Наш продукт. Тут требований много. Мы отвечаем за качество и должны его гарантировать. Здесь писал про консистентность, согласованность и целостность. А в этом посте больше остановлюсь на втором случае.

✳️Данные из внешних источников.
Нужно гарантировать, что все данные будут получены и сохранены как есть. Ничего не потеряется, ничего не изменится. Эти данные как правило уже после трансформируются и превращаются в наш продукт.

Ключевая разница в разном уровне гарантии. ☝️

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

Как это влияет на технические решения на практике.
🔸При трансфере внешних данных нет трансформаций! EL, если хотите, - extract and load. Как только вы вклинились с какой-то своей логикой посередине уже гораздо сложнее гарантиговать консистентность.
🔸Для внешних данных минимальны проверки при записи. Даже тип данных лучше не проверять. Если отправили текст вместо числа, так и запишем - значит так надо. 🤷‍♂
🔸Это не наш продукт и эти данные мы не публикуем! Это как бы сырье, которое мы применим или нет, чтобы создать наш продукт, за который уже будем отвечать и гарантировать качество.

🔍Если хотите порассуждать чуть глубже, то как и всегда есть одно но. Говоря красивыми словами, эти внешние данные просто существуют в другом контексте. Из этого следует, что внешними данными могут быть и данные другого департамента вашей компании, который работает в своём контексте. Данные его соответствуют некой модели того контекста. Это значит что они могут быть опубликаваны нами для анализа, но только в рамках нужного контекста и тот кто будет на них смотреть тоже должен быть внутри контекста. Простыми словами он должен знать что за сущности, свойства и записи тут есть, почему они такие и какие тут могут быть допущения. Используя эти данные аналитик принимает на себя риски связанные с некорректной интерпретацией контекста.

©️Все это можно свести к одному лаконичному правилу.
Собирая внешние данные нужно гарантировать только консистентность - записали ровно так как взяли и если что-то записали, то там где взяли равно так и было.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7👏5👍3
Clean code приёмы. Работа с датами в оркестраторе

Продолжаем работать над чистотой кода и чистотой архитектуры

📝 Трансфер данных почти всегда связан с датами или, лучше сказать, с диапазонами времени. Сегодня поговорим о работе с датами вообще.

Я всегда повторяю и здесь тоже писал, что все участники должны выполнять свою задачу и не брать слишком много ответственности. Оркестратор дергает сервисы в определенной последовательности, передавая контекст. А сервисы просто делают свою работу. Все участники знают свою роль и независимы. 👌
Вернемся к работе с диапазонами времени. Знать рассматриваемый в данный момент диапазон времени - работа оркестратора. Это часть контекста. Сервисы/операторы в свою очередь должны уметь работать с любыми запросами оркестратора - сказано вернуть данные за месяц? Вернул. За полчаса? Вернул. Они исполнители, не задающие вопросов.

Работа с датами в airflow
Очень часто работа с датами в airflow ограничивается использованием диапазона в один день с использованием переменной ds из контекста. Примерно вот так в sql
where date_column = '{{ ds }}'


Загнать себя и архитектуру в такие узкие рамки - неиначе как наступить самому себе на горло.
😭

Airflow в контексте имеет много чего интересного и в том числе разнообразные таймштампы. (Вот тут документация. Они назвали это template variables, но это не только для рендеринга темплейтов это в целом переменные контекста и им следовало назвать их context variables.)

Итак в контексте всегда есть два замечательных таймштампа: data_interval_start и data_interval_end. Это собственно начало и окончание временного интервала, определяемого заданным расписанием. Например для одного дня там будет 2025-02-09 00:00:00 и 2025-02-10 00:00:00, задав в schedule три месяца получите 2024-12-09 и 2025-02-09. Да хоть 25 минут и тогда кроме даты будет 03:10:00 и 03:35:00. Я думаю вы поняли. Смысл в том, что задать в schedule можно любое расписание и получить таймштампы в контекст. Более того это ещё и готовые объекты datetime! 🤤.

Вот так дышать гораздо легче и свободнее.👍 А теперь следите за руками. 👇
Оркестратор берет любой schedule и пробрасывает везде в виде контекста диапазоны.©️ Все сервисы написаны так, чтобы они принимали любой диапазон и делали свою работу. ©️Получаем независимый от диапазона времени пайплайн! Вся логика, вся последовательность операций, вся обработка одинакова и написана один раз.©️ Хочу запускаю каждые 8 часов, хочу каждые 2 часа, хочу каждые 3 дня. Хочу забэкфилить последние полгода одним раном? Пожалуйста! Только задай расписание. Хочу близко к реалтайм - ставлю минуты и тд. 🙌

Тут же добавляется ещё одна очень интересная возможность - динамически генерировать несколько идентичных дагов с разным расписанием. Звучит сложно, но по факту постой цикл for.😎 Это например можно использовать для дополнительных запусков пайплайна с чуть более редким расписанием чем основное, на случай чего-то непредвиденного в основных запусках. У нас примерно так и есть. Почти на каждый пайплайн есть два-три дага с расписанием: 2 часа, день, месяц. Ну и конечно бэкфил можно запускать хоть помесячно хоть поквартально.

📎 В этом посте уже не осталось места для примеров с кодом, так что покажу в одном из следующих постов, в котором покажу работу в коде с контекстом вообще и в том числе с датами. 👀

©️В качестве краткого резюме. Диапазон дат - детали. Логика пайплайна не должна меняться в зависимости от диапазона дат. Оркестратор дергает участников передавая даты, а сервис/оператор должен уметь работать с любыми датами.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11👍2
Бизнесу пофиг

Когда я говорю Бизнес, я имею ввиду людей которые принимают решения, стейкхолдеров, топ менеджмент.

Бизнесу все равно какой архитектурный паттерн вы там применили, чтобы организовать данные, какие потоки настроили, какие инструменты применили и тд. Без разницы ему data vault у вас, Inmon или Kimbell. Пофиг data lake, lakehouse или warehouse.🙄

Бизнес интересуют ответы на вопросы
Им интересно:
1️⃣ Можно ответить на вопрос? Да или нет.
2️⃣ Как быстро можно ответить на вопрос? В любой момент/ через часы/ через дни.
3️⃣ Будет ли уведомление, если что-то идёт не так? (Бизнес алерты. Не путать с техническими)
4️⃣ Сколько стоят ответы на вопросы? (Стоимость инструментов, трудозатраты аналитиков и инженеров)

При этом по умолчанию подразумевается, что ответить можно на любой вопрос и что данные точные (хотя иногда надо это прояснять - писал тут)

©️Избавьте бизнес от любых технических подробностей и он вас полюбит.❤️
Да, от любых. Да, даже если они хотят залезть в технические детали, аккуратно выводите их на уровень бизнеса.
Please open Telegram to view this post
VIEW IN TELEGRAM
💯7🔥6🤔2
Приоритеты не нужны! Часть 1.

Дисклеймер: Это пост — рассуждение. Здесь будет просто поток мыслей без конкретных пошаговых инструкций. Я не знаю, насколько это вам интересно, но решил попробовать.

Мне пришла странная мысль, и чем больше я о ней думаю, тем больше она мне нравится.

Мы часто говорим о приоритетах на митах. Особенно когда ресурсов мало. Мы даже собирали заказчиков вместе, чтобы они договорились о приоритетах. Батл: чья задача важнее. И в итоге мы откладывали все в сторону, чтобы сделать "важное". А то, что "неважно", откладывадось на неопределённый срок. В течение нескольких месяцев, будучи лидом, я был убеждён, что так и надо, меня так научили. Когда ко мне кто-то приходил из бизнеса, я говорил: ничего не знаю, в приоритете другое, а приоритеты ставит бизнес, то есть вы сами. Но если подумать, это супер странно. Я всегда рассматриваю работу нашей команды как сервис для бизнеса, а значит все проблемы бизнеса важны, все клиенты важны. Вот и пришла мне мысль, о которой я хочу порассуждать в этом посте.

❗️Приоритеты не нужны! Нужно выполнять ВСЕ задачи, которые прилетают команде. В разумные сроки.

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

❓Но тут возникает резонный вопрос: что такое разумные сроки? И тут, кажется, в двух словах не опишешь, но интуитивно мы это всегда как-то понимаем.
▫️Например, есть задача, которая точно терпит и может быть отложена на месяц, но занимает пять минут, и вы решаете сделать это сразу.
▫️Или бывает проблема, решение которой даст больший эффект, чем другая, но заказчик первой готов ждать дольше, чем нужно времени для решения. Тогда вы сначала берете другую задачу — с меньшим эффектом, но с большей вовлечённостью заказчика (это может быть большее давление или, наоборот, просто хорошие личные отношения. Глупо игнорировать тот факт, что мы в конце концов работаем с людьми.)
▫️Или еще бывают инфраструктурные задачи, у которых нет заказчика, но они важны с инженерной точки зрения, а точнее с точки зрения улучшения качества услуг в будущем (быстро, качественно, недорого). Сюда же я бы отнес и обучение и обмен опытом.
▫️Ну и конечно куда же без хотфиксов: пожары нужно тушить здесь и сейчас.

✔️ Выходит, что разумный срок — это некое сочетание требуемых трудозатрат, степени влияния проблемы и вовлеченности заказчика.

Смотри следующий пост ⬇️
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4👍2
Приоритеты не нужны! Часть 2.

Продолжение предыдущего поста

❓Следующий резонный вопрос: что делать прямо сейчас, если у команды/ у меня сразу несколько задач?

Получается нужно попилить доступные ресурсы (время команды, ваше время) на задачи так, чтобы все задачи были выполнены в разумный срок. Возникает необходимость распределения ресурсов. И часто как раз для этого используют приоритеты, типа у этой задачи приоритет выше только её и делаем. Но тут мы говорим о том, что для нас все клиенты важны и все задачи должны быть выполнены, поэтому не подходит.
В идеале для каждой задачи определить разумный срок и необходимые трудозатраты и выделять время пропорционально: час в день, половину вторника или четверг и среду на одно, а понедельник, вторник, пятница на другое. Важно остановиться где-то посередине между двумя крайностями:
❌ много задач решаются параллельно, то есть буквально одновременно, на одном мониторе у вас одна, а на втором другая, пару строк там пару тут - нет фокуса и слишком частое переключение - будут ошибки и усталость.
❌ проблемы решаются от начала до конца последовательно - тут как раз все проблемы, описанные выше: пока делаешь одну важную, другая ждет, потом появляется ещё одна более важная и та другая ждет бесконечно. И ещё в таком подходе большой риск связанный с ошибкой в оценке сроков или в оценке влияния проблемы: решение "важной" проблемы затянулась по какой-то причине, а другая так и не была начата. Или со временем бизнес решил, что та другая все таки важнее, а вы три недели занимались первой.
✔️Баланс между этими крайностями - ключ к высокоэффективной и гибкой системе доставки результата клиентам. Особенно если удастся разбить большую проблему на мелкие части и выдавать их по мере выполнения.

©️Итак, берём все задачи, примерно оцениваем/спрашиваем степень влияния, прикидываем трудозатраты и делаем всё сразу, выделяя какое-то время каждой. На ходу балансируем время в зависимости от того, как пошло дело, и от того, насколько вовлечён (пушит) заказчик и от других вводных, которые появляются в процессе.
Ещё выходит, что когда речь идёт о команде, особенно о большой, может оказаться так, что каждому члену выделена только одна задача, тогда вся эта история с балансировкой полностью ложится на лида.

🔍 выглядит так, что нужно расписание, а не приоритезация. Или я бы даже сказал оркестрация 😀

❗️Приоритеты не нужны! После этих рассуждений я собираюсь исключить из диалогов с бизнесом и командой слово "приоритет". Мы оказываем услуги, поэтому все запросы важны☝️

Бонус, для тех кому интересна тема + косвенное подтверждение состоятельности рассуждений. Инжиниринг он везде инжиниринг. Многие принципы и лучшие практики наследуются из разных областей, и бережливое производство Toyota — пожалуй, один из самых известных подходов, который вышел далеко за рамки применения только на сборочных линиях.
Рассуждения в этом посте хорошо укладываются в применение метода "хейдзунка" бережливого производства Тойота. Это метод выравнивания потока, чтобы заказчики получали разные изделия равномерно небольшими партиями (в идеале единицами), вместо того, чтобы ждать, пока крупнопартийное производство дойдёт до изготовления нужного изделия - очень похоже на проблему с приоритетами. А проблема быстрой переналадки очень похожа на проблему фокуса на задаче. Тот кто умеет быстро переключаться, более гибок и способен построить более равномерный поток.


Я не знаю насколько такой формат кому-либо интересен, поэтому ставьте ❤️, если было интересно и вы задумались вместе со мной.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤11👍7
Clean code в Airflow. Контекст

Продолжаем делать код в Airflow красивее и чище 😉

Работа с контекстом - ещё один очень простой способ снизить зависимость логики от оркестрации и на шаг приблизиться к Clean code.

Airflow создаёт контекст при каждом запуске дага. Этот контекст содержит ряд аргументов, которые могут передаваться оператору. Это по сути key-value пары или в случае python - dict. Оператор может использовать их для рендеринга темплейтов или в качестве аргументов функций. Вот как раз про передачу контекста как аргументов в функции я и хочу написать в этом посте.

📝 Если в двух словах — передавай контекст, принимай аргументы☝️. Код становится более читаемым и главное чистым, когда вместо kwargs принимаются конкретные аргументы.

Вот пример при работе с датами (пост про даты) и не только.

from airflow import DAG
from airflow.operators.python import PythonOperator
from datetime import datetime


def extract_data(
data_interval_start: datetime, # забираем из контекста только то, что нужно
data_interval_end: datetime, # типизация поможет IDE найти проблемы в коде
project: str = None, # опциональный параметр
**kwargs # поможет игнорировать лишние аргументы из контекста
# особенно полезно, если функция используется в нескольких дагах
)-> list[dict]:
data = []
return data


with DAG(
dag_id='example_use_context_dag',
start_date=datetime(2025, 1, 1),
schedule_interval=None,
catchup=False,
) as dag:

task_extract_data = PythonOperator(
task_id='extract_data',
python_callable=extract_data, # контекст передается всегда, то есть никакие действия не нужны
)

task_extract_data2 = PythonOperator(
task_id='extract_data2',
python_callable=extract_data,
op_kwargs={
'project': 'the_best_of_the_best', # можно добавить любые аргументы
},
)


Как видите не нужно как-либо явно передавать аргументы, которые уже в контексте. Они только и ждут, чтобы их красиво принимали🤤. Опять же отмечу, что, пожалуй, самый важный эффект здесь — снижение зависимости функции от оркестратора: функция явно принимает всё необходимое для работы. Как бонус — это удобно при работе в IDE: теперь IDE может анализировать код и подсвечивать проблемы, особенно если вы укажете типы.😎

В документации airflow есть полный список переменных контекста. Они их назвали почему-то переменными темплейтов (шаблонов), как будто ограничивая возможности их применения только теплейтами 🤔. Им следовало назвать их переменными контекста. забыли у меня спросить 😁

Вот ссылки на другие посты о Clean Code в Airflow
1) передача результата между тасками и свойство output
2) lambda в таске
3) про работу с датами
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9
Про что одна строка?

📝 Пожалуй самый первый, главный вопрос при работе с любым набором данных (датасетом, дата мартом (витриной), таблицей) - про что одна строка?

На самом деле это вопрос моделирования, но даже обычный разовый отчёт имеет свою модель.☝️

При этом неважно, говорим мы про подготовку данных или анализ — без понимания единицы (minimum grain) невозможно работать. Поэтому это первое, что нужно для себя прояснить, даже если заказчик не может ответить на вопрос прямо. 💡
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤3💯3
Язык данных = бизнес язык

📝 Если бизнес использует какие-то понятия или свойства, добавьте их в модель явно.

Нужно внимательно слушать как разговаривает бизнес и сделать так, чтобы данные могли явно отвечать на их вопросы. Ответы на вопросы бизнеса должны быть лёгкими и непринужденными.
Кстати из этого вытекают требования к модели данных. Я бы даже сказал, что в этом заключается искусство моделирования.

Чем лучше продумана модель, тем проще селект запрос к данным для ответа на вопрос.❤️ В идеале в селекте должны быть только джойны, агрегации и фильтры. И всё это просто, без подзапросов, кейсов и прочих трансформаций в селекте.

Пример
На мите вы слышите от бизнеса такую фразу:
лиды, которые позвонили нам по общую линию, могут иметь разное намерение (купить или получить поддержу), которое еще должно быть подтверждено.

В одной фразе заключена ценнейшая информация о бизнес модели! 👀 Есть сущность лид. Лид имеет свойство источник, свойство намерение, и свойство-флаг подтверждено ли намерение. Вот что должно быть в данных! Определения этих понятий, конечно, следует уточнить и в идеале записать в документ. Этот документ и есть бизнес модель данных. Не путать с табличками в базе данных приложения.
Как правило, в базе данных приложения техническая модель: лид создан через API, звонок был на какой-то номер, плюс некоторые признаки намерения и его подтверждения, которые ещё нужно правильно интерпретировать, то есть трансформировать.

Или вот бытовой пример. Бизнес просит посчитать бананы, а в базе приложения у вас только желтые объекты продолговатой формы.😁 Вот и назовите их в модели явно бананами и убедитесь, что точно отделили их от кукурузы.🙌

©️Задача инженера перевести данные с технического языка на бизнес язык.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🔥6❤5
Такие разные select запросы & трансформации

📝В прошлом посте я написал такую фразу:
Чем лучше продумана модель, тем проще селект запрос к данным для ответа на вопрос. В идеале в селекте должны быть только джойны, агрегации и фильтры. И всё это просто, без подзапросов, кейсов и прочих трансформаций в селекте.
В этом посте я разовью эту мысль и порассуждаю о трансформациях в обращении к данным. 🤔

Select запросы к данным бывают разные: с трансформацией и без.
Для ответа на вопросы (отчеты) трансформаций быть не должно!

Вот признаки трансформации в селекте:
🔵 Применение логики/правил, видно по использованию if, case, coalesce и других условных операторов.
🔵 GROUP BY используется для дедупликации, а не для агрегации.
🔵 WHERE используется для исключения некорректных данных, а не для выборки.
🔵 Есть подзапросы. Любые. Там, где JOIN, или там, где колонки, или через CTE (WITH) — неважно.
🔵 Изменение значений. Например, назначение имен идентификаторам статусов или переименование текстовых значений.
🔵 Расчёты и формулы.
🔵 Использование оператора LIKE.

Всё это должно быть сделано заранее, автоматизировано, описано и протестировано, чтобы исключить банальные ошибки и намеренные искажения. Понадобится витрина с применённой логикой.

Тут вы можете справедливо заметить, что бывают новые запросы, к которым данные ещё не готовы, или проверки гипотез. И то, и другое, конечно, потребует трансформаций в запросах, но это по сути — ресерч, проверка и подготовка нужной логики, и затем принятый вариант всё равно должен быть автоматизирован и превращён в витрину: это гарантирует, что трансформация всегда выполняется в одном месте и один раз, и любые изменения наследуются всеми зависимыми моделями.🙌 Кроме того логика трансформации может быть вынесена за пределы sql и выполнена на python, в spark и тд. А витрина может быть опубликована через API. Суть от этого не меняется. ☝️

Кстати, пример с API даже более наглядный в этом смысле: ведь чтобы дать доступ к данным через API, вы вынуждены подготовить всё заранее, чтобы пользователь просто пришёл и забрал как есть, с какими-то минимальными возможностями фильтрации (даже агрегации обычно там нет).

💡 Если для регулярных отчетов требуется трансформация - делайте витрину. Если есть более одной витрины с похожей логикой трансформации - пересмотрите модель данных.

©️не все select запросы одинаковы по смыслу. Для предсказуемых ответов на вопросы Select должны быть без трансформаций 👌
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11
Correlation vs causation

Это труба погнулась, потому что села чайка? Или чайка села именно на место сгиба уже после того, как труба была согнута?

В этом случае ответ, конечно, очевиден. Но эта картинка отлично подчёркивает саму идею:

📝 то, что выглядит на первый
взгляд
как причинно-следственная связь, может оказаться простым совпадением или следствием какой-то иной, настоящей причины.

Об этом стоит помнить при решении проблем. Особенно при траблшутинге (это когда что-то не работает, и срочно нужно сделать так, чтобы работало😁).

Например: это вот этот тяжёлый, кривой неоптимальный запрос повесил базу данных, или что-то нагрузило базу данных, а запрос просто оказался не в том месте и не в то время — прям как чайка на картинке.

Такие картинки кстати здорово всплывают в памяти в нужный момент и помогают посмотреть на ситуацию под другим углом. Наверное, поэтому они и называются мемами (на самом деле все сложнее и интереснее, спросите у gpt откуда слово meme). Так и я год назад увидел эту чайку, и теперь каждый раз её вспоминаю, когда нужно разобраться, что пошло не так - correlation vs causation. 🤔 Надеюсь и вам пригодится.

©️В целом этот пост снова про мышление инженера/аналитика. Посмотреть под разными углами, допустить неочевидное, усомниться в том, что бросается в глаза. 🧐
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤4😁2🤯1
Channel photo updated
Meta data или данные о данных

✏️ Meta data - это данные о данных. То есть это информация именно о самой записи, о строке: откуда она взялась, кто записал, когда создана запись, когда изменена и многое другое.

Это важно знать и записывать, чтобы иметь больше контроля над данными, чтобы знать больше деталей о конкретно этой записи (строке) в этой таблице. Иметь её "паспорт". 💪

На практике это просто дополнительные колонки в той же таблице. Ну или если у вас json, то дополнительный meta объект внутри. При этом их стоит явно отделить от данных, например используя префикс. Мы вот используем meta_.

Еще раз подчеркну, что важно не путать мета данные и данные!
Вот несколько примеров, объясняющих суть различия:

🔵 заказ создан 1 мая 21:00, а запись в DWH о нем создана 1 мая 22:35 (потому что у вас периодический батч процесс), created_at заказа будет отличаться от meta_created_at. А если потом уже внутри DWH на основе таблицы заказов будет обновлен дата март, то там опять же будет свое meta значение, например 22:45. Дата создания заказа не меняется, а вот дата создания записи о заказе в той или иной таблице будет своя.

🔵 Еще более наглядный пример при бэкфиле. Заказ создан в приложении 1 мая 2025 года. По какой-то причине данные о нем собраны вчера - 2 июня 2025. Важно знать, что эта запись была создана только вчера, и что отчеты построенные, например, 1 июня еще ничего о нем не знали! ☝️

🔵и ещё пример. вы сохраняете run id - идентификатор процесса, в рамках которого создана/изменены строка. Это поможет, например, при траблшутинге, так как вы точно знаете какие данные затронул тот самый ран.

В метаданные можно действительно засунуть много всего, и то, что я перечислил выше, — лишь малая часть того, что можно придумать. Все зависит или от проблем (в том числе потенциальных), которые вы хотите решить с их помощью, или от сложности потоков данных, которые ведут к таблице, особенно если там несколько пайплайнов. 😵‍💫
В каких-то таблицах мы накидываем чуть больше мета данных, в каких-то меньше.

Я даже думаю, что если у вас еще нет мета колонок в данных и вы считаете, что они вам не нужны, то просто вы еще не созрели 😁 Вы почуствуете этот момент, когда они вам понадобятся. Даже если вы просто собираете отчёт, стоит как минимум знать дату последнего обновления строки, которую вы взяли в отчёт.🫣

Минимальный набор по-моему должен включать две колонки:
©️meta_created_at
©️meta_updated_at
Я бы прям рекомендовал вставлять их во все таблицы. Для зависимых (downstream) процессов необходимо знать именно изменённые записи и meta_updated_at будет как раз кстати.👍

Ниже список колонок, которые мы используем в разных местах в зависимости от того, что мы хотим знать о записях табличке. Я сгруппировал их по "участнику" потока, через "руки" которого прошли данные, и он добавил свои мета "следы".

📎 Если есть записи из разных источников:
🔵meta_source
🔵meta_source_object_type
🔵meta_source_object_id

📎Об оркестраторе:
🔵meta_orchestrator_run_id
🔵meta_orchestrator_run_timestamp

📎 Хранилище:
🔵meta_created_at
🔵meta_updated_at

Плюс если храним историю изменений:
🔵meta_is_current
🔵meta_valid_from
🔵meta_valid_to
🔵meta_version_hash
🔵meta_version_number
🔵meta_version

Я напишу на эту тему ещё пару постов, например чуть подробнее напишу про meta_updated_at 🙌 так что продолжение следует... 😊
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13🔥3✍1
Meta данные - meta_updated_at. Часть 1

В прошлом посте писал о мета данных в целом, а в этом двойном посте остановлюсь на реализации одного из самых важных мета свойств - таймштамп последнего изменения. ☝️

Будет длинный двойной пост.
Конечно, я мог бы просто написать как мы делаем, но так неинтересно, по крайней мере мне самому 😁 я напишу почему именно так. Спойлер: во второй части будет код функциии на postgresql 👍

📝 meta_updated_at - таймштамп последнего изменения записи, то есть необходимо обновлять таймштамп каждый раз когда значение одной из колонок в строке изменилось.

Задача не такая тривиальная, как может показаться на первый взгляд, с учетом еще парочки условий:
🔸 если ничего не изменилось, то таймштамп обновлять не нужно. Даже если была выполнена операция update.
🔸 иметь гарантию, что не будет изменения данных без обновления этого таймштампа.

Для начала нужно решить кто ответственен за эту свойство. У нас есть три (как минимум) участника, через "руки" которых проходят данные и которые могут добавить свой мета след:
🔵источник
🔵исполнитель (оркестратор)
🔵хранилище.

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

Источник ничего не знает о том, в каком состоянии сейчас запись в месте назначения, более того он вообще не знает о существовании этого самого места назначения. Есть соблазн в момент извлечения данных добавить прям в select что-то вроде now или current timestamp, но это будет время извлечения, а не каждое извлечение = изменение!

Примерно по той же причине этого не может знать и исполнитель (оркестратор). Он может только знать о времени обработки, что опять же не тоже самое, что время изменения.

Текущее состояние записи знает только тот, кто ее хранит - хранилище.
Вот оно и должно отвечать за обновление этого таймштампа.

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

Вторая часть поста⬇️
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤3
Meta данные - meta_updated_at. Часть 2

(сначала смотри два предыдущих поста ⬆️)

У нас хранилище на postgresql, поэтому его и рассмотрим для примера. (хотя я думаю общий смысл можно реализовать и в других базах)

В postgresql можно создать триггер на update. Однако простой тригер на update будет менять таймштамп каждый раз, когда выполняется операция update независимо от того, изменилось ли что-то по факту в строке или нет. То есть, делая, например, бэкфил за месяц, все затронутые записи получат новый таймштамп! Так мы не хотим. Нам надо ставить новый только тогда, когда что-то изменилось. Значит нужна функция внутри тригера чуть похитрее.

Тригер на update очень удобен тем, что в нем одновременно есть и новая (new) и текущая (old) версия строк. Вот и сравним внутри функции значения колонок этих двух состояний, да так чтобы было неважно на какую таблицу повесили триггер: одна функция на всю базу.

Вот наша:

CREATE OR REPLACE FUNCTION set_meta_updated_at()
RETURNS TRIGGER AS $$
DECLARE
old_jsonb jsonb;
new_jsonb jsonb;
BEGIN
-- Convert rows to jsonb and remove metadata fields
old_jsonb := to_jsonb(OLD) - 'meta_updated_at' - 'meta_created_at';
new_jsonb := to_jsonb(NEW) - 'meta_updated_at' - 'meta_created_at';

-- Compare entire row contents
IF old_jsonb IS DISTINCT FROM new_jsonb THEN
NEW.meta_updated_at := CURRENT_TIMESTAMP;
RETURN NEW; -- proceed with update
END IF;

RETURN NULL; -- no changes → cancel the update
END;
$$ LANGUAGE plpgsql;


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

Результат:
1️⃣ Покрыты ВСЕ способы апдейта строки. Невозможно выполнить update, не запустив тригер. Это техническая гарантия, что meta_updated_at всегда обновится. То есть неважно, как и кто обновляет данные: батч процесс, реалтайм запись, руками через консоль - тригер всегда запустится и всегда поставит таймштамп, ЕСЛИ что-то изменилось.
2️⃣ Обновление meta_updated_at в одной транзакции с самой операцией update. Это тоже техническая гарантия, что если что-то идет не так, то транзакция целиком не будет принята: нет изменений нет и нового таймштампа.
3️⃣ Нет лишних dead tuples. Это особенности именно postgresql.

В двух словах про dead tuples: update строки приводит под капотом к созданию новой версии строки, а старая удаляется позже только при уборке - vacuum. То есть, по умолчанию postgresql не проверяет есть ли по факту отличия, и если 1000 раз запустить операцию update с одними и теми же данными на одну и ту же строку, postgresql создаст 1000 версий под капотом. Все они займут место на диске, создадут запись в лог, нагрузят диск операцией записи, нагрузят cpu чтобы все это провернуть.

Так вот функция в тригере отменяет update, если понимает, что изменений нет. Возврат null в коде выше как раз для этого. Нет новой версии -> нет dead tuple -> нет дополнительной нагрузки.
4️⃣ Быстро настроить для любой таблицы. Все очень просто. Одна функция на всю базу! В любой таблице создал колонку и создал тригер. Готово!
Более того, всё это можно обернуть в скрипт, и одним движением руки вы раскатаете решение на всю базу или всю схему. Мы так и сделали 😊

✏️Минус. (или нет)
Каждая операция update запускает функцию. Внутри функции какие-то операции, а выполняет операции cpu. Следовательно, появляется дополнительная нагрузку на cpu. Однако это сглаживается тем, что я писал выше про dead tuples. Справедливости ради скажу, что у нас нагрузка на cpu слегка выросла после введения этих тригеров, но скорость увеличилась из-за меньшего количества операций с диском. 👌

©️Очень простой способ получить мета колонку с таймштампом последнего изменения, да еще и с гарантией на техническом уровне. 🙌
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥3👏1
Изменения: предвидеть vs сделать так, чтобы они были неважны

Когда делаешь что-то, хочется, чтобы оно работало долго. Но условия, конечно, меняются, и все это понимают. Возникает желание как-то помочь себе будущему, и главное тут — не загнать себя в тупик.

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

Проблема в том, что вопрос поставлен так, что решения нет.

Предвидеть будущее невозможно. Невозможно сегодня сказать, что там изменится завтра, через месяц, через год. Разве что вы обладаете экстрасенсорными способностями. 😁. Но все-таки хочется же как-то облегчить жизнь себе в будущем. 🤔

Неопределенность всегда существует. Даже если вам кажется, что вы все продумали. Просто не нужно ее бояться. Пытаться все продумать наперед = бояться. Лучше принять ее и быть готовым к тому, что изменения будут. 🥲

Обычно, когда я размышляю, я приземляю мысль в какой-то лаконичный принцип или вывод. (В первую очередь для себя, чтобы у рассуждений был результат. Ну и здесь потом удобно писать🙌) В этот раз получилось вот что:

❌Предвидеть - создать решение, подходящее заранее предусмотренным изменениям.

✔️Сделать так, чтобы было неважно - создать решение, которое легко адаптировать при любом изменении.

✳️есть еще третий вариант, но он немного офтоп для этого поста. Сделать так, чтобы не жалко было сломать и выкинуть - fail fast. Это тоже интересный вариант для случаев, когда неопределенность на другом уровне - под сомнением сама необходимость решения проблемы или даже само ее существование. Однако это другая история

📎Правильная постановка вопроса:
Как сделать решение, которое легко адаптировать/расширять в случае изменений?

Это запускает мышление в другую сторону.

©️Я думаю, что создание технического решения, которое легко расширять, дополнять, легко понять - один из ключевых принципов инжиниринга. Работающий код ещё не значит хороший. Хороший код определяется НЕ сколько тем как он работает, а тем, как легко его изменять.

Эта финальная мысль мне напомнила книгу Роберта Мартина Clean architecture, которая несколько лет назад дала мне ответы на многие вопросы 😉
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7
Квантовая аналитика 😄

Такой перл у нас родился сегодня на дейлике 😆

А тема вообще очень серьёзная. И это я не про квантовую физику😁.

Auditability - полная прослеживаемость и проверяемость данных: почему, в какой момент менялись. И как следствие этого свойства — возможность получить данные на определённый момент времени.

©️Чтобы получать предсказуемые отчеты, а не квантовую аналитику, всегда собираем историю изменений и метаданные 🙌
Please open Telegram to view this post
VIEW IN TELEGRAM
😁6👍5
Без паники!

Пост про траблшутинг и проблем солвинг.

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

Паника - это когда решение принимается не на основе исследования причины, а на основе страха, что что-то было сделано не так.
Возможно, в основе лежит неуверенность в себе.🤔
Ошибка на проде, из-за которой может быть упущена прибыль, конечно, ситуация критическая, и тут важно сохранять спокойствие. Все как на ОБЖ учили😁

Вот что поможет избежать паники:
1️⃣ Доверяй себе — если исходить из того, что вы хороший инженер и просто так на удачу ничего не релизите, то значит, вы всё сделали правильно.
2️⃣ Доверяй коллеге — это следующий шаг от доверия себе — он/она тоже хороший инженер и т. д.

Так что вместо того, чтобы сразу по умолчанию признавать всю работу некачественной, стоит потратить немного времени на поиск причины.

Несколько возможных сценариев:

©️ Причина может вообще не быть связана с последними изменениями непосредственно (см. пост). Например, кто-то где-то что-то поменял и то, что вы сделали релиз - просто совпадение.

©️ Причина может быть связана косвенно: изменения выявили скрытую проблему в другом месте.

©️ Причина в небольшой ошибке в релизе - баг.

©️ Причина в критической ошибке в релизе.

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

Берите пример с кота на картинке: без паники! ❤️
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6👏2
Сфотал недавно на одном ларьке.

Эта картинка почему-то напомнила мне документацию.

Любую.

К чему бы это.🤔😁
😁13👍2
Google, heavy is the crown?

Раньше я думал, что гугл это идеал, если бы это был человек, то у него был бы нимб или корона. Но поработав с сервисами гугла, я понял, что ничего там особенного:
🔸ошибки (да, я и 503 видел от одного из их сервисов в течение нескольких часов😳),
🔸странное поведение,
🔸запутанная и где-то неполная документация

Все как у людей. 😁 То же самое могу сказать и про facebook, bing и ещё ряд разных не таких известных сервисов. Google — просто яркий пример, чтобы донести саму идею.

Я осознал что все это просто сервисы, написанные простыми разработчиками, которые не факт, что умнее меня или вас. 🧐 (Дисклеймер: я сейчас не имею ввиду топ инженеров того же гугла, которые меняют мир, я имею ввиду ребят, которые работают "в поле" и каждый день пишут код)

Мы как дата инженеры часто делаем интеграции с другими сервисами, API, приложениями, собираем данные из баз и тд. То есть пользуемся результатом работы других разработчиков. Так вот мы часто склонны думать, что если что-то не получается, то обязательно виноваты мы. Я тоже был таким раньше, особенно в отношении гигантов. Но со временем, с опытом, с тонной прочитанной документации, с общением с поддержкой разных сервисов я понял, что чудес не бывает. Везде просто люди. Везде есть ошибки и неточности.

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

❌Опасно! Есть риск уйти в крайность и стать вечно ворчащим разработчиком, который ругает всё, кроме того, что сделал сам! 🙅‍♂

©️Я разработчик ©️ Я могу ошибаться ©️ Все сделали люди ©️Они такие же разработчики как я ©️Они могут ошибаться 🙌
Please open Telegram to view this post
VIEW IN TELEGRAM
👏6
Дата инженерная доля

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

Ошибки, неточности могут быть в любом сервисе, с которым мы интегрируемся. Но это не всё...

📖 Проблемное поведение сервисов, приложений, источников данных:

🔸Ошибки - сервис не выполняет предъявляемые ему требования

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

🔸Неполные данные - сервис выполняет все известные требования, но в данных не хватает деталей, однако сервис не может добавить эти детали в принципе. Например, есть три внешних сервиса, выполняющие одинаковую функцию. Сервис 1 предоставляет свойства A, B, C; сервис 2 - тоже A, B, C; сервис 3 только A, B.

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

🔸Разные комбинации всего этого одновременно в рамках одного сервиса

А теперь самое интересное.
Бизнес требует полные, точные данные без ошибок и стабильно.😐


Если сервис внутренний, то еще можно как-то приоритезировать задачи в команде разработки, но если внешний, то привидение всего этого в порядок ложится на хрупкие мощные плечи дата инженеров. 💪
Все же просто:

➡️ Ошибки? Ну вы же их видите - добавьте в код костыль, фильтраните, пока мы делаем фикс.
➡️ Ошибку исправили. В исторических данных она осталась? Конечно, как мы в прошлом ошибку исправим. Проблема была такая-то - исторические данные исправьте сами.
➡️ Неточности? Да, знаем — добавьте логику на своём уровне, пока у нас руки не дошли туда (никогда не дойдут).
➡️ Неполные данные? Заполните. Сделайте допущение, мы и правила вам расскажем. Примерно.
➡️ Нестабильный источник? Ну есть же второй еще. Берите из него, если первый недоступен, да смотрите, чтобы дублей не было.

⬇️⬇️⬇️⬇️⬇️⬇️⬇️⬇️⬇️⬇️

Бизнес:
- В общем сделайте так, чтобы данные отвечали на наши вопросы.
Дата инженеры:
- ок


Такая вот дата инженерная доля. 🥲🫡
Please open Telegram to view this post
VIEW IN TELEGRAM
🫡9👨‍💻3