Настоящий детектив.
Основано на реальных событиях.
Очень интересная история приключилась в нашем офисе на днях.
Хитрость, бдительность, находчивость, арест. В жанре драма, криминал, комедия 😁
В офис проник посторонний парень (проскочил в открытую дверь когда кто-то выходил). Как выяснилось потом, это был вор, который проникал в офисы и, видимо, в расчёте на то, что не все знают друг друга в лицо, ходил по офису и в итоге выносил какие-то вещи. 🫣 Назовем его хитрый. Так вот поднялся хитрый на один этаж, заглянул в дверь, на второй, на третий... а там у нас бар и зона, где можно покушать. Дело было после обеда и пара наших ребят припозднились и были там. И тут хитрому не повезло, потому что это были именно те ребята, которые знают всех в лицо. Они начали расспрашивать хитрого, кто он и зачем пришёл. Тот сказал, что он пришёл на собеседование (цитата) "программистом за любые деньги". Но наших ребят не проведешь, они уже поняли, в чём дело, и проявили удивительную находчивость: предложилихитрому наивному пройти в митинг-рум для "собеседования" и, пока один из наших находчивых делал вид, что собеседует его, второй вызвал полицию.
Полчаса шло это "собеседование", пока полиция не приехала и не арестовала наивного. Оказалось, что он уже три месяца был в розыске за кражу на сумму более 10К евро из разных офисов. Но потом вошёл не в ту дверь... 🙌
Из офисного чата: 😂
Основано на реальных событиях.
Очень интересная история приключилась в нашем офисе на днях.
Хитрость, бдительность, находчивость, арест. В жанре драма, криминал, комедия 😁
В офис проник посторонний парень (проскочил в открытую дверь когда кто-то выходил). Как выяснилось потом, это был вор, который проникал в офисы и, видимо, в расчёте на то, что не все знают друг друга в лицо, ходил по офису и в итоге выносил какие-то вещи. 🫣 Назовем его хитрый. Так вот поднялся хитрый на один этаж, заглянул в дверь, на второй, на третий... а там у нас бар и зона, где можно покушать. Дело было после обеда и пара наших ребят припозднились и были там. И тут хитрому не повезло, потому что это были именно те ребята, которые знают всех в лицо. Они начали расспрашивать хитрого, кто он и зачем пришёл. Тот сказал, что он пришёл на собеседование (цитата) "программистом за любые деньги". Но наших ребят не проведешь, они уже поняли, в чём дело, и проявили удивительную находчивость: предложили
Полчаса шло это "собеседование", пока полиция не приехала и не арестовала наивного. Оказалось, что он уже три месяца был в розыске за кражу на сумму более 10К евро из разных офисов. Но потом вошёл не в ту дверь... 🙌
Из офисного чата: 😂
🤣17🏆4❤1
Маленькая инженерная задача. Часть 1. Контекст.
На гифке выше — голова Франца Кафки в Праге.
Взялся я описать одну небольшую инженерную задачу, с которой столкнулся недавно, и получилась аж серия постов. 😳 Будет много специфики, однако идея этой серии в том, чтобы показать сам процесс решения от определения проблемы до выбора технической реализации так, как это было в жизни.
📝 Задача связана с Apache Kafka — брокером сообщений, частым участником архитектуры приложений и дата-платформ.
Брокер сообщений работает в producer-consumer схеме, то есть продюсер закидывает туда сообщение (публикует), а получить его может множество подписчиков (консьюмеров) – сервисов, которым нужно как-то использовать этот опубликованный факт: запускать внутреннюю логику или просто сохранять данные.
У нас Kafka в первую очередь используется как инфраструктурный элемент для общения между приложениями (асинхронный API, декаплинг) и только во вторую для публикации данных. То есть это даже не часть дата платформы. Дата платформа тут выступает лишь как один из консьюмеров.
Еще одна важная особенность. Мы используем один общий поток для всех событий (в kafka это называется топик). Решение со своими плюсами и минусами. И именно с минусами этого подхода и связана задача, о которой я пишу.
Плюс единого потока:
🔵 участникам легко интегрироваться (всегда только один поток),
🔵 легко поддерживать инфраструктуру (не нужно добавлять топики),
🔵 команда продюсера ни о чем не думает, не делает запросов на создание топиков в команду поддержки (девопсы или дата инженеры), а просто начинает отправлять события.
Все очень просто, а значит надёжно.
Минус:
🔸 консьюмер вынужден читать весь поток и выбирать из него только интересующие его события. Вполне может быть так, что подписчик "пропускет" 90% всех событий в ожидании "того самого". 😵💫
Вот история с применением СПР паттерна (писал про него тут).
📝 Ситуация: есть kafka с одним общим топиком, в который попадают все события. Еще есть http proxy микросервис (написан на Go), который принимает http post запрос, валидирует пейлоад и отправляет его в kafka. Все события имеют единую схему метаданных и пейлоад. Есть несколько продюсеров и несколько консьюмеров. kafka и прокси развернуты в кубернетес (aws eks).
🐞 Проблема: есть флоу, которые выполняются с превышением SLO, то есть end-to-end время превышает требование бизнеса.
End-to-end для бизнеса означает от одного бизнес-события до другого. Например, клиент на сайте нажал кнопочку "купить" и через 5 секунд получил email с подтверждением. Заметьте, что бизнесу пофиг: Kafka там или что-то ещё под капотом (пост бизнесу пофиг).
💡 Решение: 1) предоставить консьюмерам возможность потреблять часть событий; 2) организовать мониторинг каждого шага, времени работы каждого участника, чтобы такие вопросы не возникали в будущем, чтобы точно знать, кто и где даёт задержки; 3) переключить консьюмера на "урезанный" топик и наблюдать за флоу, так как есть вероятность, что задержки в этом конкретном флоу были вызваны чем-то другим.
Пункт 3 решения может показаться вам странным, как будто мы гадаем. Вам не показалось 🙂 Выглядит логично сначала организовать мониторинг на всех этапах, выяснить точно, а потом действовать. Так бы и было где-то в книжке, но на решения в жизни влияют еще и другие факторы (ресурсы, загруженность команд, другие приоритетные задачи, внутренние политические моменты, личные взаимоотношения и фазы луны 😁). В данном случае по совокупности факторов нам было проще предоставить урезанный топик и посмотреть, что будет. Даже если в этом флоу это не поможет, в любом случае хорошо иметь возможность быстро фильтровать топики в будущем.
Дальше я буду писать о создании урезанных топиков (п. 1 решения), а мониторинг в этой истории опустим.
Итак, ситуация, проблема и решение определены. Теперь можно уже делать? Нет. Ещё подумать ☝️ 😁
Продолжение следует...
На гифке выше — голова Франца Кафки в Праге.
Взялся я описать одну небольшую инженерную задачу, с которой столкнулся недавно, и получилась аж серия постов. 😳 Будет много специфики, однако идея этой серии в том, чтобы показать сам процесс решения от определения проблемы до выбора технической реализации так, как это было в жизни.
Брокер сообщений работает в producer-consumer схеме, то есть продюсер закидывает туда сообщение (публикует), а получить его может множество подписчиков (консьюмеров) – сервисов, которым нужно как-то использовать этот опубликованный факт: запускать внутреннюю логику или просто сохранять данные.
У нас Kafka в первую очередь используется как инфраструктурный элемент для общения между приложениями (асинхронный API, декаплинг) и только во вторую для публикации данных. То есть это даже не часть дата платформы. Дата платформа тут выступает лишь как один из консьюмеров.
Еще одна важная особенность. Мы используем один общий поток для всех событий (в kafka это называется топик). Решение со своими плюсами и минусами. И именно с минусами этого подхода и связана задача, о которой я пишу.
Плюс единого потока:
Все очень просто, а значит надёжно.
Минус:
Вот история с применением СПР паттерна (писал про него тут).
End-to-end для бизнеса означает от одного бизнес-события до другого. Например, клиент на сайте нажал кнопочку "купить" и через 5 секунд получил email с подтверждением. Заметьте, что бизнесу пофиг: Kafka там или что-то ещё под капотом (пост бизнесу пофиг).
Пункт 3 решения может показаться вам странным, как будто мы гадаем. Вам не показалось 🙂 Выглядит логично сначала организовать мониторинг на всех этапах, выяснить точно, а потом действовать. Так бы и было где-то в книжке, но на решения в жизни влияют еще и другие факторы (ресурсы, загруженность команд, другие приоритетные задачи, внутренние политические моменты, личные взаимоотношения и фазы луны 😁). В данном случае по совокупности факторов нам было проще предоставить урезанный топик и посмотреть, что будет. Даже если в этом флоу это не поможет, в любом случае хорошо иметь возможность быстро фильтровать топики в будущем.
Дальше я буду писать о создании урезанных топиков (п. 1 решения), а мониторинг в этой истории опустим.
Итак, ситуация, проблема и решение определены. Теперь можно уже делать? Нет. Ещё подумать ☝️ 😁
Продолжение следует...
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Маленькая инженерная задача. Часть 2. Решение
Дальше рассуждения о том, как именно реализовать решение. 🤔
Мы хотели найти решение с наименьшим изменением уже работающей архитектуры и наименьшей поддержкой в будущем и конечно с высокой гарантией. Нужно сохранить общий топик для всех, кто уже на него подписан, и создавать отдельные топики по каким-то правилам так, чтобы не лазить постоянно в конфигурации/код для настройки.
Вот некоторые из рассмотренных подходов:
©️ топик под требования консьюмера, то есть консьюмер приходит и говорит "меня интересуют конкретно события А, B, C" и создаем соответствующий топик именно под него. Отмели сразу, потому что на ровном месте вносит зависимость разработчиков консьюмера от команды поддержки инфраструктуры. К тому же задач может быть множество, и каждый раз создавать топик — перебор.
©️ топики под каждый тип события. Многовато получится топиков. У нас более 100 сейчас разных событий и постоянно добавляются еще.
©️ топики по группам событий. У нас события могут быть разделены по контекстам. Их около 20. А консьюмеры подписываются на контекст и получают сабсет событий и чувствуют себя лучше. Выбрали этот вариант.✔️
Идем дальше: создавать топики динамически или предварительно? Динамически звучит лучше: появился новый контекст, автоматически создался топик. Так участие инженеров нужно только один раз при запуске, а потом все работает само - красота. 🤤
Теперь детали: инструменты, языки и тд. Тут тоже варианты.
🔵 внешние saas инструменты. Отмели сразу, что я даже не искал такие. Kafka у нас в AWS EKS кластере (Kubernetes), поэтому подключение внешнего инструмента потребует "открыть" инфраструктуру в мир. Плюс такие тулы не могут дать 99% гарантию, что все события попадут в нужные топики, по крайней мере банально из-за добавления общения по сети, не говоря уже о внутренних делах того сервиса. Ну и конечно saas стоит денег 💰
🔵 расширить функции уже имеющегося http proxy микросервиса, чтобы обрабатывая событие, он сразу записывал его в два топика: общий и специальный. Тоже отклонили по архитектурной причине: из простого "деревянного" прокси он превратится в сервис с логикой. Сломается принцип единой ответственности (SOLID). Сейчас его простота даёт гарантию доставки событий, а добавление логики внесёт риск. И это потребует вмешательства в то, что уже работает.
🔵 готовый open-source инструмент, развёрнутый внутри того же кластера Kubernetes и того же namespace, где и Kafka. Цельная инфраструктура работает слаженно. Исключаются любые внешние "помехи", а вся работа происходит в одном и том же изолированном namespace. Вот это нам понравилось. 👍
🔵 кастомный микросервис внутри кластера. Очевидный минус: нужна разработка, а потом поддержка.
В итоге техническая задача звучала так:
✏️ подобрать и внедрить инструмент, который будет из общего топика динамически генерировать топик для каждой группы событий (или типу событий) так, чтобы при появлении нового типа автоматически создавался отдельный топик без вмешательства инженеров.
Вот теперь можно делать. 😁Спойлер: такого инструмента нет
Продолжение следует...
Дальше рассуждения о том, как именно реализовать решение. 🤔
Мы хотели найти решение с наименьшим изменением уже работающей архитектуры и наименьшей поддержкой в будущем и конечно с высокой гарантией. Нужно сохранить общий топик для всех, кто уже на него подписан, и создавать отдельные топики по каким-то правилам так, чтобы не лазить постоянно в конфигурации/код для настройки.
Вот некоторые из рассмотренных подходов:
Идем дальше: создавать топики динамически или предварительно? Динамически звучит лучше: появился новый контекст, автоматически создался топик. Так участие инженеров нужно только один раз при запуске, а потом все работает само - красота. 🤤
Теперь детали: инструменты, языки и тд. Тут тоже варианты.
В итоге техническая задача звучала так:
Вот теперь можно делать. 😁
Продолжение следует...
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4
Маленькая инженерная задача. Часть 3. Реализация
Из предыдущего поста:
Оказалось, что не существует готового инструмента, закрывающего данный вопрос, чтобы разработка не нужна была вообще, а только конфигурация (например тераформ, хелм и всё). 😳🫣😞
Вот что есть:
🟣 Ksql – популярный и не требующий разработки open source инструмент. Есть официальный helm. Удобно создавать топик по условиям, но динамически он не умеет. 🤬
🟣 Kafka Streams – библиотека, которая позволяет накодить что угодно на python или java, но ключевое слово накодить, то есть это будет кастомная разработка, которую надо поддерживать. 💔
🟣 Apache Flink – стриминг инструмент с широкими возможностями и, конечно, умеет динамически, но тяжелый и требует сложной конфигурации – для данной простой задачи это перебор. 🤯
Есть еще парочка вариантов, которые накидал gpt, но все они примерно о том же.🤨
©️ В итоге пошли на компромисс. Отказались от идеи динамической генерации с необходимостью разработки в пользу предварительно настроенных топиков с использованием готового инструмента – ksql. Новые контексты добавляются относительно редко (может, раз в несколько месяцев), и да, придётся зайти в конфиг ksql и добавить ещё один стрим, но это на данный момент показалось проще, чем делать разработку.
Ksql развернули через helm внутри существующего неймспейса в кубернетес рядышком с kafka и proxy сервисом. Прямо там же, через helm, на языке SQL описали новые стримы в интуитивно понятном формате select запроса типа: выбрать из топика A, где контекст равен B, и отправить в топик C. 🙌
Я намеренно не добавлял здесь код конфигурации ksql. Суть истории не в коде, а в процессе решения проблемы и в том, что изначальную идею пришлось в пересмотреть. Не исключено, что будут ещё и другие итерации.
〰️ 〰️ 〰️ 〰️ 〰️
Часть 4. Рефлексия
Завершу я эту историю 3 финальными мыслями.
1️⃣ Описание относительно маленькой задачи растянулось аж на 3 поста. Да, я мог бы просто написать: нам нужны были топики в kafka и мы внедрили kqsl. Уложился бы в один пост. Но упустил бы самое главное: в реальной работе редко бывает так, что решение очевидно и однозначно. Любую проблему можно решить множеством способов. Более того, ещё и саму проблему нужно правильно определить.
2️⃣ Минусы есть всегда. Наш архитектор сказал такую мысль:
3️⃣ "Накликать" не получилось. В последнее время я много читал про modern data stack, off-the-shelf инструменты, и создалось впечатление, что на любой каприз уже есть проверенное готовое решение с открытым кодом. А тут вдруг облом с супер популярной кафкой: отсутствие возможности создавать топики динамически без кастомного кода. Получается, еще далеко до того, чтобы инженер только сидел и "накликивал" себе решение на готовых инструментах.
©️ Может быть вы заметили, что в той истории я упоминал разные термины и концепты: брокер сообщений, at least once доставка, принципы SOLID, асинхронный API и другие. Ставьте ❤️ если хотите, чтобы я кратко объяснил их в одном из следующих постов. Хотя я все равно опишу, потому что хочу😁
Из предыдущего поста:
подобрать и внедрить инструмент, который будет из общего топика динамически генерировать топик для каждой группы событий (или типу событий) так, чтобы при появлении нового типа автоматически создавался отдельный топик без вмешательства инженеров.Звучит несложно, подумал я, с учётом огромной популярности Kafka, с учётом всех этих разговоров о modern data stack, где на каждую идею уже придуман off-the-shelf (прямо с полки), plug-and-play инструмент. По крайней мере такое сложилось у меня впечатление, когда я последнее время читал разные статьи, посты и тд. (пост про modern data stack)
Оказалось, что не существует готового инструмента, закрывающего данный вопрос, чтобы разработка не нужна была вообще, а только конфигурация (например тераформ, хелм и всё). 😳🫣😞
Вот что есть:
Есть еще парочка вариантов, которые накидал gpt, но все они примерно о том же.
Ksql развернули через helm внутри существующего неймспейса в кубернетес рядышком с kafka и proxy сервисом. Прямо там же, через helm, на языке SQL описали новые стримы в интуитивно понятном формате select запроса типа: выбрать из топика A, где контекст равен B, и отправить в топик C. 🙌
Я намеренно не добавлял здесь код конфигурации ksql. Суть истории не в коде, а в процессе решения проблемы и в том, что изначальную идею пришлось в пересмотреть. Не исключено, что будут ещё и другие итерации.
Часть 4. Рефлексия
Завершу я эту историю 3 финальными мыслями.
Если инженер приходит и говорит, что это решение нужно выбрать и оно идеально со всех сторон, значит, он не доработал. Всегда что-то теряем.Решение может быть подходящим или нет с учётом того, на что вы готовы пойти (разработка, поддержка, цена, гарантии и т. д.).
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3
Почисти свою архитектуру
Всё перечисленное на картинке — только ingestion layer: извлечь/принять данные из какого-либо источника и сохранить как есть в raw storage.
Вот так внезапно может выглядеть ваш стек, если каждый раз выбирать удобный off-the-shelf инструмент или просто тот, что был под рукой, не задумываясь об архитектуре.
В моём понимании, даже два инструмента, выполняющие одну и ту же задачу, — уже много. Одну и ту же я имею в виду на архитектурном уровне. Конечно, обстоятельства бывают разные и иногда это оправдано, но нужно понимать, что это технический долг: архитектуру придётся почистить.
В прошлом году видел твит Роберта Мартина – автора книг Clean architecture, Clean code и других.
Тут фишка в игре слов на английском: clean можно перевести как "чистый" и как "чисти". Обычно "clean" в его книгах переводят как "чистый/чистая". А в том твите он писал, что словосочетание так же хорошо звучит и как команда, то есть "Чисти архитектуру" и "Чисти код", подчеркивая что это постоянный процесс, а не однократное решение.
Что ж, пойду чистить. 🧹
Всё перечисленное на картинке — только ingestion layer: извлечь/принять данные из какого-либо источника и сохранить как есть в raw storage.
Вот так внезапно может выглядеть ваш стек, если каждый раз выбирать удобный off-the-shelf инструмент или просто тот, что был под рукой, не задумываясь об архитектуре.
В моём понимании, даже два инструмента, выполняющие одну и ту же задачу, — уже много. Одну и ту же я имею в виду на архитектурном уровне. Конечно, обстоятельства бывают разные и иногда это оправдано, но нужно понимать, что это технический долг: архитектуру придётся почистить.
В прошлом году видел твит Роберта Мартина – автора книг Clean architecture, Clean code и других.
“Clean Code!” is a command, not a noun. We don’t write Clean Code — we Clean Code.
Тут фишка в игре слов на английском: clean можно перевести как "чистый" и как "чисти". Обычно "clean" в его книгах переводят как "чистый/чистая". А в том твите он писал, что словосочетание так же хорошо звучит и как команда, то есть "Чисти архитектуру" и "Чисти код", подчеркивая что это постоянный процесс, а не однократное решение.
Что ж, пойду чистить. 🧹
👏7🔥3💯1
Обнаружил для себя, что Ask AI на официальном сайте Clickhouse отлично помогает. По-моему, лучше, чем просто ChatGPT или Claude в вопросах, связанных с Clickhouse. Наверное, там под капотом тот же ChatGPT, но обучен он на официальной документации.👍
В ClickHouse огромное количество специфических настроек, особого синтаксиса, фич, которые ещё тестируются, но уже доступны при включении флагов. 😵💫 Другие "чаты" путаются во всём этом и часто предлагают то, что не работает. 🤬 Я слишком часто писал в chatgpt что-то типа "doesn't work, unknown setting, unknown system table" и тд, пока не открыл для себя этого официального помощника. И ответит и ссылочку на документацию прикрепит. 🙌
В общем, мне нравится! Последние пару месяцев с вопросом по Clickhouse в первую очередь иду туда, и обычно этого достаточно. Попробуйте! Может кому-то тоже зайдет. 😊
В ClickHouse огромное количество специфических настроек, особого синтаксиса, фич, которые ещё тестируются, но уже доступны при включении флагов. 😵💫 Другие "чаты" путаются во всём этом и часто предлагают то, что не работает. 🤬 Я слишком часто писал в chatgpt что-то типа "doesn't work, unknown setting, unknown system table" и тд, пока не открыл для себя этого официального помощника. И ответит и ссылочку на документацию прикрепит. 🙌
В общем, мне нравится! Последние пару месяцев с вопросом по Clickhouse в первую очередь иду туда, и обычно этого достаточно. Попробуйте! Может кому-то тоже зайдет. 😊
👍17
Теория разбитых окон
"Теория разбитых окон" появилась в США в начале 1980-х годов.
По-моему, теория работает много где, в том числе и в инжиниринге данных.
У меня есть пунктик по поводу порядка в нейминге (таблиц, свойств, типов), в синтаксисе, в структуре директорий в репозитории и тд. Это как порядок дома или в городе: разбитое окно нужно менять сразу.
Вот пример.
Мы пишем события. У события есть свойство type. Обычно его пишем в snake_case: something_occured. Но однажды кто-то пишет someThing_occured. Мне такие вещи режут глаз. Смешение camelCase и snake_case в одном значении - перебор. Мы это сразу поправили. А оставили бы так и завтра пришел бы другой, посмотрел и написал в новом событии Smth Occured. Потом третий добавил бы "smth occured_new Final 2025". Окна начали бы разбивать.
Когда я вижу такое в чужих реализациях, у меня сразу снижается уровень доверия. Если ребята не отнеслись серьезно к порядку, то как я могу доверять тому, что они сделали внутри? Это как зайти в автомастерскую и увидеть верстак заваленный хламом и грязные инструменты на полу. Мало вероятно, что работу тут сделают хорошо...
©️ Окна будут разбивать. Может парочку разобьете даже вы сами. 🫣 Главное — заметить это и быстро навести порядок!
"Теория разбитых окон" появилась в США в начале 1980-х годов.
Суть теории в том, что признаки беспорядка (разбитое окно, граффити, мусор) сигнализируют: за этим местом не следят.
Наблюдали такую картину: рядом могут стоять два здания — одно ухоженное, другое с разбитым окном. И именно второе продолжали портить снова и снова. Если разбито одно окно, то вскоре разобьют и другое, а потом и третье и здание быстро приходит в упадок.
Отсюда идея: беспорядок порождает новый беспорядок.
Решение — устранять даже мелкие нарушения как можно быстрее, чтобы разорвать эту цепочку.
Позже этот подход применяли, в том числе, в Нью-Йорке, и в ряде случаев он показал заметный эффект — хотя на первый взгляд кажется, что «ну подумаешь, одно разбитое окно».
По-моему, теория работает много где, в том числе и в инжиниринге данных.
У меня есть пунктик по поводу порядка в нейминге (таблиц, свойств, типов), в синтаксисе, в структуре директорий в репозитории и тд. Это как порядок дома или в городе: разбитое окно нужно менять сразу.
Вот пример.
Мы пишем события. У события есть свойство type. Обычно его пишем в snake_case: something_occured. Но однажды кто-то пишет someThing_occured. Мне такие вещи режут глаз. Смешение camelCase и snake_case в одном значении - перебор. Мы это сразу поправили. А оставили бы так и завтра пришел бы другой, посмотрел и написал в новом событии Smth Occured. Потом третий добавил бы "smth occured_new Final 2025". Окна начали бы разбивать.
Когда я вижу такое в чужих реализациях, у меня сразу снижается уровень доверия. Если ребята не отнеслись серьезно к порядку, то как я могу доверять тому, что они сделали внутри? Это как зайти в автомастерскую и увидеть верстак заваленный хламом и грязные инструменты на полу. Мало вероятно, что работу тут сделают хорошо...
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤4
Покажи деньги!
В последнее время я много размышляю о конечной пользе для бизнеса от существования данных и существования дата-платформы. Поэтому мне понравился недавний пост Джо Рейса — автора книги Fundamentals of Data Engineering.
Вот небольшая выдержка из него:
Именно эта часть прям "попала в меня" и заставила задуматься. Я много раз заявлял бизнесу, что качество — цель! 🫣
Но качество не цель, а средство.
PS. Увидел ещё на днях выражение: data-to-dollar, в котором заключена суть ожиданий бизнеса. 💸 коротко и ёмко! 👍
В последнее время я много размышляю о конечной пользе для бизнеса от существования данных и существования дата-платформы. Поэтому мне понравился недавний пост Джо Рейса — автора книги Fundamentals of Data Engineering.
Вот небольшая выдержка из него:
Как продать моделирование данных?
Анти-патерн: Продажа «качества данных» или «единого источника правды» в качестве конечной цели.
«Нам нужно моделировать данные, чтобы улучшить качество данных» — звучит прекрасно. Проблема в том, что «качество данных» — абстрактное понятие, о котором даже опытные специалисты по данным не всегда могут договориться. А «единственный источник истины» звучит отлично в теории, но что это на самом деле означает и достижимо ли это? Оба выражения — всего лишь технические средства для достижения цели.
Когда бизнес-лидер слышит такие фразы, он скорее всего думает: «И что дальше?» Плохое качество данных — не его проблема. Его проблема — последствия плохого качества данных.
Именно эта часть прям "попала в меня" и заставила задуматься. Я много раз заявлял бизнесу, что качество — цель! 🫣
Но качество не цель, а средство.
PS. Увидел ещё на днях выражение: data-to-dollar, в котором заключена суть ожиданий бизнеса. 💸 коротко и ёмко! 👍
❤7👍4
Ловушка кодера
Писать код или использовать готовый инструмент? 🤔
Есть задача, и ты точно знаешь, что нужно сделать. Ты точно знаешь, что можешь написать код, обеспечивающий нужное поведение. При этом есть инструмент, который вроде как умеет это делать, но ты только слышал/читал о нём без практического опыта. У задачи конечно есть сроки и требования к качеству.
Вариант «накодить» понятен и предсказуем: известно, что будет работать, известно, сколько надо времени. Новый инструмент вносит неопределённость, точно неизвестно, удастся ли уложиться в требования. Поэтому в такой ситуации правильное решение — накодить.
Это я назвал ловушкой кодера. 👇⏭
📎 В отдельно взятой ситуации решение принимается правильное — «взять известное», но в долгосрочной перспективе понятно, что никогда не будет задачи с достаточным временем, чтобы изучить новое. То есть снова и снова будет приниматься "правильное" решение....
Поэтому новые инструменты нужно изучать до того, как они понадобятся. Тогда, когда понятно, что они потенциально понадобятся или потенциально могут улучшить то, что уже есть: ускорят доставку результата, уменьшат стоимость, упростят поддержку, уменьшат порог входа в текущую реализацию, улучшат понимание решения другими участниками команды и т. д.
Если инструмент нужен прямо сейчас, то уже поздно разбиратся, лучше кодить. Но только инструмент надо тоже изучить в спокойном режиме. Это инвестиция в будущее – выход из ловушки.🙌
Это все равно что пытаться вдруг заговорить на итальянском, когда ты уже в италии и тебе нужно купить еду, чтобы не помереть с голода. Просто покажи пальцем на пиццу! Да, так от голода, может, и не помрёшь, но качество жизни будет так себе — завтра начинай учить язык.
©️ Инструменты и технологии позволяют решать задачи быстро только тогда, когда ты знаешь, как ими пользоваться прямо сейчас. В краткосрочной перспективе лучше взять известное, а в долгосрочной — изучить разное и выбрать лучшее.
Писать код или использовать готовый инструмент? 🤔
Есть задача, и ты точно знаешь, что нужно сделать. Ты точно знаешь, что можешь написать код, обеспечивающий нужное поведение. При этом есть инструмент, который вроде как умеет это делать, но ты только слышал/читал о нём без практического опыта. У задачи конечно есть сроки и требования к качеству.
Вариант «накодить» понятен и предсказуем: известно, что будет работать, известно, сколько надо времени. Новый инструмент вносит неопределённость, точно неизвестно, удастся ли уложиться в требования. Поэтому в такой ситуации правильное решение — накодить.
Это я назвал ловушкой кодера. 👇
Поэтому новые инструменты нужно изучать до того, как они понадобятся. Тогда, когда понятно, что они потенциально понадобятся или потенциально могут улучшить то, что уже есть: ускорят доставку результата, уменьшат стоимость, упростят поддержку, уменьшат порог входа в текущую реализацию, улучшат понимание решения другими участниками команды и т. д.
Если инструмент нужен прямо сейчас, то уже поздно разбиратся, лучше кодить. Но только инструмент надо тоже изучить в спокойном режиме. Это инвестиция в будущее – выход из ловушки.🙌
Это все равно что пытаться вдруг заговорить на итальянском, когда ты уже в италии и тебе нужно купить еду, чтобы не помереть с голода. Просто покажи пальцем на пиццу! Да, так от голода, может, и не помрёшь, но качество жизни будет так себе — завтра начинай учить язык.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7🤔2❤1💩1
Материализация vs стриминг в ETL: контроль потребления памяти в Airflow
Рассмотрим простой ETL-процесс, реализованный в Airflow.
Есть источник и назначение. На практике это может быть база приложения → DWH или DWH → какая-то система (reverse ETL). Посередине есть оркестратор, который отправляет запрос в источник, получает результат и отправляет его в назначение.
Если вы используете встроенные операторы Airflow, то это будут две разные задачи: extract и insert. Задачи выполняются последовательно, и результат первой часто полностью материализуется в памяти воркера. Вот тут и кроется крайне невыгодное использование ресурсов: если у вас много DAG'ов или объём данных достаточно большой, Airflow начинает активно потреблять память воркеров.
В итоге вы либо
🔸 платите больше за ресурсы,
🔸 играете с расписанием, чтобы в один момент времени было меньше данных в памяти и воркер не падал,
🔸 режете объём данных.
Все варианты плохие хотя бы потому, что ресурсы воркера вообще начинают участвовать в уравнении. Зависимость от памяти становится ограничивающим фактором.
Эту проблему можно решить, если сделать так, чтобы оркестратор оставался оркестратором, а не буфером между источником и назначением.
Суть решения — организовать процесс как микробатч-стриминг. Тогда в памяти воркера в любой момент времени будет только один микробатч (например, 1000 строк).
Достичь этого можно с помощью специального Python-объекта — Generator.
Для тех, кто хорошо разбирается в программировании, я нового ничего не открою.
Такой подход даёт две серьёзные возможности:
1️⃣ Можно делать трансфер практически любого объёма без роста потребления памяти воркера.
2️⃣ Можно запускать больше процессов трансфера параллельно, потому что они почти не конкурируют за память (память ограничена размером микробатча).
Дальше — техническая часть.
Многие встроенные операторы и хуки в Airflow по умолчанию материализуют результат запроса в памяти воркера. Поэтому потребуется написать немного кода.
Я опишу вариант зрелой, универсальной реализации — с возможностью расширения и переиспользования. Для разовой задачи решение может быть проще.
Итак, что нам нужно.
Во-первых, убрать разрыв на две задачи (извлечение/вставка) и обеспечить одну — трансфер. Это позволит контролировать использование памяти внутри одного процесса на одном воркере.
Во-вторых, нужен адаптер для источника. Его задача — получить запрос и вернуть не данные, а специальный Python-объект — Generator.
Generator не содержит сами данные. Он лишь определяет, как их получать. При итерации он каждый раз возвращает очередную порцию данных.
Большинство баз поддерживают серверные курсоры или потоковую выдачу результатов. Адаптер делает запрос к источнику, но не забирает всё сразу — он получает данные частями.
Например, SQLAlchemy умеет работать в streaming-режиме через соответствующие параметры соединения.
Далее этот Generator передаётся адаптеру назначения. Он итерируется по нему и за раз обрабатывает только небольшой батч данных, освобождая память после каждой обработки.
В любой момент времени в памяти воркера находится только микробатч. 🙌
Для непрограммиста это может выглядеть необычно: фактическое извлечение данных происходит в момент вставки, а до этого между функциями передаётся лишь абстрактный объект, который сам по себе почти ничего не весит.🤯
Примерно год назад мы реализовали такой подход у себя.🧐
С тех пор ошибки DAG'ов из-за нехватки памяти на воркерах перестали быть проблемой.
Сейчас у нас есть универсальный оператор и набор адаптеров для баз и сервисов, реализующих потоковое поведение. Адаптеры инкапсулируют логику стриминга за простыми интерфейсами extract/insert, поэтому оркестратор остаётся только управляющим слоем.
Это уже архитектурный подход — разделение orchestration и data transfer.
Для старта не обязательно строить такую обвязку. Того же поведения можно добиться и обычной функцией внутри одного таска.
Рассмотрим простой ETL-процесс, реализованный в Airflow.
Есть источник и назначение. На практике это может быть база приложения → DWH или DWH → какая-то система (reverse ETL). Посередине есть оркестратор, который отправляет запрос в источник, получает результат и отправляет его в назначение.
Если вы используете встроенные операторы Airflow, то это будут две разные задачи: extract и insert. Задачи выполняются последовательно, и результат первой часто полностью материализуется в памяти воркера. Вот тут и кроется крайне невыгодное использование ресурсов: если у вас много DAG'ов или объём данных достаточно большой, Airflow начинает активно потреблять память воркеров.
В итоге вы либо
Все варианты плохие хотя бы потому, что ресурсы воркера вообще начинают участвовать в уравнении. Зависимость от памяти становится ограничивающим фактором.
Эту проблему можно решить, если сделать так, чтобы оркестратор оставался оркестратором, а не буфером между источником и назначением.
Суть решения — организовать процесс как микробатч-стриминг. Тогда в памяти воркера в любой момент времени будет только один микробатч (например, 1000 строк).
Достичь этого можно с помощью специального Python-объекта — Generator.
Для тех, кто хорошо разбирается в программировании, я нового ничего не открою.
Такой подход даёт две серьёзные возможности:
Дальше — техническая часть.
Многие встроенные операторы и хуки в Airflow по умолчанию материализуют результат запроса в памяти воркера. Поэтому потребуется написать немного кода.
Я опишу вариант зрелой, универсальной реализации — с возможностью расширения и переиспользования. Для разовой задачи решение может быть проще.
Итак, что нам нужно.
Во-первых, убрать разрыв на две задачи (извлечение/вставка) и обеспечить одну — трансфер. Это позволит контролировать использование памяти внутри одного процесса на одном воркере.
Во-вторых, нужен адаптер для источника. Его задача — получить запрос и вернуть не данные, а специальный Python-объект — Generator.
Generator не содержит сами данные. Он лишь определяет, как их получать. При итерации он каждый раз возвращает очередную порцию данных.
Большинство баз поддерживают серверные курсоры или потоковую выдачу результатов. Адаптер делает запрос к источнику, но не забирает всё сразу — он получает данные частями.
Например, SQLAlchemy умеет работать в streaming-режиме через соответствующие параметры соединения.
Далее этот Generator передаётся адаптеру назначения. Он итерируется по нему и за раз обрабатывает только небольшой батч данных, освобождая память после каждой обработки.
В любой момент времени в памяти воркера находится только микробатч. 🙌
Для непрограммиста это может выглядеть необычно: фактическое извлечение данных происходит в момент вставки, а до этого между функциями передаётся лишь абстрактный объект, который сам по себе почти ничего не весит.🤯
Примерно год назад мы реализовали такой подход у себя.🧐
С тех пор ошибки DAG'ов из-за нехватки памяти на воркерах перестали быть проблемой.
Сейчас у нас есть универсальный оператор и набор адаптеров для баз и сервисов, реализующих потоковое поведение. Адаптеры инкапсулируют логику стриминга за простыми интерфейсами extract/insert, поэтому оркестратор остаётся только управляющим слоем.
Это уже архитектурный подход — разделение orchestration и data transfer.
Для старта не обязательно строить такую обвязку. Того же поведения можно добиться и обычной функцией внутри одного таска.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🔥7❤2
Попробовал code agent
На неделе впервые попробовал code agent. Пока что не multi agent со множеством ролей (к этому ещё приду), а просто один агент, который выполняет задачу полностью, даже вместе с деплоем.
Я, конечно, много видел упоминаний и описаний того, как оно работает, но пока сам не попробуешь на своей реальной задаче, всё равно непонятно. Тут как раз появилась простая задачка – идеальная, чтобы начать работать с агентом. И результат превзошёл мои ожидания!
Мне нужно было сделать простой прокси-микросервис, который состоит из AWS API Gateway и одной AWS Lambda. Всё, что делает сервис, — это принимает POST-запрос, проверяет аутентификацию и передаёт его дальше на внутренний API endpoint. Мне нужно было, чтобы агент написал terraform, саму лямбду, тесты. Про то, что он может и задеплоить, я даже и не думал, когда начал.
В пустом репозитории я создал readme файл, описал там задачу сервиса примерно так же, как описал выше. Открыл чат с агентом и попросил его создать сервис. И он реально начал создавать файлы! Не примеры кода, а зависимые друг от друга файлы, которые вместе представляют собой работающий сервис. Я, в общем-то, так и хотел, но увидеть на практике - другое дело. Он уже был не чатом, не ассистентом, а разработчиком.
Затем мне было интересно увидеть, как он будет взаимодействовать со внешними элементами. Я просил его:
▫️ задеплоить сервис (stage).
▫️ сделать git операции: commit и push в удаленный репозиторий.
▫️ провести интеграционный тест: запустить код лямбды локально, отправить реальный запрос на реальный endpoint и оценить результат.
Он выполнял команды terraform, aws cli, git, запускал .py файлы, получал ответы, адаптировался, пробовал снова и... успешно справлялся.
‼️ Среди всей этой магии был один важный момент. Он совершил глупую, но серьезную ошибку: в одной из итераций он удалил проверку токена авторизации, оставив только проверку наличия заголовка. Ошибка опасная. Я заметил это, просматривая код наискосок (я не читал каждую строку), попросил его поправить, и он конечно признал ошибку и поправил. Да, наверное можно в конце попросить его же самого сделать ревью и, возможно, он такое заметит сам (в тот момент я не подумал это попробовать).
Главное – остаётся риск ошибки, если "оставить его одного". При этом не стоит проваливаться слишком глубоко в ревью и переписывать всё доводя до идеала. Без перфекционизма. Иначе вместо помощника, который даёт результат, вы сами себе создадите лишнюю работу.
©️ В итоге я остался под впечатлением.
(Даже жене вечером рассказал, хоть она и не поняла половину терминов😁).
Несмотря на риск ошибки и необходимость ревью, ai агент может существенно ускорить доставку результата, увеличить личную продуктивность. Дополнения, которые я его просил сделать, были, по существу, уточнениями изначальных требований, то есть если достаточно хорошо описать всё вначале, то он всё сделает хорошо сразу.
Я точно буду использовать его больше. Следующий интересный шаг – пробовать подключать его напрямую к базе данных.
Дисклеймер: я понимаю что люди давным давно делают вещи гораздо сложнее, но для меня, да и думаю для многих из вас, это все еще новейшие технологии, которые мы не применяем каждый день.
Кстати, я использовал бесплатный vs code и gpt codex, включённый в gpt plus подписку.
.
На неделе впервые попробовал code agent. Пока что не multi agent со множеством ролей (к этому ещё приду), а просто один агент, который выполняет задачу полностью, даже вместе с деплоем.
Я, конечно, много видел упоминаний и описаний того, как оно работает, но пока сам не попробуешь на своей реальной задаче, всё равно непонятно. Тут как раз появилась простая задачка – идеальная, чтобы начать работать с агентом. И результат превзошёл мои ожидания!
Мне нужно было сделать простой прокси-микросервис, который состоит из AWS API Gateway и одной AWS Lambda. Всё, что делает сервис, — это принимает POST-запрос, проверяет аутентификацию и передаёт его дальше на внутренний API endpoint. Мне нужно было, чтобы агент написал terraform, саму лямбду, тесты. Про то, что он может и задеплоить, я даже и не думал, когда начал.
В пустом репозитории я создал readme файл, описал там задачу сервиса примерно так же, как описал выше. Открыл чат с агентом и попросил его создать сервис. И он реально начал создавать файлы! Не примеры кода, а зависимые друг от друга файлы, которые вместе представляют собой работающий сервис. Я, в общем-то, так и хотел, но увидеть на практике - другое дело. Он уже был не чатом, не ассистентом, а разработчиком.
Затем мне было интересно увидеть, как он будет взаимодействовать со внешними элементами. Я просил его:
Он выполнял команды terraform, aws cli, git, запускал .py файлы, получал ответы, адаптировался, пробовал снова и... успешно справлялся.
Главное – остаётся риск ошибки, если "оставить его одного". При этом не стоит проваливаться слишком глубоко в ревью и переписывать всё доводя до идеала. Без перфекционизма. Иначе вместо помощника, который даёт результат, вы сами себе создадите лишнюю работу.
Несмотря на риск ошибки и необходимость ревью, ai агент может существенно ускорить доставку результата, увеличить личную продуктивность. Дополнения, которые я его просил сделать, были, по существу, уточнениями изначальных требований, то есть если достаточно хорошо описать всё вначале, то он всё сделает хорошо сразу.
Я точно буду использовать его больше. Следующий интересный шаг – пробовать подключать его напрямую к базе данных.
Дисклеймер: я понимаю что люди давным давно делают вещи гораздо сложнее, но для меня, да и думаю для многих из вас, это все еще новейшие технологии, которые мы не применяем каждый день.
Кстати, я использовал бесплатный vs code и gpt codex, включённый в gpt plus подписку.
.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8👍4❤2😁1
Нужно ли хранить историю на уровне моделей?
Часто это воспринимается как дефолт:
делаем модель → сразу закладываем версионирование, SCD, valid_from / valid_to.
Но вопрос — действительно ли это всегда нужно?
История, конечно, важна.
Но важно разделить уровни.
👍 На уровне ingestion layer — да.
Сырые данные, события, изменения в источнике — это базовый слой, который должен сохранять полную историю и не зависеть от дальнейшей логики.
🤔 На уровне model layer всё менее однозначно.
Изменения там обычно происходят по двум причинам:
🔹 меняются данные в источнике
🔹 меняется логика трансформации
Но хранить историю на model layer уровне имеет смысл только тогда, когда у этого есть бизнес-ценность, то есть когда история является частью публичной модели данных. Например, история состояния заказа.
Во всех остальных случаях это скорее техническая страховка.
Частый аргумент — observability:
нужно иметь возможность разобраться, почему раньше считалось иначе.
Но для этого не обязательно хранить историю в моделях. Observability можно обеспечить имея:
🔵 полная история на ingestion layer
🔵 воспроизводимые (детерминированные) трансформации
Что значит детерминированность?
В общем смысле это "один и тот же input всегда ведёт к одному и тому же output". В случае sql трансформаций input это и сам запрос и данные, к которым он обращается.
Если:
🔹 данные на ingestion layer неизменяемы и имеют временную ось (meta timeline)
🔹 функции/запросы имеют свою историю изменений (хотя бы git)
то в любой момент времени можно восстановить нужный input и получить тот же самый output.
Это и есть детерминированный пайплайн.
Тогда:
история в ingestion layer + воспроизводимая логика = возможность восстановить результат на любой момент 🙌
©️ Можно не хранить все промежуточные состояния моделей, но при этом уметь получить любое из них при необходимости.
И тогда вопрос сводится к простому:
история в model layer — это осознанное бизнес-требование
или компенсация недостаточной воспроизводимости пайплайна?
Часто это воспринимается как дефолт:
делаем модель → сразу закладываем версионирование, SCD, valid_from / valid_to.
Но вопрос — действительно ли это всегда нужно?
История, конечно, важна.
Но важно разделить уровни.
👍 На уровне ingestion layer — да.
Сырые данные, события, изменения в источнике — это базовый слой, который должен сохранять полную историю и не зависеть от дальнейшей логики.
🤔 На уровне model layer всё менее однозначно.
Изменения там обычно происходят по двум причинам:
Но хранить историю на model layer уровне имеет смысл только тогда, когда у этого есть бизнес-ценность, то есть когда история является частью публичной модели данных. Например, история состояния заказа.
Во всех остальных случаях это скорее техническая страховка.
Частый аргумент — observability:
нужно иметь возможность разобраться, почему раньше считалось иначе.
Но для этого не обязательно хранить историю в моделях. Observability можно обеспечить имея:
Что значит детерминированность?
В общем смысле это "один и тот же input всегда ведёт к одному и тому же output". В случае sql трансформаций input это и сам запрос и данные, к которым он обращается.
Если:
то в любой момент времени можно восстановить нужный input и получить тот же самый output.
Это и есть детерминированный пайплайн.
Тогда:
история в ingestion layer + воспроизводимая логика = возможность восстановить результат на любой момент 🙌
И тогда вопрос сводится к простому:
история в model layer — это осознанное бизнес-требование
или компенсация недостаточной воспроизводимости пайплайна?
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤2
Искажение модели
Организационная структура — один из частых источников искажения модели данных.
❗️ Элементы оргструктуры начинают определять сущности, метрики, сегментации.
❗️ Бизнес-определения начинают разъезжаться —
не потому что меняется бизнес,
а потому что разные отделы «так видят».
❗️ Границы ответственности превращаются в границы данных.
И со временем это начинает выглядеть как естественная часть модели.
Например.
Одна команда назовёт запросы клиентов case, другая — lead.
Какая разница с точки зрения бизнеса, если и то и другое — запрос клиента?
Это искажение.
Или маркетинг разделён на направления:
реклама, партнёры, органика, email.
Это нормальное управленческое решение —
разделить ответственность и сфокусировать команды.
Но дальше каждое направление начинает выстраивать свою картину:
свои метрики, свои воронки, свои правила атрибуции.
И постепенно это выглядит так,
будто это разные части бизнеса.
Хотя это один поток:
трафик → клиенты → выручка.
Границы, введённые для удобства управления,
начинают восприниматься как ограничения самой модели.
Искажение.
Со временем это закрепляется в данных, отчётах и процессах.
И начинает влиять на решения.
Что с этим делать
При моделировании важно абстрагироваться от команд, отделов и ролей.
Полезные вопросы:
🔵 Эта сущность будет существовать, если завтра отдел расформируют?
🔵 Как изменится сегментация, если завтра два отдела объединят в один?
Организационная структура тоже может быть частью данных — но явно.
Она не должна тихо влиять на определения бизнес-сущностей.
©️ В корректной модели оргструктура — это отдельный слой, который дополняет бизнес-объекты, а не подменяет их.
Иногда мы принимаем за бизнес-модель то, что ей не является.
Организационная структура — один из частых источников искажения модели данных.
не потому что меняется бизнес,
а потому что разные отделы «так видят».
И со временем это начинает выглядеть как естественная часть модели.
Например.
Одна команда назовёт запросы клиентов case, другая — lead.
Какая разница с точки зрения бизнеса, если и то и другое — запрос клиента?
Это искажение.
Или маркетинг разделён на направления:
реклама, партнёры, органика, email.
Это нормальное управленческое решение —
разделить ответственность и сфокусировать команды.
Но дальше каждое направление начинает выстраивать свою картину:
свои метрики, свои воронки, свои правила атрибуции.
И постепенно это выглядит так,
будто это разные части бизнеса.
Хотя это один поток:
трафик → клиенты → выручка.
Границы, введённые для удобства управления,
начинают восприниматься как ограничения самой модели.
Искажение.
Со временем это закрепляется в данных, отчётах и процессах.
И начинает влиять на решения.
Что с этим делать
При моделировании важно абстрагироваться от команд, отделов и ролей.
Полезные вопросы:
Организационная структура тоже может быть частью данных — но явно.
Она не должна тихо влиять на определения бизнес-сущностей.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4❤🔥1🔥1💯1
Полезный ресурс про то, что происходит в мире ai. Не только про код, а вообще. Вот ссылка на сайт, но у них ещё есть newsletter. Не реклама. У ребят 700 тысяч подписчиков и им реклама у меня точно не нужна 😂
Я читаю у них далеко не все, но чтобы оставаться в теме, по-моему, посматривать стоит.
Например, в последнем посте есть ссылка на репозиторий со скилами. Выглядит интересно 👍 я вот еще в использование скилов не погружался. Завтра попробую.
Я читаю у них далеко не все, но чтобы оставаться в теме, по-моему, посматривать стоит.
Например, в последнем посте есть ссылка на репозиторий со скилами. Выглядит интересно 👍 я вот еще в использование скилов не погружался. Завтра попробую.
The Neuron
😺 You're either Jeremy or you're cut
PLUS: Meta axed 10% to feed AI. One analyst spent $6K/day on Claude and replaced a 100-person team.
🔥4
Нужно запретить сортировку в дата-инжиниринге на законодательном уровне.
* так пошутил инженер из Databricks, объясняя работу Spark. Он показал, что сортировка увеличивает потребление ресурсов и время выполнения задачи в несколько раз. Мне понравилась эта цитата, потому что я пришел ровно к тому же выводу работая с Clickhouse. В итоге пришлось изменить свои привычки, наработанные в строковых базах.
©️ Большая часть сортировок в запросах существует не потому, что она нужна задаче. Она существует потому, что мы привыкли писать SQL определённым образом. Проблема справедлива для разных систем, но особенно хорошо видна на примере Clickhouse.
▫️ Привычка первая — одна строка на ключ.
Если вы много работали с PostgreSQL, рука сама тянется к distinct on или похожим конструкциям. И там это работает хорошо. ClickHouse тоже поддерживает и distinct on и limit 1 by, но они требуют сортировку. Забавно, что AI-ассистенты тоже любят такие конструкции и регулярно предлагают их как решение по умолчанию.
Я тоже использовал такие конструкции, пока не начал регулярно сталкиваться с ростом потребления памяти и периодическими падениями запросов.
В итоге везде заменил их на GROUP BY с агрегатными функциями вроде argMax() и argMin(). Агрегация - вообще любимая операция Clickhouse.
▫️ Привычка вторая — посмотреть последние данные через
select * from table order by timestamp (да, некоторые даже не пишут limit полагаясь на IDE, которая получит ограниченное количество строк).
На практике человеку обычно нужно не 100 самых последних строк во всей таблице, а просто посмотреть свежие данные. То есть точная сортировка не является частью задачи, а скорее привычкой. Фильтр по последнему часу плюс limit решают это за доли секунды без сортировки вообще. Пока писал этот пост, прогнал пару запросов на одной из наших таблиц в Clickhouse на 300М записей:
✔️ фильтр + лимит - 800 мс
❌ сортировка + лимит - 9 минут!
Теперь я стал смотреть критически на сортировку везде. И нашёл order by в пайплайнах, где он просто стоит как артефакт после чьей-то работы. Никто не убрал, а база честно сортирует данные при каждом запуске. И если для строковой базы это терпимо, то для колончатой или для распределенных вычислений (типа Spark) - это выстрел в ногу.
©️ Перед тем как написать ORDER BY — убедитесь, что не нарушаете закон. ☝️😁
* так пошутил инженер из Databricks, объясняя работу Spark. Он показал, что сортировка увеличивает потребление ресурсов и время выполнения задачи в несколько раз. Мне понравилась эта цитата, потому что я пришел ровно к тому же выводу работая с Clickhouse. В итоге пришлось изменить свои привычки, наработанные в строковых базах.
Если вы много работали с PostgreSQL, рука сама тянется к distinct on или похожим конструкциям. И там это работает хорошо. ClickHouse тоже поддерживает и distinct on и limit 1 by, но они требуют сортировку. Забавно, что AI-ассистенты тоже любят такие конструкции и регулярно предлагают их как решение по умолчанию.
Я тоже использовал такие конструкции, пока не начал регулярно сталкиваться с ростом потребления памяти и периодическими падениями запросов.
В итоге везде заменил их на GROUP BY с агрегатными функциями вроде argMax() и argMin(). Агрегация - вообще любимая операция Clickhouse.
select * from table order by timestamp (да, некоторые даже не пишут limit полагаясь на IDE, которая получит ограниченное количество строк).
На практике человеку обычно нужно не 100 самых последних строк во всей таблице, а просто посмотреть свежие данные. То есть точная сортировка не является частью задачи, а скорее привычкой. Фильтр по последнему часу плюс limit решают это за доли секунды без сортировки вообще. Пока писал этот пост, прогнал пару запросов на одной из наших таблиц в Clickhouse на 300М записей:
Теперь я стал смотреть критически на сортировку везде. И нашёл order by в пайплайнах, где он просто стоит как артефакт после чьей-то работы. Никто не убрал, а база честно сортирует данные при каждом запуске. И если для строковой базы это терпимо, то для колончатой или для распределенных вычислений (типа Spark) - это выстрел в ногу.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14❤2🔥2
Асимметрия обратной связи
На днях поймал себя на мысли.
Иногда к концу дня чувствуется внутреннее напряжение. Стал разбираться, откуда оно берется, и пришел к такой мысли.
Мне кажется, у инженеров данных есть особенность обратной связи, которая создает психологическую нагрузку.
Обычно у продукта есть понятная обратная связь. Можно оценить, насколько часто он приносит пользователям ценность.
У разработчика сайта есть понятные метрики. Он знает, сколько пользователей пришло, сколько оформили заказ, сколько людей дошли до оплаты.
У разработчика бэкенда тоже есть обратная связь. Сколько запросов обработал сервис, сколько ошибок произошло, какой процент успешных ответов.
А когда результат твоей работы — данные, всё становится иначе.
Мы предоставляем данные как продукт. Дальше пользователь сам формулирует вопрос, анализирует информацию и принимает решение.
Но мы почти никогда не видим результат этой цепочки.
Мы не знаем,
– сколько вопросов сегодня было решено благодаря данным.
– сколько бизнес-проблем удалось обнаружить.
– сколько решений приняли руководители.
– сколько возможностей для бизнеса нашли.
Зато есть другая сторона.
Если в данных обнаружили проблему, если не сошлась метрика, если качество данных оказалось недостаточным — об этом обязательно придут рассказать. Иногда сразу о нескольких проблемах.
И это правильно. Ошибки должны быстро доходить до тех, кто отвечает за качество данных. И тот факт, что пользователи их находят, говорит о том, что данными пользуются.
Но почти никто не приходит сказать:
«Сегодня снова работал с отчетами. Получил ответы на все вопросы. Всё было как нужно.»
Получается интересная особенность профессии.
До нас почти всегда доходят проблемы. А объем пользы, который ежедневно создают данные, остается скрытым.
Возможно, именно асимметрия обратной связи и создает психологическую нагрузку.
На днях поймал себя на мысли.
Иногда к концу дня чувствуется внутреннее напряжение. Стал разбираться, откуда оно берется, и пришел к такой мысли.
Мне кажется, у инженеров данных есть особенность обратной связи, которая создает психологическую нагрузку.
Обычно у продукта есть понятная обратная связь. Можно оценить, насколько часто он приносит пользователям ценность.
У разработчика сайта есть понятные метрики. Он знает, сколько пользователей пришло, сколько оформили заказ, сколько людей дошли до оплаты.
У разработчика бэкенда тоже есть обратная связь. Сколько запросов обработал сервис, сколько ошибок произошло, какой процент успешных ответов.
А когда результат твоей работы — данные, всё становится иначе.
Мы предоставляем данные как продукт. Дальше пользователь сам формулирует вопрос, анализирует информацию и принимает решение.
Но мы почти никогда не видим результат этой цепочки.
Мы не знаем,
– сколько вопросов сегодня было решено благодаря данным.
– сколько бизнес-проблем удалось обнаружить.
– сколько решений приняли руководители.
– сколько возможностей для бизнеса нашли.
Зато есть другая сторона.
Если в данных обнаружили проблему, если не сошлась метрика, если качество данных оказалось недостаточным — об этом обязательно придут рассказать. Иногда сразу о нескольких проблемах.
И это правильно. Ошибки должны быстро доходить до тех, кто отвечает за качество данных. И тот факт, что пользователи их находят, говорит о том, что данными пользуются.
Но почти никто не приходит сказать:
«Сегодня снова работал с отчетами. Получил ответы на все вопросы. Всё было как нужно.»
Получается интересная особенность профессии.
До нас почти всегда доходят проблемы. А объем пользы, который ежедневно создают данные, остается скрытым.
Возможно, именно асимметрия обратной связи и создает психологическую нагрузку.
💯4👍3🤔3😁1🤝1
Языки программирования были нужны только человеку?
Мне пришла одна мысль и я попытался ее развить и порассуждать.
Что, если стек абстракций — от языков программирования до фреймворков — появился прежде всего как интерфейс для человека? Тогда что произойдёт с ним, если новым пользователем вычислительной техники становится AI?
Если оглянуться назад, развитие информационных технологий почти всегда шло через добавление слоёв абстракции:
железо → операционные системы → низкоуровневые языки → высокоуровневые языки → фреймворки → no code / serverless
Каждый новый слой решал одну задачу — упростить взаимодействие для человека: скрыть сложность нижнего уровня, снизить порог входа, сделать разработку более предсказуемой.
Если посмотреть на эту историю под таким углом, то получается, что этот стек создавался не для компьютеров, а для людей.
Стек абстракций, по всей видимости, достиг своего пика с точки зрения удобства для человека. Даже без AI сегодня легко запустить сайт, сервис или приложение. Но у этого есть обратная сторона. Каждый слой не только упрощает, но и ограничивает.
По сути, языки программирования — это интерфейс. Не для машины, а для человека. А теперь появляется новый «пользователь» — AI. И у него нет наших ограничений: ему несложно держать в голове детали, он не устаёт от низкоуровневой работы, ему не нужно упрощать задачу. Значит, абстракции, созданные для человека, ему не нужны?
Можно представить сценарий, где AI постепенно снимает уровни. Сначала работает через привычные нам языки, потом опускается ниже — туда, где меньше ограничений и больше контроля. Он может работать с промежуточными представлениями, машинным кодом или другими внутренними формами.
Например, подумаем о компилируемых языках. Они же для человека: человек пишет код, а компилятор переводит его из формата, удобного человеку, в формат, удобный машине. Если человека в процессе нет, всё может быть наоборот. AI может работать с представлением, удобным машине, а если человеку понадобится посмотреть на результат — «компилировать» его обратно в естественный язык. Получается своеобразная обратная компиляция: не человек пишет код и переводит его для машины, а машина формирует решение в удобном для себя представлении и при необходимости переводит его обратно для человека
Другой пример. Meta выпустила LLM Compiler — модель, обученную на LLVM IR и ассемблерном коде для задач оптимизации. LLVM IR — это промежуточное представление кода, расположенное ниже привычных высокоуровневых языков программирования.
То есть инженеры в этом случае уже пришли к тому, что "наши" языки программирования только помешают AI.
Там, где нет человека, не нужны человеческие интерфейсы. Если эта логика верна, под вопросом оказываются не только языки программирования, но и многое другое.
Однако, есть и другой слой, который пока что все таки нужен.
До сих пор речь шла об абстракциях, которые помогают человеку взаимодействовать с вычислительной системой.
Но существует и другой класс абстракций. При взаимодействии независимых систем всё равно нужны договорённости — общие протоколы, стандарты и форматы обмена. Здесь проходит фундаментальное различие между двумя типами абстракций:
1) появились как компенсация человеческих ограничений. Они помогают человеку справляться со сложностью вычислительных систем.
2) появились как механизм взаимодействия между независимыми системами. Они помогают системам договариваться друг с другом.
Первые могут оказаться временными. Вторые, вероятно, останутся с нами гораздо дольше.
Если эта гипотеза верна, то человек и AI движутся в противоположных направлениях: AI постепенно спускается вниз по стеку абстракций, тогда как человек поднимается вверх. Мы всё реже описываем решение через инструкции и всё чаще через намерение. Языки программирования могут исчезнуть не потому, что станут не нужны компьютерам, а потому, что однажды станут не нужны людям.
Мы привыкли воспринимать стек абстракций как естественную эволюцию вычислительной техники. Каждый новый слой казался шагом вперёд по сравнению с предыдущим. Возможно, это была не столько эволюция компьютеров, сколько эволюция интерфейсов для человека.
Мне пришла одна мысль и я попытался ее развить и порассуждать.
Что, если стек абстракций — от языков программирования до фреймворков — появился прежде всего как интерфейс для человека? Тогда что произойдёт с ним, если новым пользователем вычислительной техники становится AI?
Если оглянуться назад, развитие информационных технологий почти всегда шло через добавление слоёв абстракции:
железо → операционные системы → низкоуровневые языки → высокоуровневые языки → фреймворки → no code / serverless
Каждый новый слой решал одну задачу — упростить взаимодействие для человека: скрыть сложность нижнего уровня, снизить порог входа, сделать разработку более предсказуемой.
Если посмотреть на эту историю под таким углом, то получается, что этот стек создавался не для компьютеров, а для людей.
Стек абстракций, по всей видимости, достиг своего пика с точки зрения удобства для человека. Даже без AI сегодня легко запустить сайт, сервис или приложение. Но у этого есть обратная сторона. Каждый слой не только упрощает, но и ограничивает.
По сути, языки программирования — это интерфейс. Не для машины, а для человека. А теперь появляется новый «пользователь» — AI. И у него нет наших ограничений: ему несложно держать в голове детали, он не устаёт от низкоуровневой работы, ему не нужно упрощать задачу. Значит, абстракции, созданные для человека, ему не нужны?
Можно представить сценарий, где AI постепенно снимает уровни. Сначала работает через привычные нам языки, потом опускается ниже — туда, где меньше ограничений и больше контроля. Он может работать с промежуточными представлениями, машинным кодом или другими внутренними формами.
Например, подумаем о компилируемых языках. Они же для человека: человек пишет код, а компилятор переводит его из формата, удобного человеку, в формат, удобный машине. Если человека в процессе нет, всё может быть наоборот. AI может работать с представлением, удобным машине, а если человеку понадобится посмотреть на результат — «компилировать» его обратно в естественный язык. Получается своеобразная обратная компиляция: не человек пишет код и переводит его для машины, а машина формирует решение в удобном для себя представлении и при необходимости переводит его обратно для человека
Другой пример. Meta выпустила LLM Compiler — модель, обученную на LLVM IR и ассемблерном коде для задач оптимизации. LLVM IR — это промежуточное представление кода, расположенное ниже привычных высокоуровневых языков программирования.
То есть инженеры в этом случае уже пришли к тому, что "наши" языки программирования только помешают AI.
Там, где нет человека, не нужны человеческие интерфейсы. Если эта логика верна, под вопросом оказываются не только языки программирования, но и многое другое.
Однако, есть и другой слой, который пока что все таки нужен.
До сих пор речь шла об абстракциях, которые помогают человеку взаимодействовать с вычислительной системой.
Но существует и другой класс абстракций. При взаимодействии независимых систем всё равно нужны договорённости — общие протоколы, стандарты и форматы обмена. Здесь проходит фундаментальное различие между двумя типами абстракций:
1) появились как компенсация человеческих ограничений. Они помогают человеку справляться со сложностью вычислительных систем.
2) появились как механизм взаимодействия между независимыми системами. Они помогают системам договариваться друг с другом.
Первые могут оказаться временными. Вторые, вероятно, останутся с нами гораздо дольше.
Если эта гипотеза верна, то человек и AI движутся в противоположных направлениях: AI постепенно спускается вниз по стеку абстракций, тогда как человек поднимается вверх. Мы всё реже описываем решение через инструкции и всё чаще через намерение. Языки программирования могут исчезнуть не потому, что станут не нужны компьютерам, а потому, что однажды станут не нужны людям.
Мы привыкли воспринимать стек абстракций как естественную эволюцию вычислительной техники. Каждый новый слой казался шагом вперёд по сравнению с предыдущим. Возможно, это была не столько эволюция компьютеров, сколько эволюция интерфейсов для человека.
❤8💯2
Software ручной работы
Кстати в гипотезу из предыдущего поста укладывается аналогия с ремеслами, которые сейчас стали историей.
Например, кузнечное дело. За тысячи лет кузнецы создали множество хитроумных приспособлений, приёмов как ковать металл и получать из него изделия. Были специальные инструменты, которые сейчас можно увидеть в музеях. Их ремесло казалось вершиной развития именно в том виде.
Но когда наука и инженерия шагнули вперед, новые технологии позволили создать станки. Но важный момент. Станки не копируют действия кузнеца, они воспроизводят не процесс, а результат, избавляясь от ограничений человека. Вместо двух часов ударов кувалдой — один удар прессом в несколько тонн. А где-то металл вообще перестал быть нужен.
Мы, как кузнецы, создали много удобных инструментов и приёмов, но новые технологии будут создавать результат, а не копировать наши действия. Так что все наши фреймворки, высокоуровневые языки, среды разработки, клиенты баз данных, однажды могут оказаться в музее на полке рядом с кузнечным молотом.
Хотя у этой же аналогии есть интересное следствие. Кузнецы ведь не исчезли. Они просто перестали быть массовым способом производства. Возможно, останутся и разработчики эксклюзивного software ручной работы.
Кстати в гипотезу из предыдущего поста укладывается аналогия с ремеслами, которые сейчас стали историей.
Например, кузнечное дело. За тысячи лет кузнецы создали множество хитроумных приспособлений, приёмов как ковать металл и получать из него изделия. Были специальные инструменты, которые сейчас можно увидеть в музеях. Их ремесло казалось вершиной развития именно в том виде.
Но когда наука и инженерия шагнули вперед, новые технологии позволили создать станки. Но важный момент. Станки не копируют действия кузнеца, они воспроизводят не процесс, а результат, избавляясь от ограничений человека. Вместо двух часов ударов кувалдой — один удар прессом в несколько тонн. А где-то металл вообще перестал быть нужен.
Мы, как кузнецы, создали много удобных инструментов и приёмов, но новые технологии будут создавать результат, а не копировать наши действия. Так что все наши фреймворки, высокоуровневые языки, среды разработки, клиенты баз данных, однажды могут оказаться в музее на полке рядом с кузнечным молотом.
Хотя у этой же аналогии есть интересное следствие. Кузнецы ведь не исчезли. Они просто перестали быть массовым способом производства. Возможно, останутся и разработчики эксклюзивного software ручной работы.
👍5
Модель космического масштаба
История о том, как строгая работа с семантической моделью исключила Плутон из списка планет.
В 2005 был открыт объект Эрида сопоставимый с Плутоном по размеру и массе. Тогда стало понятно, что считать Плутон планетой, а Эриду нет - разрушение консистентности модели. Неточное определение того, что такое планета, оставляет пространство для интерпретации, а значит, для ошибки и искажения.
Возникла неопределённость, которую решили на уровне семантической модели — изменили определение планеты, приняли единое формальное определение. Однако Плутон перестал соответствовать определению и перестал быть планетой. Официальное решение IAU 2006 года: Definition of a Planet
Решение серьёзное и влекущее за собой множество последствий. Вдруг множество книг, научных статей, учебников и тд стали устаревшими. Презентации, отчёты, дашборды стали показывать количество планет не 9, а 8. Никто на научных конференциях больше не говорит, что планет 9, объясняя это тем, что "мы так привыкли" и что "всегда считали так" и что "метрики поедут". Никто не пишет в научной статье, что планет 9, потому что "руководитель отдела продаж планет просил оставить 9".
На уровне доменной области было принято решение, которое касается всех оперирующих в данном контексте без исключений. Если у кого-то есть возражения, то он должен их решать на уровне доменной области, а не создавать локальную модель.
Изменение определения коснулось множества downstream процессов, но это не аргумент против уточнения модели.
По-моему, эта история - хороший пример управления семантической моделью на доменном уровне.
Select count(*)
From solar_system.planets
-- 2005: 9
-- 2006: 8
История о том, как строгая работа с семантической моделью исключила Плутон из списка планет.
В 2005 был открыт объект Эрида сопоставимый с Плутоном по размеру и массе. Тогда стало понятно, что считать Плутон планетой, а Эриду нет - разрушение консистентности модели. Неточное определение того, что такое планета, оставляет пространство для интерпретации, а значит, для ошибки и искажения.
Возникла неопределённость, которую решили на уровне семантической модели — изменили определение планеты, приняли единое формальное определение. Однако Плутон перестал соответствовать определению и перестал быть планетой. Официальное решение IAU 2006 года: Definition of a Planet
Решение серьёзное и влекущее за собой множество последствий. Вдруг множество книг, научных статей, учебников и тд стали устаревшими. Презентации, отчёты, дашборды стали показывать количество планет не 9, а 8. Никто на научных конференциях больше не говорит, что планет 9, объясняя это тем, что "мы так привыкли" и что "всегда считали так" и что "метрики поедут". Никто не пишет в научной статье, что планет 9, потому что "руководитель отдела продаж планет просил оставить 9".
На уровне доменной области было принято решение, которое касается всех оперирующих в данном контексте без исключений. Если у кого-то есть возражения, то он должен их решать на уровне доменной области, а не создавать локальную модель.
Изменение определения коснулось множества downstream процессов, но это не аргумент против уточнения модели.
По-моему, эта история - хороший пример управления семантической моделью на доменном уровне.
❤3🔥2