<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~files/feed-premium.xsl"?>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:feedpress="https://feed.press/xmlns" xmlns:podcast="https://podcastindex.org/namespace/1.0" version="2.0">
  <channel>
    <feedpress:locale>en</feedpress:locale>
    <atom:link rel="self" href="https://feeds.dzone.com/devops-and-cicd"/>
    <atom:link rel="hub" href="https://feedpress.superfeedr.com/"/>
    <title>DZone DevOps and CI/CD Zone</title>
    <link>https://dzone.com/devops-and-cicd</link>
    <description>Recent posts in DevOps and CI/CD on DZone.com</description>
    <item>
      <title>Scaling Teams, Scaling Systems: Unlocking Developer Productivity With Platform Engineering</title>
      <link>https://feeds.dzone.com/link/23568/17380214/platform-engineering-productivity</link>
      <description><![CDATA[<p data-selectable-paragraph="">Modern software delivery is complex. Developers are responsible not only for writing code that meets business requirements — both functional and non-functional — but also for navigating a long chain of supporting steps. From containerization, testing, configuration, security, deployment, and monitoring, each stage often relies on specialized tools and teams.</p>
<p data-selectable-paragraph="">When these processes aren’t standardized, every project risks reinventing the wheel. The result is inconsistency, delays, and frustration. For example, requesting a new test environment might require submitting detailed tickets to a DevOps team, slowing timelines and draining energy. As organizations scale, so does the complexity — and the pain of delivery.</p><img src="https://feeds.dzone.com/link/23568/17380214.gif" height="1" width="1"/>]]></description>
      <pubDate>Tue, 14 Jul 2026 15:00:00 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3665888</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19080575&amp;w=600"/>
      <dc:creator>Ammar Husain</dc:creator>
    </item>
    <item>
      <title>Building Reliable Async Processing Pipelines Using Temporal</title>
      <link>https://feeds.dzone.com/link/23568/17379548/building-async-pipelines-using-temporal</link>
      <description><![CDATA[<p>Asynchronous processing pipelines are a cornerstone of modern distributed systems, but wiring them together reliably can be complex. A typical pipeline built with queues or message brokers requires custom retry logic, dead-letter queues, cron recovery jobs, and database status flags to ensure every step eventually succeeds.&nbsp;</p>
<p>Temporal replaces this heavy plumbing with durable workflows. In a <a href="https://dzone.com/articles/temporal-workflow-design-patterns">Temporal workflow</a>, the business logic of the pipeline is written as ordinary sequential code, yet it executes reliably across failures. The platform persists every state transition and step so that if a worker crashes or a network blip occurs, execution resumes exactly where it left off.&nbsp;</p><img src="https://feeds.dzone.com/link/23568/17379548.gif" height="1" width="1"/>]]></description>
      <pubDate>Mon, 13 Jul 2026 13:00:06 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3654791</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19088013&amp;w=600"/>
      <dc:creator>Akhil Madineni</dc:creator>
    </item>
    <item>
      <title>Candidate Generation Decides Your Pipeline's Cost, Not the LLM</title>
      <link>https://feeds.dzone.com/link/23568/17375651/candidate-generation-cost</link>
      <description><![CDATA[<h2>When the Most Capable Model Is the Wrong Starting Point</h2>
<p>The fastest way to exceed a document pipeline budget is to let an LLM inspect <em>every</em> document before you have performed lightweight filtering. This sounds obvious, but the bottleneck is invisible at the prototype stage. A single model call is cheap, and it works well on the 20 documents in your test set. Then you hit production traffic.</p>
<p>The <a href="https://dzone.com/articles/the-hidden-failure-modes-of-ai-systems">failure mode</a> is usually pretty similar across teams: tens of thousands of LLM calls per day, tens of millions of tokens, and a monthly bill that drifts past the assigned budget. No candidate generation. No triage. Raw corpus straight to the model. The cost compounds because the corpus does not shrink without an upstream triage. A more capable model just gives you a more expensive way to process noise.</p><img src="https://feeds.dzone.com/link/23568/17375651.gif" height="1" width="1"/>]]></description>
      <pubDate>Thu, 09 Jul 2026 18:00:00 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3654651</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19085078&amp;w=600"/>
      <dc:creator>Deepak Gupta</dc:creator>
    </item>
    <item>
      <title>From Bash Script to Operational Triage: What Eight Months of Kubernetes Debugging Taught Me</title>
      <link>https://feeds.dzone.com/link/23568/17375580/kubernetes-debugging-lessons</link>
      <description><![CDATA[<p>In November 2025, I published a Bash script that analyzed Kubernetes clusters in about 60 seconds. It generated HTML reports, surfaced crash loops, orphaned resources, and other operational issues that were easy to overlook. The most interesting part wasn't the script — it was what happened after people started running it. Many told me they found problems they hadn't known existed.</p>
<p>Looking back, the bash script wasn't really solving debugging. It was solving prioritization. I just didn't have the vocabulary for it yet.</p><img src="https://feeds.dzone.com/link/23568/17375580.gif" height="1" width="1"/>]]></description>
      <pubDate>Thu, 09 Jul 2026 15:00:06 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3664901</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19084034&amp;w=600"/>
      <dc:creator>Shamsher Khan</dc:creator>
    </item>
    <item>
      <title>Getting Started With RabbitMQ in Spring Boot</title>
      <link>https://feeds.dzone.com/link/23568/17375049/rabbitmq-spring-boot</link>
      <description><![CDATA[<p>RabbitMQ is an enterprise-grade open-source messaging and streaming broker. In this blog, you will learn some basic concepts of RabbitMQ and how to use it in a Spring Boot application. Enjoy!</p>
<h2>Introduction</h2>
<p>Before diving into the programmatic details, first some concepts need to be explained. Do realize that in this blog, only the surface is scratched from what is possible with RabbitMQ. A detailed overview can be found in the <a href="https://www.rabbitmq.com/tutorials" rel="noopener noreferrer" target="_blank">official RabbitMQ documentation</a>.</p><img src="https://feeds.dzone.com/link/23568/17375049.gif" height="1" width="1"/>]]></description>
      <pubDate>Wed, 08 Jul 2026 17:00:03 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3665897</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19083484&amp;w=600"/>
      <dc:creator>Gunter Rotsaert</dc:creator>
    </item>
    <item>
      <title>Building Production-Grade Delta Lake Pipelines With Apache Spark on Databricks</title>
      <link>https://feeds.dzone.com/link/23568/17374991/production-grade-data-late-pipelines</link>
      <description><![CDATA[<h2>Why Delta Lake?</h2>
<p>Apache Parquet on cloud storage was a great first step for <a href="https://dzone.com/articles/data-lake-warehouse-or-lakehouse">data lakes</a> — but it left engineers dealing with a painful set of problems in production:</p>
<ul>
 <li><strong>No ACID transactions</strong> — concurrent reads/writes could corrupt data silently</li>
 <li><strong>Schema drift</strong> — nothing stopped upstream systems from changing column types</li>
 <li><strong>No deletes or updates</strong> — GDPR compliance meant rewriting entire partitions</li>
 <li><strong>Painful failure recovery</strong> — half-written data after a job crash became your problem</li>
</ul>
<p>Delta Lake solves all of this by sitting on top of Parquet and adding a transaction log (<code>_delta_log/</code>) that records every operation atomically. On Databricks, Delta is the default table format, deeply integrated with Apache Spark, Auto Optimize, and the Photon execution engine.</p><img src="https://feeds.dzone.com/link/23568/17374991.gif" height="1" width="1"/>]]></description>
      <pubDate>Wed, 08 Jul 2026 14:00:00 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3662913</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19081615&amp;w=600"/>
      <dc:creator>Jubin Abhishek Soni</dc:creator>
    </item>
    <item>
      <title>AI Won't Keep You from Hitting the Scalability Wall</title>
      <link>https://feeds.dzone.com/link/23568/17374915/ai-scalability-wall</link>
      <description><![CDATA[<p dir="ltr">Using AI to build integrations? You might just be hitting the scalability wall faster. Discover why faster builds don't solve the long-term cost of ownership.</p>
<p>There's an idea making the rounds in B2B SaaS product and engineering meetings right now. It sounds reasonable. It feels optimistic. And it's leading companies straight into the same trap they've always fallen into, just at an accelerated rate.</p><img src="https://feeds.dzone.com/link/23568/17374915.gif" height="1" width="1"/>]]></description>
      <pubDate>Wed, 08 Jul 2026 12:00:00 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3659524</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19049242&amp;w=600"/>
      <dc:creator>Bru Woodring</dc:creator>
    </item>
    <item>
      <title>How to Build a Production-Ready RAG Pipeline With Vector DBs</title>
      <link>https://feeds.dzone.com/link/23568/17374054/production-rag-pipeline</link>
      <description><![CDATA[<p dir="ltr">The adoption of retrieval-augmented generation (RAG) from research papers to production systems has been rapid. Those who tried it in 2023 are now deploying it at scale for enterprise search, internal knowledge bases, and customer-facing assistants. However, a lot is still between a working prototype RAG and one that can withstand traffic on the road, using real data, and real modes of failure.</p>
<p dir="ltr">This article explains what this gap is, how to plug it, and where most production pipelines fail.</p><img src="https://feeds.dzone.com/link/23568/17374054.gif" height="1" width="1"/>]]></description>
      <pubDate>Mon, 06 Jul 2026 19:15:01 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3663121</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19078882&amp;w=600"/>
      <dc:creator>Mark Saxon</dc:creator>
    </item>
    <item>
      <title>Building an AI Agent That Responds to Real-Time Events With AWS Bedrock, Kinesis, DynamoDB, and S3</title>
      <link>https://feeds.dzone.com/link/23568/17372262/real-time-ai-agent-aws</link>
      <description><![CDATA[<p>Most recommendation systems are batch jobs. They crunch last night's data, write a recommendations table, and serve it all day. That works fine until your user watches three thriller movies in a row at 9 pm and your system is still recommending rom-coms because the batch hasn't run yet.</p>
<p>In this post, I'll walk through building an agent system that reacts to streaming user behavior in real time using:</p><img src="https://feeds.dzone.com/link/23568/17372262.gif" height="1" width="1"/>]]></description>
      <pubDate>Fri, 03 Jul 2026 13:00:04 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3663564</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19077386&amp;w=600"/>
      <dc:creator>Jubin Abhishek Soni</dc:creator>
    </item>
    <item>
      <title>One Stolen Key, One Stolen Token: Why Machine Identity Is Cloud-Native's Quietest Crisis — and the Only Fix That Actually Holds</title>
      <link>https://feeds.dzone.com/link/23568/17371223/machine-identity-cloud-security</link>
      <description><![CDATA[<p>On December 2, 2024, a security vendor called BeyondTrust noticed something wrong inside its own AWS account. By the time the investigation closed, the story that emerged was almost absurdly simple for something with this much fallout: an attacker — later attributed to the Chinese state-sponsored group Silk Typhoon — had used a software flaw to reach into a BeyondTrust cloud account and pull out an API key. Not a password. Not a phishing victim's login. A string of characters that a piece of software used to talk to another piece of software.&nbsp;</p>
<p>With that one key, the attacker walked straight into the U.S. Department of the Treasury, reset internal passwords, accessed workstations inside the Office of Foreign Assets Control, and read unclassified documents before anyone noticed. The Treasury disclosed it to Congress on December 30. The Department of Justice indicted the alleged operators in March 2025.</p><img src="https://feeds.dzone.com/link/23568/17371223.gif" height="1" width="1"/>]]></description>
      <pubDate>Wed, 01 Jul 2026 17:00:00 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3659906</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19075934&amp;w=600"/>
      <dc:creator>Igboanugo David Ugochukwu</dc:creator>
    </item>
    <item>
      <title>Building Production-Safe Agentic Remediation With Docker MCP Gateway: Lessons From 43% to 100% Accuracy</title>
      <link>https://feeds.dzone.com/link/23568/17369883/docker-mcp-agentic-remediation</link>
      <description><![CDATA[<p>Our first version was wrong 57% of the time.&nbsp;</p>
<p>Not because the AI model couldn't identify Docker container failure scenarios—it usually could. The failures occurred at the decision boundary: determining when an automated action was appropriate, when escalation was required, and when no action should be taken.</p><img src="https://feeds.dzone.com/link/23568/17369883.gif" height="1" width="1"/>]]></description>
      <pubDate>Mon, 29 Jun 2026 17:00:00 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3660985</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19071355&amp;w=600"/>
      <dc:creator>Mohammad-Ali Arabi</dc:creator>
      <dc:creator>Shamsher Khan</dc:creator>
    </item>
    <item>
      <title>Data Pipeline Observability: Why Your AI Model Fails in Production</title>
      <link>https://feeds.dzone.com/link/23568/17368711/why-ai-model-fails-in-production</link>
      <description><![CDATA[<h2 data-anchor="the3amincidentthatchangedeverything" data-slate-node="element" data-slug="the3amincidentthatchangedeverything3"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">The 3:00 AM Incident That Changed Everything</span></span></span></h2>
<div data-slate-node="element">
 <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">It was a Tuesday morning when the alerts started firing. Our recommendation engine, the one that drives 30% of our revenue, had tanked. Accuracy dropped from 94% to 58% overnight. The data science team immediately blamed the model. They started tweaking hyperparameters, re-training on new data, and running diagnostics. Nothing worked.&nbsp;</span></span></span>
</div>
<div data-slate-node="element">
 <br>
</div>
<div data-slate-node="element">
 <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">I got pulled into the war room at 3:00 AM. The first thing I asked wasn't "What's wrong with the model?" It was "What changed in the data pipeline?"</span></span></span>
</div>
<div data-slate-node="element">
 <br>
</div>
<div data-slate-node="element">
 <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Turns out, everything.</span></span></span>
 <br>
 <br>
</div>
<div data-slate-node="element">
 <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">A vendor had pushed a schema change upstream. A field that used to be required became optional. Null values started flowing through our pipeline. Our feature engineering code didn't handle nulls gracefully; it just propagated them downstream. By the time the data reached the model, 40% of our feature vectors were corrupted.</span></span></span>
 <br>
 <br>
</div>
<div data-slate-node="element">
 <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">The model wasn't broken. The data was.</span></span></span>
 <br>
 <br>
</div>
<div data-slate-node="element">
 <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">We spent six hours manually rolling back the schema change, re-running the pipeline, and restoring service. The incident report was brutal: "Lack of data validation caught a breaking change too late."</span></span></span>
</div>
<div data-slate-fragment="JTVCJTdCJTIydHlwZSUyMiUzQSUyMmhlYWRpbmclMjIlMkMlMjJsZXZlbCUyMiUzQTIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJUaGUlMjAzJTIwQU0lMjBJbmNpZGVudCUyMFRoYXQlMjBDaGFuZ2VkJTIwRXZlcnl0aGluZyUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJwJTIyJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIySXQlMjB3YXMlMjBhJTIwVHVlc2RheSUyMG1vcm5pbmclMjB3aGVuJTIwdGhlJTIwYWxlcnRzJTIwc3RhcnRlZCUyMGZpcmluZy4lMjBPdXIlMjByZWNvbW1lbmRhdGlvbiUyMGVuZ2luZSVFMiU4MCU5NHRoZSUyMG9uZSUyMHRoYXQlMjBkcml2ZXMlMjAzMCUyNSUyMG9mJTIwb3VyJTIwcmV2ZW51ZSVFMiU4MCU5NGhhZCUyMHRhbmtlZC4lMjBBY2N1cmFjeSUyMGRyb3BwZWQlMjBmcm9tJTIwOTQlMjUlMjB0byUyMDU4JTI1JTIwb3Zlcm5pZ2h0LiUyMFRoZSUyMGRhdGElMjBzY2llbmNlJTIwdGVhbSUyMGltbWVkaWF0ZWx5JTIwYmxhbWVkJTIwdGhlJTIwbW9kZWwuJTIwVGhleSUyMHN0YXJ0ZWQlMjB0d2Vha2luZyUyMGh5cGVycGFyYW1ldGVycyUyQyUyMHJlLXRyYWluaW5nJTIwb24lMjBuZXclMjBkYXRhJTJDJTIwcnVubmluZyUyMGRpYWdub3N0aWNzLiUyME5vdGhpbmclMjB3b3JrZWQuJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJJJTIwZ290JTIwcHVsbGVkJTIwaW50byUyMHRoZSUyMHdhciUyMHJvb20lMjBhdCUyMDMlMjBBTS4lMjBUaGUlMjBmaXJzdCUyMHRoaW5nJTIwSSUyMGFza2VkJTIwd2Fzbid0JTIwJTVDJTIyV2hhdCdzJTIwd3JvbmclMjB3aXRoJTIwdGhlJTIwbW9kZWwlM0YlNUMlMjIlMjBJdCUyMHdhcyUyMCU1QyUyMldoYXQlMjBjaGFuZ2VkJTIwaW4lMjB0aGUlMjBkYXRhJTIwcGlwZWxpbmUlM0YlNUMlMjIlMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIycCUyMiUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMlR1cm5zJTIwb3V0JTJDJTIwZXZlcnl0aGluZy4lMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIycCUyMiUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMkElMjB2ZW5kb3IlMjBoYWQlMjBwdXNoZWQlMjBhJTIwc2NoZW1hJTIwY2hhbmdlJTIwdXBzdHJlYW0uJTIwQSUyMGZpZWxkJTIwdGhhdCUyMHVzZWQlMjB0byUyMGJlJTIwcmVxdWlyZWQlMjBiZWNhbWUlMjBvcHRpb25hbC4lMjBOdWxsJTIwdmFsdWVzJTIwc3RhcnRlZCUyMGZsb3dpbmclMjB0aHJvdWdoJTIwb3VyJTIwcGlwZWxpbmUuJTIwT3VyJTIwZmVhdHVyZSUyMGVuZ2luZWVyaW5nJTIwY29kZSUyMGRpZG4ndCUyMGhhbmRsZSUyMG51bGxzJTIwZ3JhY2VmdWxseSVFMiU4MCU5NGl0JTIwanVzdCUyMHByb3BhZ2F0ZWQlMjB0aGVtJTIwZG93bnN0cmVhbS4lMjBCeSUyMHRoZSUyMHRpbWUlMjB0aGUlMjBkYXRhJTIwcmVhY2hlZCUyMHRoZSUyMG1vZGVsJTJDJTIwNDAlMjUlMjBvZiUyMG91ciUyMGZlYXR1cmUlMjB2ZWN0b3JzJTIwd2VyZSUyMGNvcnJ1cHRlZC4lMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIycCUyMiUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMlRoZSUyMG1vZGVsJTIwd2Fzbid0JTIwYnJva2VuLiUyMFRoZSUyMGRhdGElMjB3YXMuJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJXZSUyMHNwZW50JTIwc2l4JTIwaG91cnMlMjBtYW51YWxseSUyMHJvbGxpbmclMjBiYWNrJTIwdGhlJTIwc2NoZW1hJTIwY2hhbmdlJTJDJTIwcmUtcnVubmluZyUyMHRoZSUyMHBpcGVsaW5lJTJDJTIwYW5kJTIwcmVzdG9yaW5nJTIwc2VydmljZS4lMjBUaGUlMjBpbmNpZGVudCUyMHJlcG9ydCUyMHdhcyUyMGJydXRhbCUzQSUyMCU1QyUyMkxhY2slMjBvZiUyMGRhdGElMjB2YWxpZGF0aW9uJTIwY2F1Z2h0JTIwYSUyMGJyZWFraW5nJTIwY2hhbmdlJTIwdG9vJTIwbGF0ZS4lNUMlMjIlMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIycCUyMiUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMlRoYXQncyUyMHdoZW4lMjBJJTIwcmVhbGl6ZWQlMjB3ZSUyMG5lZWRlZCUyMG9ic2VydmFiaWxpdHklMjBpbiUyMG91ciUyMGRhdGElMjBwaXBlbGluZSUyQyUyMG5vdCUyMGp1c3QlMjBpbiUyMG91ciUyMG1vZGVscy4lMjIlN0QlNUQlN0QlNUQ=">
 <div data-slate-node="element">
  <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">That's when I realized we needed&nbsp;</span></span></span><a href="https://dzone.com/articles/introduction-to-the-four-pillars-of-observability"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">observability</span></span></span></a><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">&nbsp;in our data pipeline, not just in our models.</span></span></span>
  <br>
  <br>
 </div>
 <h2 data-anchor="theproblem%3Adataqualityisinvisibleuntilitbreaks" data-slate-node="element" data-slug="theproblem%3Adataqualityisinvisibleuntilitbreaks12"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">The Problem: Data Quality is Invisible Until It Breaks</span></span></span></h2>
 <div data-slate-node="element">
  <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Here's the uncomfortable truth about data pipelines: they fail silently.</span></span></span>
  <br>
  <br>
 </div>
 <div data-slate-node="element">
  <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Your ETL job completes successfully. Your Spark cluster finishes transformations. Your data warehouse loads without errors. Everything looks green in the monitoring dashboard. But the data itself? Garbage in, garbage out.</span></span></span>
  <br>
  <br>
 </div>
 <div data-slate-node="element">
  <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">There are three categories of failures that break AI models in production:</span></span></span>
  <br>
  <br>
 </div>
 <ul>
  <li>
   <div data-slate-node="element">
    <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true"><strong>Missing Values:</strong></span></span></span><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true"><strong>&nbsp;</strong>A source system stops populating a field. Your pipeline doesn't validate it. The model gets NaN values it never saw during training. Predictions become random noise.</span></span></span>
   </div></li>
  <li>
   <div data-slate-node="element">
    <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true"><strong>Schema Changes:</strong></span></span></span><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true"><strong>&nbsp;</strong>An upstream team adds a new column, renames an existing one, or changes data types. Your pipeline doesn't expect these changes. Either it crashes, or worse, it silently maps data to the wrong columns.</span></span></span>
   </div></li>
  <li>
   <div data-slate-node="element">
    <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true"><strong>Distribution Shifts:</strong></span></span></span><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true"><strong>&nbsp;</strong>The statistical properties of your data change. A field that was always between 0 and 100 suddenly has values of 50,000. Your model's scaling assumptions break. Predictions become nonsensical.</span></span></span>
   </div></li>
 </ul>
 <div data-slate-fragment="JTVCJTdCJTIydHlwZSUyMiUzQSUyMmhlYWRpbmclMjIlMkMlMjJsZXZlbCUyMiUzQTIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJUaGUlMjBQcm9ibGVtJTNBJTIwRGF0YSUyMFF1YWxpdHklMjBpcyUyMEludmlzaWJsZSUyMFVudGlsJTIwSXQlMjBCcmVha3MlMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIycCUyMiUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMkhlcmUncyUyMHRoZSUyMHVuY29tZm9ydGFibGUlMjB0cnV0aCUyMGFib3V0JTIwZGF0YSUyMHBpcGVsaW5lcyUzQSUyMHRoZXklMjBmYWlsJTIwc2lsZW50bHkuJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJZb3VyJTIwRVRMJTIwam9iJTIwY29tcGxldGVzJTIwc3VjY2Vzc2Z1bGx5LiUyMFlvdXIlMjBTcGFyayUyMGNsdXN0ZXIlMjBmaW5pc2hlcyUyMHRyYW5zZm9ybWF0aW9ucy4lMjBZb3VyJTIwZGF0YSUyMHdhcmVob3VzZSUyMGxvYWRzJTIwd2l0aG91dCUyMGVycm9ycy4lMjBFdmVyeXRoaW5nJTIwbG9va3MlMjBncmVlbiUyMGluJTIwdGhlJTIwbW9uaXRvcmluZyUyMGRhc2hib2FyZC4lMjBCdXQlMjB0aGUlMjBkYXRhJTIwaXRzZWxmJTNGJTIwR2FyYmFnZSUyMGluJTJDJTIwZ2FyYmFnZSUyMG91dC4lMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIycCUyMiUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMlRoZXJlJTIwYXJlJTIwdGhyZWUlMjBjYXRlZ29yaWVzJTIwb2YlMjBmYWlsdXJlcyUyMHRoYXQlMjBicmVhayUyMEFJJTIwbW9kZWxzJTIwaW4lMjBwcm9kdWN0aW9uJTNBJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJNaXNzaW5nJTIwVmFsdWVzJTNBJTIyJTJDJTIyYm9sZCUyMiUzQXRydWUlN0QlMkMlN0IlMjJ0ZXh0JTIyJTNBJTIyJTIwQSUyMHNvdXJjZSUyMHN5c3RlbSUyMHN0b3BzJTIwcG9wdWxhdGluZyUyMGElMjBmaWVsZC4lMjBZb3VyJTIwcGlwZWxpbmUlMjBkb2Vzbid0JTIwdmFsaWRhdGUlMjBpdC4lMjBUaGUlMjBtb2RlbCUyMGdldHMlMjBOYU4lMjB2YWx1ZXMlMjBpdCUyMG5ldmVyJTIwc2F3JTIwZHVyaW5nJTIwdHJhaW5pbmcuJTIwUHJlZGljdGlvbnMlMjBiZWNvbWUlMjByYW5kb20lMjBub2lzZS4lMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIycCUyMiUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMlNjaGVtYSUyMENoYW5nZXMlM0ElMjIlMkMlMjJib2xkJTIyJTNBdHJ1ZSU3RCUyQyU3QiUyMnRleHQlMjIlM0ElMjIlMjBBbiUyMHVwc3RyZWFtJTIwdGVhbSUyMGFkZHMlMjBhJTIwbmV3JTIwY29sdW1uJTJDJTIwcmVuYW1lcyUyMGFuJTIwZXhpc3RpbmclMjBvbmUlMkMlMjBvciUyMGNoYW5nZXMlMjBkYXRhJTIwdHlwZXMuJTIwWW91ciUyMHBpcGVsaW5lJTIwZG9lc24ndCUyMGV4cGVjdCUyMHRoZXNlJTIwY2hhbmdlcy4lMjBFaXRoZXIlMjBpdCUyMGNyYXNoZXMlMkMlMjBvciUyMHdvcnNlJTJDJTIwaXQlMjBzaWxlbnRseSUyMG1hcHMlMjBkYXRhJTIwdG8lMjB0aGUlMjB3cm9uZyUyMGNvbHVtbnMuJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJEaXN0cmlidXRpb24lMjBTaGlmdHMlM0ElMjIlMkMlMjJib2xkJTIyJTNBdHJ1ZSU3RCUyQyU3QiUyMnRleHQlMjIlM0ElMjIlMjBUaGUlMjBzdGF0aXN0aWNhbCUyMHByb3BlcnRpZXMlMjBvZiUyMHlvdXIlMjBkYXRhJTIwY2hhbmdlLiUyMEElMjBmaWVsZCUyMHRoYXQlMjB3YXMlMjBhbHdheXMlMjBiZXR3ZWVuJTIwMCUyMGFuZCUyMDEwMCUyMHN1ZGRlbmx5JTIwaGFzJTIwdmFsdWVzJTIwb2YlMjA1MCUyQzAwMC4lMjBZb3VyJTIwbW9kZWwncyUyMHNjYWxpbmclMjBhc3N1bXB0aW9ucyUyMGJyZWFrLiUyMFByZWRpY3Rpb25zJTIwYmVjb21lJTIwbm9uc2Vuc2ljYWwuJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJOb25lJTIwb2YlMjB0aGVzZSUyMHNob3clMjB1cCUyMGluJTIwdHJhZGl0aW9uYWwlMjBpbmZyYXN0cnVjdHVyZSUyMG1vbml0b3JpbmcuJTIwWW91ciUyMENQVSUyMGlzJTIwZmluZS4lMjBNZW1vcnklMjBpcyUyMGZpbmUuJTIwTmV0d29yayUyMGlzJTIwZmluZS4lMjBCdXQlMjB5b3VyJTIwZGF0YSUyMGlzJTIwb24lMjBmaXJlLiUyMiU3RCU1RCU3RCU1RA==">
  <div data-slate-node="element">
   <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">None of these show up in traditional infrastructure monitoring. Your CPU is fine. Memory is fine. Network is fine. But your data is on fire.</span></span></span>
  </div>
  <h2 data-anchor="thesolution%3Aobservabilityateverylayer" data-slate-node="element" data-slug="thesolution%3Aobservabilityateverylayer21"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">The Solution: Observability at Every Layer</span></span></span></h2>
  <div data-slate-node="element">
   <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">I started building a three-layer observability framework using dbt, Great Expectations, and custom validation logic. The goal was simple: catch data quality issues before they reach the model.</span></span></span>
  </div>
  <h3 data-anchor="layer1%3Adbttests(thefirstlineofdefense)" data-slate-node="element" data-slug="layer1%3Adbttests(thefirstlineofdefense)23"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Layer 1: dbt Tests (The First Line of Defense)</span></span></span></h3>
  <div data-slate-node="element">
   <a href="https://dzone.com/articles/dbt-false-failures"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">dbt tests</span></span></span></a><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">&nbsp;are your cheapest, fastest way to catch obvious data quality issues. They run after every transformation and fail the entire pipeline if something's wrong.</span></span></span>
  </div>
  <div data-slate-fragment="JTVCJTdCJTIydHlwZSUyMiUzQSUyMmhlYWRpbmclMjIlMkMlMjJsZXZlbCUyMiUzQTIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJUaGUlMjBTb2x1dGlvbiUzQSUyME9ic2VydmFiaWxpdHklMjBhdCUyMEV2ZXJ5JTIwTGF5ZXIlMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIycCUyMiUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMkklMjBzdGFydGVkJTIwYnVpbGRpbmclMjBhJTIwdGhyZWUtbGF5ZXIlMjBvYnNlcnZhYmlsaXR5JTIwZnJhbWV3b3JrJTIwdXNpbmclMjBkYnQlMkMlMjBHcmVhdCUyMEV4cGVjdGF0aW9ucyUyQyUyMGFuZCUyMGN1c3RvbSUyMHZhbGlkYXRpb24lMjBsb2dpYy4lMjBUaGUlMjBnb2FsJTIwd2FzJTIwc2ltcGxlJTNBJTIwY2F0Y2glMjBkYXRhJTIwcXVhbGl0eSUyMGlzc3VlcyUyMGJlZm9yZSUyMHRoZXklMjByZWFjaCUyMHRoZSUyMG1vZGVsLiUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJoZWFkaW5nJTIyJTJDJTIybGV2ZWwlMjIlM0EzJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyTGF5ZXIlMjAxJTNBJTIwZGJ0JTIwVGVzdHMlMjAoVGhlJTIwRmlyc3QlMjBMaW5lJTIwb2YlMjBEZWZlbnNlKSUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJwJTIyJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyZGJ0JTIwdGVzdHMlMjBhcmUlMjB5b3VyJTIwY2hlYXBlc3QlMkMlMjBmYXN0ZXN0JTIwd2F5JTIwdG8lMjBjYXRjaCUyMG9idmlvdXMlMjBkYXRhJTIwcXVhbGl0eSUyMGlzc3Vlcy4lMjBUaGV5JTIwcnVuJTIwYWZ0ZXIlMjBldmVyeSUyMHRyYW5zZm9ybWF0aW9uJTIwYW5kJTIwZmFpbCUyMHRoZSUyMGVudGlyZSUyMHBpcGVsaW5lJTIwaWYlMjBzb21ldGhpbmcncyUyMHdyb25nLiUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJwJTIyJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIySGVyZSdzJTIwd2hhdCUyMHdlJTIwaW1wbGVtZW50ZWQlM0ElMjIlN0QlNUQlN0QlNUQ=">
   <div data-slate-node="element">
    <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Here's what we implemented:</span></span></span>
   </div>
   <div class="codeMirror-wrapper" contenteditable="false">
    <div contenteditable="false">
     <div class="codeHeader">
      <div class="nameLanguage">
       SQL
      </div><i class="icon-cancel-circled-1 cm-remove">&nbsp;</i>
     </div>
     <div class="codeMirror-code--wrapper" data-code="-- models/staging/stg_user_events.yml
version: 2

models:
  - name: stg_user_events
    columns:
      - name: user_id
        tests:
          - not_null
          - unique
      - name: event_timestamp
        tests:
          - not_null
          - dbt_utils.expression_is_true:
              expression: &quot;event_timestamp <= current_timestamp()&quot;
      - name: event_value
        tests:
          - not_null
          - dbt_utils.expression_is_true:
              expression: &quot;event_value > 0&quot;" data-lang="text/x-sql">
      <pre><code lang="text/x-sql">-- models/staging/stg_user_events.yml
version: 2

models:
  - name: stg_user_events
    columns:
      - name: user_id
        tests:
          - not_null
          - unique
      - name: event_timestamp
        tests:
          - not_null
          - dbt_utils.expression_is_true:
              expression: "event_timestamp &lt;= current_timestamp()"
      - name: event_value
        tests:
          - not_null
          - dbt_utils.expression_is_true:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; expression: "event_value &gt; 0"</code></pre>
     </div>
    </div>
   </div>
   <div data-slate-node="element">
    <br>
   </div>
   <div data-slate-node="element">
    <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">These tests are simple but powerful. They catch:</span></span></span>
   </div>
   <ul>
    <li>Missing required fields (<code>not_null</code>)</li>
    <li>Duplicate records (unique)</li>
    <li>Impossible values (<code>event_timestamp</code> in the future)</li>
    <li>Out-of-range values (negative prices)</li>
   </ul>
   <div data-slate-node="element">
    <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">We run these tests on every dbt run. If any test fails, the pipeline stops. No data reaches the model. No silent corruption.</span></span></span>
    <br>
    <br>
   </div>
   <div data-slate-fragment="JTVCJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJUaGVzZSUyMHRlc3RzJTIwYXJlJTIwc2ltcGxlJTIwYnV0JTIwcG93ZXJmdWwuJTIwVGhleSUyMGNhdGNoJTNBJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMmxpc3RJdGVtJTIyJTJDJTIyb3JkZXJlZCUyMiUzQWZhbHNlJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyTWlzc2luZyUyMHJlcXVpcmVkJTIwZmllbGRzJTIwKG5vdF9udWxsKSUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJsaXN0SXRlbSUyMiUyQyUyMm9yZGVyZWQlMjIlM0FmYWxzZSUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMkR1cGxpY2F0ZSUyMHJlY29yZHMlMjAodW5pcXVlKSUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJsaXN0SXRlbSUyMiUyQyUyMm9yZGVyZWQlMjIlM0FmYWxzZSUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMkltcG9zc2libGUlMjB2YWx1ZXMlMjAoZXZlbnRfdGltZXN0YW1wJTIwaW4lMjB0aGUlMjBmdXR1cmUpJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMmxpc3RJdGVtJTIyJTJDJTIyb3JkZXJlZCUyMiUzQWZhbHNlJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyT3V0LW9mLXJhbmdlJTIwdmFsdWVzJTIwKG5lZ2F0aXZlJTIwcHJpY2VzKSUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJwJTIyJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyV2UlMjBydW4lMjB0aGVzZSUyMHRlc3RzJTIwb24lMjBldmVyeSUyMGRidCUyMHJ1bi4lMjBJZiUyMGFueSUyMHRlc3QlMjBmYWlscyUyQyUyMHRoZSUyMHBpcGVsaW5lJTIwc3RvcHMuJTIwTm8lMjBkYXRhJTIwcmVhY2hlcyUyMHRoZSUyMG1vZGVsLiUyME5vJTIwc2lsZW50JTIwY29ycnVwdGlvbi4lMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIycCUyMiUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMlRoZSUyMGJlYXV0eSUyMG9mJTIwZGJ0JTIwdGVzdHMlMjBpcyUyMHRoYXQlMjB0aGV5J3JlJTIwdmVyc2lvbi1jb250cm9sbGVkJTJDJTIwZG9jdW1lbnRlZCUyQyUyMGFuZCUyMHBhcnQlMjBvZiUyMHlvdXIlMjB0cmFuc2Zvcm1hdGlvbiUyMGNvZGUuJTIwV2hlbiUyMGElMjBzY2hlbWElMjBjaGFuZ2UlMjBoYXBwZW5zJTJDJTIweW91JTIwdXBkYXRlJTIwdGhlJTIwdGVzdCUyQyUyMGNvbW1pdCUyMGl0JTJDJTIwYW5kJTIwZXZlcnlvbmUlMjBrbm93cyUyMHdoYXQlMjBjaGFuZ2VkLiUyMiU3RCU1RCU3RCU1RA==">
    <div data-slate-node="element">
     <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">The beauty of dbt tests is that they're version-controlled, documented, and part of your transformation code. When a schema change happens, you update the test, commit it, and everyone knows what changed.</span></span></span>
     <br>
     <br>
    </div>
    <h3 data-anchor="layer2%3Agreatexpectations(thestatisticalvalidator)" data-slate-node="element" data-slug="layer2%3Agreatexpectations(thestatisticalvalidator)34"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Layer 2: Great Expectations (The Statistical Validator)</span></span></span></h3>
    <div data-slate-node="element">
     <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">dbt tests catch structural issues. Great Expectations catches statistical anomalies, the subtle shifts that break models.</span></span></span>
     <br>
     <br>
    </div>
    <div data-slate-fragment="JTVCJTdCJTIydHlwZSUyMiUzQSUyMmhlYWRpbmclMjIlMkMlMjJsZXZlbCUyMiUzQTMlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJMYXllciUyMDIlM0ElMjBHcmVhdCUyMEV4cGVjdGF0aW9ucyUyMChUaGUlMjBTdGF0aXN0aWNhbCUyMFZhbGlkYXRvciklMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIycCUyMiUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMmRidCUyMHRlc3RzJTIwY2F0Y2glMjBzdHJ1Y3R1cmFsJTIwaXNzdWVzLiUyMEdyZWF0JTIwRXhwZWN0YXRpb25zJTIwY2F0Y2hlcyUyMHN0YXRpc3RpY2FsJTIwYW5vbWFsaWVzJUUyJTgwJTk0dGhlJTIwc3VidGxlJTIwc2hpZnRzJTIwdGhhdCUyMGJyZWFrJTIwbW9kZWxzLiUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJwJTIyJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIySGVyZSdzJTIwYSUyMHJlYWwlMjBzY2VuYXJpbyUzQSUyMG91ciUyMHVzZXJfYWdlJTIwY29sdW1uJTIwaGFkJTIwYSUyMGRpc3RyaWJ1dGlvbiUyMG9mJTIwMTgtNjUlMjBmb3IlMjB0d28lMjB5ZWFycy4lMjBUaGVuJTIwb25lJTIwZGF5JTJDJTIwd2UlMjBzdGFydGVkJTIwZ2V0dGluZyUyMGFnZXMlMjBvZiUyMDIwMCUyQyUyMDUwMCUyQyUyMDEwMDAuJTIwQSUyMGRhdGElMjBlbnRyeSUyMGJ1ZyUyMHVwc3RyZWFtLiUyMGRidCUyMHRlc3RzJTIwd291bGRuJ3QlMjBjYXRjaCUyMHRoaXMlMjBiZWNhdXNlJTIwdGhlJTIwdmFsdWVzJTIwYXJlJTIwdGVjaG5pY2FsbHklMjB2YWxpZCUyMGludGVnZXJzLiUyMEJ1dCUyMEdyZWF0JTIwRXhwZWN0YXRpb25zJTIwd291bGQuJTIyJTdEJTVEJTdEJTVE">
     <div data-slate-node="element">
      <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Here's a real scenario: our <code>user_age</code> column had a distribution of 18-65 for two years. Then one day, we started getting ages of 200, 500, 1000. A data entry bug upstream. dbt tests wouldn't catch this because the values are technically valid integers. But Great Expectations would.</span></span></span>
     </div>
     <div class="codeMirror-wrapper" contenteditable="false">
      <div contenteditable="false">
       <div class="codeHeader">
        <div class="nameLanguage">
         Python
        </div><i class="icon-cancel-circled-1 cm-remove">&nbsp;</i>
       </div>
       <div class="codeMirror-code--wrapper" data-code="# great_expectations/expectations/user_events_expectations.py
from great_expectations.core.batch import RuntimeBatchRequest
from great_expectations.data_context import DataContext

context = DataContext()
suite = context.create_expectation_suite(
    expectation_suite_name=&quot;user_events_suite&quot;,
    overwrite_existing=True
)

validator = context.get_validator(
    batch_request=RuntimeBatchRequest(
        datasource_name=&quot;my_spark_datasource&quot;,
        data_connector_name=&quot;default_runtime_data_connector&quot;,
        data_asset_name=&quot;user_events&quot;
    ),
    expectation_suite_name=&quot;user_events_suite&quot;
)

# Expect user_age to be between 18 and 120
validator.expect_column_values_to_be_between(
    column=&quot;user_age&quot;,
    min_value=18,
    max_value=120
)

# Expect event_value to have a mean between 50 and 200
validator.expect_column_mean_to_be_between(
    column=&quot;event_value&quot;,
    min_value=50,
    max_value=200
)

# Expect less than 5% missing values in critical columns
validator.expect_column_values_to_not_be_null(
    column=&quot;user_id&quot;,
    mostly=0.95
)

# Expect the distribution to match historical patterns
validator.expect_column_kl_divergence_from_list(
    column=&quot;event_type&quot;,
    partition_object={&quot;event_type&quot;: [&quot;click&quot;, &quot;view&quot;, &quot;purchase&quot;]},
    threshold=0.1
)

validator.save_expectation_suite(discard_failed_expectations=False)" data-lang="text/x-python">
        <pre><code lang="text/x-python"># great_expectations/expectations/user_events_expectations.py
from great_expectations.core.batch import RuntimeBatchRequest
from great_expectations.data_context import DataContext

context = DataContext()
suite = context.create_expectation_suite(
    expectation_suite_name="user_events_suite",
    overwrite_existing=True
)

validator = context.get_validator(
    batch_request=RuntimeBatchRequest(
        datasource_name="my_spark_datasource",
        data_connector_name="default_runtime_data_connector",
        data_asset_name="user_events"
    ),
    expectation_suite_name="user_events_suite"
)

# Expect user_age to be between 18 and 120
validator.expect_column_values_to_be_between(
    column="user_age",
    min_value=18,
    max_value=120
)

# Expect event_value to have a mean between 50 and 200
validator.expect_column_mean_to_be_between(
    column="event_value",
    min_value=50,
    max_value=200
)

# Expect less than 5% missing values in critical columns
validator.expect_column_values_to_not_be_null(
    column="user_id",
    mostly=0.95
)

# Expect the distribution to match historical patterns
validator.expect_column_kl_divergence_from_list(
    column="event_type",
    partition_object={"event_type": ["click", "view", "purchase"]},
    threshold=0.1
)

validator.save_expectation_suite(discard_failed_expectations=False)</code></pre>
       </div>
      </div>
     </div>
     <div data-slate-node="element">
      <br>
     </div>
     <div data-slate-node="element">
      <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Great Expectations runs after dbt tests. It validates:</span></span></span>
     </div>
     <ul>
      <li>Value ranges (age between 18 and 120)</li>
      <li>Statistical properties (mean event value between 50 and 200)</li>
      <li>Null rates (less than 5% missing in critical columns)</li>
      <li>Distribution shifts (<code>event_type</code> distribution matches historical patterns)</li>
     </ul>
     <div data-slate-node="element">
      <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">If Great Expectations detects an anomaly, it alerts us. We investigate before the data reaches the model.</span></span></span>
     </div>
     <h3 data-anchor="layer3%3Acustomvalidation(thedomainexpert)" data-slate-node="element" data-slug="layer3%3Acustomvalidation(thedomainexpert)44"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Layer 3: Custom Validation (The Domain Expert)</span></span></span></h3>
     <div data-slate-fragment="JTVCJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJHcmVhdCUyMEV4cGVjdGF0aW9ucyUyMHJ1bnMlMjBhZnRlciUyMGRidCUyMHRlc3RzLiUyMEl0JTIwdmFsaWRhdGVzJTNBJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMmxpc3RJdGVtJTIyJTJDJTIyb3JkZXJlZCUyMiUzQWZhbHNlJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyVmFsdWUlMjByYW5nZXMlMjAoYWdlJTIwYmV0d2VlbiUyMDE4JTIwYW5kJTIwMTIwKSUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJsaXN0SXRlbSUyMiUyQyUyMm9yZGVyZWQlMjIlM0FmYWxzZSUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMlN0YXRpc3RpY2FsJTIwcHJvcGVydGllcyUyMChtZWFuJTIwZXZlbnQlMjB2YWx1ZSUyMGJldHdlZW4lMjA1MCUyMGFuZCUyMDIwMCklMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIybGlzdEl0ZW0lMjIlMkMlMjJvcmRlcmVkJTIyJTNBZmFsc2UlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJOdWxsJTIwcmF0ZXMlMjAobGVzcyUyMHRoYW4lMjA1JTI1JTIwbWlzc2luZyUyMGluJTIwY3JpdGljYWwlMjBjb2x1bW5zKSUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJsaXN0SXRlbSUyMiUyQyUyMm9yZGVyZWQlMjIlM0FmYWxzZSUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMkRpc3RyaWJ1dGlvbiUyMHNoaWZ0cyUyMChldmVudF90eXBlJTIwZGlzdHJpYnV0aW9uJTIwbWF0Y2hlcyUyMGhpc3RvcmljYWwlMjBwYXR0ZXJucyklMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIycCUyMiUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMklmJTIwR3JlYXQlMjBFeHBlY3RhdGlvbnMlMjBkZXRlY3RzJTIwYW4lMjBhbm9tYWx5JTJDJTIwaXQlMjBhbGVydHMlMjB1cy4lMjBXZSUyMGludmVzdGlnYXRlJTIwYmVmb3JlJTIwdGhlJTIwZGF0YSUyMHJlYWNoZXMlMjB0aGUlMjBtb2RlbC4lMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIyaGVhZGluZyUyMiUyQyUyMmxldmVsJTIyJTNBMyUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMkxheWVyJTIwMyUzQSUyMEN1c3RvbSUyMFZhbGlkYXRpb24lMjAoVGhlJTIwRG9tYWluJTIwRXhwZXJ0KSUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJwJTIyJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyZGJ0JTIwYW5kJTIwR3JlYXQlMjBFeHBlY3RhdGlvbnMlMjBhcmUlMjBnZW5lcmljLiUyMFlvdXIlMjBkb21haW4lMjBpcyUyMHNwZWNpZmljLiUyMFdlJTIwYWRkZWQlMjBjdXN0b20lMjB2YWxpZGF0aW9uJTIwbG9naWMlMjB0aGF0JTIwdW5kZXJzdGFuZHMlMjBvdXIlMjBidXNpbmVzcy4lMjIlN0QlNUQlN0QlNUQ=">
      <div data-slate-node="element">
       <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">dbt and Great Expectations are generic. Your domain is specific. We added custom validation logic that understands our business.</span></span></span>
      </div>
      <div class="codeMirror-wrapper newest" contenteditable="false">
       <div contenteditable="false">
        <div class="codeHeader">
         <div class="nameLanguage">
          Python
         </div><i class="icon-cancel-circled-1 cm-remove">&nbsp;</i>
        </div>
        <div class="codeMirror-code--wrapper" data-code="# pipelines/validation/custom_validators.py
import pandas as pd
from datetime import datetime, timedelta

def validate_feature_engineering(df: pd.DataFrame) -> dict:
    &quot;&quot;&quot;
    Custom validation for features before they reach the model.
    Returns a dict of validation results.
    &quot;&quot;&quot;
    results = {}
    
    # Validate 1: Feature completeness
    # We need at least 95% of features populated
    feature_cols = [col for col in df.columns if col.startswith('feature_')]
    null_rate = df[feature_cols].isnull().sum().sum() / (len(df) * len(feature_cols))
    results['feature_completeness'] = {
        'passed': null_rate < 0.05,
        'null_rate': null_rate,
        'threshold': 0.05
    }
    
    # Validate 2: Feature scaling
    # After normalization, features should be roughly between -3 and 3 (3 sigma)
    for col in feature_cols:
        max_val = df[col].max()
        min_val = df[col].min()
        results[f'{col}_scaling'] = {
            'passed': max_val < 10 and min_val > -10,
            'max': max_val,
            'min': min_val
        }
    
    # Validate 3: Temporal consistency
    # Events should be recent (within last 30 days)
    if 'event_date' in df.columns:
        df['event_date'] = pd.to_datetime(df['event_date'])
        days_old = (datetime.now() - df['event_date'].max()).days
        results['temporal_freshness'] = {
            'passed': days_old < 30,
            'days_old': days_old,
            'threshold_days': 30
        }
    
    # Validate 4: Business logic
    # Revenue should always be positive
    if 'revenue' in df.columns:
        negative_revenue = (df['revenue'] < 0).sum()
        results['business_logic_revenue'] = {
            'passed': negative_revenue == 0,
            'negative_count': negative_revenue
        }
    
    return results

def validate_and_alert(df: pd.DataFrame, validation_results: dict) -> bool:
    &quot;&quot;&quot;
    Check all validations and alert if any fail.
    Returns True if all pass, False otherwise.
    &quot;&quot;&quot;
    all_passed = True
    
    for check_name, check_result in validation_results.items():
        if not check_result['passed']:
            all_passed = False
            print(f&quot;ALERT: {check_name} failed&quot;)
            print(f&quot;Details: {check_result}&quot;)
            # Send to monitoring system (Datadog, New Relic, etc.)
            # send_alert(check_name, check_result)
    
    return all_passed" data-lang="text/x-python">
         <pre><code lang="text/x-python"># pipelines/validation/custom_validators.py
import pandas as pd
from datetime import datetime, timedelta

def validate_feature_engineering(df: pd.DataFrame) -&gt; dict:
    """
    Custom validation for features before they reach the model.
    Returns a dict of validation results.
    """
    results = {}
    
    # Validate 1: Feature completeness
    # We need at least 95% of features populated
    feature_cols = [col for col in df.columns if col.startswith('feature_')]
    null_rate = df[feature_cols].isnull().sum().sum() / (len(df) * len(feature_cols))
    results['feature_completeness'] = {
        'passed': null_rate &lt; 0.05,
        'null_rate': null_rate,
        'threshold': 0.05
    }
    
    # Validate 2: Feature scaling
    # After normalization, features should be roughly between -3 and 3 (3 sigma)
    for col in feature_cols:
        max_val = df[col].max()
        min_val = df[col].min()
        results[f'{col}_scaling'] = {
            'passed': max_val &lt; 10 and min_val &gt; -10,
            'max': max_val,
            'min': min_val
        }
    
    # Validate 3: Temporal consistency
    # Events should be recent (within last 30 days)
    if 'event_date' in df.columns:
        df['event_date'] = pd.to_datetime(df['event_date'])
        days_old = (datetime.now() - df['event_date'].max()).days
        results['temporal_freshness'] = {
            'passed': days_old &lt; 30,
            'days_old': days_old,
            'threshold_days': 30
        }
    
    # Validate 4: Business logic
    # Revenue should always be positive
    if 'revenue' in df.columns:
        negative_revenue = (df['revenue'] &lt; 0).sum()
        results['business_logic_revenue'] = {
            'passed': negative_revenue == 0,
            'negative_count': negative_revenue
        }
    
    return results

def validate_and_alert(df: pd.DataFrame, validation_results: dict) -&gt; bool:
    """
    Check all validations and alert if any fail.
    Returns True if all pass, False otherwise.
    """
    all_passed = True
    
    for check_name, check_result in validation_results.items():
        if not check_result['passed']:
            all_passed = False
            print(f"ALERT: {check_name} failed")
            print(f"Details: {check_result}")
            # Send to monitoring system (Datadog, New Relic, etc.)
            # send_alert(check_name, check_result)
    
&nbsp; &nbsp; return all_passed</code></pre>
        </div>
       </div>
      </div>
      <div data-slate-node="element">
       <br>
      </div>
      <div data-slate-node="element">
       <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">This custom validation runs after Great Expectations. It checks:</span></span></span>
      </div>
      <ul>
       <li>Feature completeness (95% of features populated)</li>
       <li>Feature scaling (normalized features in the expected range)</li>
       <li>Temporal freshness (data is recent)</li>
       <li>Business logic (revenue is positive)</li>
      </ul>
      <div data-slate-fragment="JTVCJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJUaGlzJTIwY3VzdG9tJTIwdmFsaWRhdGlvbiUyMHJ1bnMlMjBhZnRlciUyMEdyZWF0JTIwRXhwZWN0YXRpb25zLiUyMEl0JTIwY2hlY2tzJTNBJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMmxpc3RJdGVtJTIyJTJDJTIyb3JkZXJlZCUyMiUzQWZhbHNlJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyRmVhdHVyZSUyMGNvbXBsZXRlbmVzcyUyMCg5NSUyNSUyMG9mJTIwZmVhdHVyZXMlMjBwb3B1bGF0ZWQpJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMmxpc3RJdGVtJTIyJTJDJTIyb3JkZXJlZCUyMiUzQWZhbHNlJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyRmVhdHVyZSUyMHNjYWxpbmclMjAobm9ybWFsaXplZCUyMGZlYXR1cmVzJTIwaW4lMjBleHBlY3RlZCUyMHJhbmdlKSUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJsaXN0SXRlbSUyMiUyQyUyMm9yZGVyZWQlMjIlM0FmYWxzZSUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMlRlbXBvcmFsJTIwZnJlc2huZXNzJTIwKGRhdGElMjBpcyUyMHJlY2VudCklMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIybGlzdEl0ZW0lMjIlMkMlMjJvcmRlcmVkJTIyJTNBZmFsc2UlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJCdXNpbmVzcyUyMGxvZ2ljJTIwKHJldmVudWUlMjBpcyUyMHBvc2l0aXZlKSUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJwJTIyJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIySWYlMjBhbnklMjBjaGVjayUyMGZhaWxzJTJDJTIwd2UlMjBibG9jayUyMHRoZSUyMHBpcGVsaW5lJTIwYW5kJTIwYWxlcnQlMjB0aGUlMjB0ZWFtLiUyMiU3RCU1RCU3RCU1RA==">
       <div data-slate-node="element">
        <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">If any check fails, we block the pipeline and alert the team.</span></span></span>
       </div>
       <h2 data-anchor="therealworldgotchaswediscovered" data-slate-node="element" data-slug="therealworldgotchaswediscovered54"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">The Real-World Gotchas We Discovered</span></span></span></h2>
       <h3 data-slate-node="element"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Gotcha 1: Validation Overhead</span></span></span></h3>
       <div data-slate-node="element">
        <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Running dbt tests, Great Expectations, and custom validation on every pipeline run adds latency. We went from 15-minute runs to 25-minute runs. The trade-off was worth it (catching one data quality issue saved us more time than we lost), but you need to plan for it.</span></span></span>
       </div>
       <h3 data-slate-node="element"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Gotcha 2: False Positives</span></span></span></h3>
       <div data-slate-node="element">
        <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Great Expectations' distribution shift detection is sensitive. Legitimate business changes (a marketing campaign causing a spike in <code>user_age</code> distribution) triggered false alerts. We had to tune thresholds carefully and add context to alerts.</span></span></span>
       </div>
       <h3 data-slate-node="element"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Gotcha 3: Schema Changes Are Sneaky</span></span></span></h3>
       <div data-slate-node="element">
        <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">A vendor added a new column to an upstream table. Our pipeline didn't break; it just ignored the new column. But the data science team expected it. We added schema validation to catch new columns and alert us.</span></span></span>
       </div>
       <div data-slate-fragment="JTVCJTdCJTIydHlwZSUyMiUzQSUyMmhlYWRpbmclMjIlMkMlMjJsZXZlbCUyMiUzQTIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJUaGUlMjBSZWFsLVdvcmxkJTIwR290Y2hhcyUyMFdlJTIwRGlzY292ZXJlZCUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJwJTIyJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyR290Y2hhJTIwMSUzQSUyMFZhbGlkYXRpb24lMjBPdmVyaGVhZCUyMiUyQyUyMmJvbGQlMjIlM0F0cnVlJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJpc0JyZWFrJTIyJTNBdHJ1ZSUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMiUyMiU3RCU1RCU3RCUyQyU3QiUyMnRleHQlMjIlM0ElMjJSdW5uaW5nJTIwZGJ0JTIwdGVzdHMlMkMlMjBHcmVhdCUyMEV4cGVjdGF0aW9ucyUyQyUyMGFuZCUyMGN1c3RvbSUyMHZhbGlkYXRpb24lMjBvbiUyMGV2ZXJ5JTIwcGlwZWxpbmUlMjBydW4lMjBhZGRzJTIwbGF0ZW5jeS4lMjBXZSUyMHdlbnQlMjBmcm9tJTIwMTUtbWludXRlJTIwcnVucyUyMHRvJTIwMjUtbWludXRlJTIwcnVucy4lMjBUaGUlMjB0cmFkZS1vZmYlMjB3YXMlMjB3b3J0aCUyMGl0JTIwKGNhdGNoaW5nJTIwb25lJTIwZGF0YSUyMHF1YWxpdHklMjBpc3N1ZSUyMHNhdmVkJTIwdXMlMjBtb3JlJTIwdGltZSUyMHRoYW4lMjB3ZSUyMGxvc3QpJTJDJTIwYnV0JTIweW91JTIwbmVlZCUyMHRvJTIwcGxhbiUyMGZvciUyMGl0LiUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJwJTIyJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyR290Y2hhJTIwMiUzQSUyMEZhbHNlJTIwUG9zaXRpdmVzJTIyJTJDJTIyYm9sZCUyMiUzQXRydWUlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIycCUyMiUyQyUyMmlzQnJlYWslMjIlM0F0cnVlJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyJTIyJTdEJTVEJTdEJTJDJTdCJTIydGV4dCUyMiUzQSUyMkdyZWF0JTIwRXhwZWN0YXRpb25zJyUyMGRpc3RyaWJ1dGlvbiUyMHNoaWZ0JTIwZGV0ZWN0aW9uJTIwaXMlMjBzZW5zaXRpdmUuJTIwTGVnaXRpbWF0ZSUyMGJ1c2luZXNzJTIwY2hhbmdlcyUyMChhJTIwbWFya2V0aW5nJTIwY2FtcGFpZ24lMjBjYXVzaW5nJTIwYSUyMHNwaWtlJTIwaW4lMjB1c2VyX2FnZSUyMGRpc3RyaWJ1dGlvbiklMjB0cmlnZ2VyZWQlMjBmYWxzZSUyMGFsZXJ0cy4lMjBXZSUyMGhhZCUyMHRvJTIwdHVuZSUyMHRocmVzaG9sZHMlMjBjYXJlZnVsbHklMjBhbmQlMjBhZGQlMjBjb250ZXh0JTIwdG8lMjBhbGVydHMuJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJHb3RjaGElMjAzJTNBJTIwU2NoZW1hJTIwQ2hhbmdlcyUyMEFyZSUyMFNuZWFreSUyMiUyQyUyMmJvbGQlMjIlM0F0cnVlJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJpc0JyZWFrJTIyJTNBdHJ1ZSUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMiUyMiU3RCU1RCU3RCUyQyU3QiUyMnRleHQlMjIlM0ElMjJBJTIwdmVuZG9yJTIwYWRkZWQlMjBhJTIwbmV3JTIwY29sdW1uJTIwdG8lMjBhbiUyMHVwc3RyZWFtJTIwdGFibGUuJTIwT3VyJTIwcGlwZWxpbmUlMjBkaWRuJ3QlMjBicmVhayVFMiU4MCU5NGl0JTIwanVzdCUyMGlnbm9yZWQlMjB0aGUlMjBuZXclMjBjb2x1bW4uJTIwQnV0JTIwdGhlJTIwZGF0YSUyMHNjaWVuY2UlMjB0ZWFtJTIwZXhwZWN0ZWQlMjBpdC4lMjBXZSUyMGFkZGVkJTIwc2NoZW1hJTIwdmFsaWRhdGlvbiUyMHRvJTIwY2F0Y2glMjBuZXclMjBjb2x1bW5zJTIwYW5kJTIwYWxlcnQlMjB1cy4lMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIycCUyMiUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMkdvdGNoYSUyMDQlM0ElMjBOdWxsJTIwSGFuZGxpbmclMjBWYXJpZXMlMjIlMkMlMjJib2xkJTIyJTNBdHJ1ZSU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJwJTIyJTJDJTIyaXNCcmVhayUyMiUzQXRydWUlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjIlMjIlN0QlNUQlN0QlMkMlN0IlMjJ0ZXh0JTIyJTNBJTIyUHl0aG9uJTIwdHJlYXRzJTIwbnVsbCUyMGFzJTIwTm9uZS4lMjBTUUwlMjB0cmVhdHMlMjBpdCUyMGFzJTIwTlVMTC4lMjBTcGFyayUyMHRyZWF0cyUyMGl0JTIwYXMlMjBudWxsLiUyMFdoZW4lMjBkYXRhJTIwZmxvd3MlMjBiZXR3ZWVuJTIwc3lzdGVtcyUyQyUyMG51bGxzJTIwZ2V0JTIwbG9zdCUyMG9yJTIwbWlzaW50ZXJwcmV0ZWQuJTIwV2UlMjBoYWQlMjB0byUyMHN0YW5kYXJkaXplJTIwbnVsbCUyMGhhbmRsaW5nJTIwYWNyb3NzJTIwdGhlJTIwZW50aXJlJTIwcGlwZWxpbmUuJTIyJTdEJTVEJTdEJTVE">
        <h3 data-slate-node="element"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Gotcha 4: Null Handling Varies</span></span></span></h3>
        <div data-slate-node="element">
         <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Python treats null as None. SQL treats it as NULL. Spark treats it as null. When data flows between systems, nulls get lost or misinterpreted. We had to standardize null handling across the entire pipeline.</span></span></span>
        </div>
        <h2 data-anchor="theframework%3Aadecisionmatrix" data-slate-node="element" data-slug="theframework%3Aadecisionmatrix60"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">The Framework: A Decision Matrix</span></span></span></h2>
        <div data-slate-fragment="JTVCJTdCJTIydHlwZSUyMiUzQSUyMmhlYWRpbmclMjIlMkMlMjJsZXZlbCUyMiUzQTIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJUaGUlMjBGcmFtZXdvcmslM0ElMjBBJTIwRGVjaXNpb24lMjBNYXRyaXglMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIycCUyMiUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMkhlcmUncyUyMGhvdyUyMHdlJTIwZGVjaWRlJTIwd2hpY2glMjB2YWxpZGF0aW9uJTIwbGF5ZXIlMjB0byUyMHVzZSUzQSUyMiU3RCU1RCU3RCU1RA==">
         <div data-slate-node="element">
          <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Here's how we decide which validation layer to use:</span></span></span>
         </div>
         <div class="table-responsive" style="border: none;">
          <table style="width: auto; max-width: 100%; table-layout: fixed; display: table;" width="auto">
           <tbody>
            <tr style="overflow-wrap: break-word; width: auto;" width="auto">
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Issue Type</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Caught By</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Example</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Action</td>
            </tr>
            <tr style="overflow-wrap: break-word; width: auto;" width="auto">
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Missing required field</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">dbt tests</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">user_id is null</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Fail pipeline immediately</td>
            </tr>
            <tr style="overflow-wrap: break-word; width: auto;" width="auto">
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Duplicate records</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">dbt tests</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Same user_id appears twice</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Fail pipeline immediately</td>
            </tr>
            <tr style="overflow-wrap: break-word; width: auto;" width="auto">
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Impossible values</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">dbt tests</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">event_timestamp in future</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Fail pipeline immediately</td>
            </tr>
            <tr style="overflow-wrap: break-word; width: auto;" width="auto">
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Out-of-range values</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Great Expectations</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">age &gt; 150</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Alert, investigate, fail if severe</td>
            </tr>
            <tr style="overflow-wrap: break-word; width: auto;" width="auto">
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Distribution shift</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Great Expectations</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">event_value mean changes 50%</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Alert, investigate, continue if acceptable</td>
            </tr>
            <tr style="overflow-wrap: break-word; width: auto;" width="auto">
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Business logic violation</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Custom validation</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">revenue is negative</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Alert, investigate, fail</td>
            </tr>
            <tr style="overflow-wrap: break-word; width: auto;" width="auto">
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Schema change</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Custom validation</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">New column added upstream</td>
             <td style="width: auto; overflow-wrap: break-word;" width="auto">Alert, investigate, update tests</td>
            </tr>
           </tbody>
          </table>
         </div>
         <h2 data-anchor="theresults%3Afromchaostoconfidence" data-slate-node="element" data-slug="theresults%3Afromchaostoconfidence64"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">The Results: From Chaos to Confidence</span></span></span></h2>
         <div data-slate-node="element">
          <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">After implementing this three-layer framework:</span></span></span>
         </div>
         <ul>
          <li><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Incident reduction:</span></span></span><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">&nbsp;We went from 2-3 data quality incidents per month to 0 in six months.</span></span></span></li>
          <li><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Time to resolution:</span></span></span><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">&nbsp;When issues do occur, we catch them within minutes instead of hours.</span></span></span></li>
          <li><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Model stability:</span></span></span><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">&nbsp;Model accuracy stopped fluctuating. It's now consistently 93-95%.</span></span></span></li>
          <li><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Team confidence:</span></span></span><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">&nbsp;Data scientists trust the data. Engineers trust the pipeline.</span></span></span></li>
         </ul>
         <div data-slate-fragment="JTVCJTdCJTIydHlwZSUyMiUzQSUyMmhlYWRpbmclMjIlMkMlMjJsZXZlbCUyMiUzQTIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJUaGUlMjBSZXN1bHRzJTNBJTIwRnJvbSUyMENoYW9zJTIwdG8lMjBDb25maWRlbmNlJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJBZnRlciUyMGltcGxlbWVudGluZyUyMHRoaXMlMjB0aHJlZS1sYXllciUyMGZyYW1ld29yayUzQSUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJsaXN0SXRlbSUyMiUyQyUyMm9yZGVyZWQlMjIlM0FmYWxzZSUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMkluY2lkZW50JTIwcmVkdWN0aW9uJTNBJTIyJTJDJTIyYm9sZCUyMiUzQXRydWUlN0QlMkMlN0IlMjJ0ZXh0JTIyJTNBJTIyJTIwV2UlMjB3ZW50JTIwZnJvbSUyMDItMyUyMGRhdGElMjBxdWFsaXR5JTIwaW5jaWRlbnRzJTIwcGVyJTIwbW9udGglMjB0byUyMDAlMjBpbiUyMHNpeCUyMG1vbnRocyUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJsaXN0SXRlbSUyMiUyQyUyMm9yZGVyZWQlMjIlM0FmYWxzZSUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMlRpbWUlMjB0byUyMHJlc29sdXRpb24lM0ElMjIlMkMlMjJib2xkJTIyJTNBdHJ1ZSU3RCUyQyU3QiUyMnRleHQlMjIlM0ElMjIlMjBXaGVuJTIwaXNzdWVzJTIwZG8lMjBvY2N1ciUyQyUyMHdlJTIwY2F0Y2glMjB0aGVtJTIwd2l0aGluJTIwbWludXRlcyUyMGluc3RlYWQlMjBvZiUyMGhvdXJzJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMmxpc3RJdGVtJTIyJTJDJTIyb3JkZXJlZCUyMiUzQWZhbHNlJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyTW9kZWwlMjBzdGFiaWxpdHklM0ElMjIlMkMlMjJib2xkJTIyJTNBdHJ1ZSU3RCUyQyU3QiUyMnRleHQlMjIlM0ElMjIlMjBNb2RlbCUyMGFjY3VyYWN5JTIwc3RvcHBlZCUyMGZsdWN0dWF0aW5nLiUyMEl0J3MlMjBub3clMjBjb25zaXN0ZW50bHklMjA5My05NSUyNSUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJsaXN0SXRlbSUyMiUyQyUyMm9yZGVyZWQlMjIlM0FmYWxzZSUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMlRlYW0lMjBjb25maWRlbmNlJTNBJTIyJTJDJTIyYm9sZCUyMiUzQXRydWUlN0QlMkMlN0IlMjJ0ZXh0JTIyJTNBJTIyJTIwRGF0YSUyMHNjaWVudGlzdHMlMjB0cnVzdCUyMHRoZSUyMGRhdGEuJTIwRW5naW5lZXJzJTIwdHJ1c3QlMjB0aGUlMjBwaXBlbGluZSUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJwJTIyJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyVGhlJTIwYmVzdCUyMHBhcnQlM0YlMjBXZSUyMGNhdWdodCUyMHRoZSUyMHNjaGVtYSUyMGNoYW5nZSUyMGluY2lkZW50JTIwYmVmb3JlJTIwaXQlMjBoYXBwZW5lZC4lMjBHcmVhdCUyMEV4cGVjdGF0aW9ucyUyMGRldGVjdGVkJTIwdGhlJTIwZGlzdHJpYnV0aW9uJTIwc2hpZnQlMkMlMjB3ZSUyMGludmVzdGlnYXRlZCUyQyUyMGZvdW5kJTIwdGhlJTIwdXBzdHJlYW0lMjBjaGFuZ2UlMkMlMjBhbmQlMjBjb29yZGluYXRlZCUyMHdpdGglMjB0aGUlMjB2ZW5kb3IlMjB0ZWFtJTIwYmVmb3JlJTIwYW55JTIwZGF0YSUyMHJlYWNoZWQlMjBwcm9kdWN0aW9uLiUyMiU3RCU1RCU3RCU1RA==">
          <div data-slate-node="element">
           <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">The best part? We caught the schema change incident before it happened. Great Expectations detected the distribution shift, we investigated, found the upstream change, and coordinated with the vendor team before any data reached production.</span></span></span>
          </div>
          <h2 data-anchor="gettingstarted%3Atheminimalviableobservability" data-slate-node="element" data-slug="gettingstarted%3Atheminimalviableobservability72"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Getting Started: The Minimal Viable Observability</span></span></span></h2>
          <div data-slate-node="element">
           <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">You don't need to implement everything at once. Start here:</span></span></span>
          </div>
          <ol>
           <li><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Week 1:</span></span></span><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">&nbsp;Add dbt tests for not_null and unique on critical columns.</span></span></span></li>
           <li><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Week 1:</span></span></span><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">&nbsp;Add dbt tests for not_null and unique on critical columns.</span></span></span></li>
           <li><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Week 1:</span></span></span><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">&nbsp;Add dbt tests for not_null and unique on critical columns.</span></span></span></span></span></span></li>
           <li><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Week 4:</span></span></span><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">&nbsp;Set up alerting so you're notified when validations fail.</span></span></span></span></span></span></span></span></span></li>
          </ol>
          <div data-slate-fragment="JTVCJTdCJTIydHlwZSUyMiUzQSUyMmhlYWRpbmclMjIlMkMlMjJsZXZlbCUyMiUzQTIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJHZXR0aW5nJTIwU3RhcnRlZCUzQSUyMFRoZSUyME1pbmltYWwlMjBWaWFibGUlMjBPYnNlcnZhYmlsaXR5JTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJZb3UlMjBkb24ndCUyMG5lZWQlMjB0byUyMGltcGxlbWVudCUyMGV2ZXJ5dGhpbmclMjBhdCUyMG9uY2UuJTIwU3RhcnQlMjBoZXJlJTNBJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMmxpc3RJdGVtJTIyJTJDJTIyb3JkZXJlZCUyMiUzQXRydWUlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJXZWVrJTIwMSUzQSUyMiUyQyUyMmJvbGQlMjIlM0F0cnVlJTdEJTJDJTdCJTIydGV4dCUyMiUzQSUyMiUyMEFkZCUyMGRidCUyMHRlc3RzJTIwZm9yJTIwbm90X251bGwlMjBhbmQlMjB1bmlxdWUlMjBvbiUyMGNyaXRpY2FsJTIwY29sdW1ucyUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJsaXN0SXRlbSUyMiUyQyUyMm9yZGVyZWQlMjIlM0F0cnVlJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyV2VlayUyMDIlM0ElMjIlMkMlMjJib2xkJTIyJTNBdHJ1ZSU3RCUyQyU3QiUyMnRleHQlMjIlM0ElMjIlMjBBZGQlMjBHcmVhdCUyMEV4cGVjdGF0aW9ucyUyMGZvciUyMHZhbHVlJTIwcmFuZ2VzJTIwb24lMjBudW1lcmljJTIwY29sdW1ucyUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJsaXN0SXRlbSUyMiUyQyUyMm9yZGVyZWQlMjIlM0F0cnVlJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyV2VlayUyMDMlM0ElMjIlMkMlMjJib2xkJTIyJTNBdHJ1ZSU3RCUyQyU3QiUyMnRleHQlMjIlM0ElMjIlMjBBZGQlMjBjdXN0b20lMjB2YWxpZGF0aW9uJTIwZm9yJTIweW91ciUyMHNwZWNpZmljJTIwYnVzaW5lc3MlMjBsb2dpYyUyMiU3RCU1RCU3RCUyQyU3QiUyMnR5cGUlMjIlM0ElMjJsaXN0SXRlbSUyMiUyQyUyMm9yZGVyZWQlMjIlM0F0cnVlJTJDJTIyY2hpbGRyZW4lMjIlM0ElNUIlN0IlMjJ0ZXh0JTIyJTNBJTIyV2VlayUyMDQlM0ElMjIlMkMlMjJib2xkJTIyJTNBdHJ1ZSU3RCUyQyU3QiUyMnRleHQlMjIlM0ElMjIlMjBTZXQlMjB1cCUyMGFsZXJ0aW5nJTIwc28lMjB5b3UncmUlMjBub3RpZmllZCUyMHdoZW4lMjB2YWxpZGF0aW9ucyUyMGZhaWwlMjIlN0QlNUQlN0QlMkMlN0IlMjJ0eXBlJTIyJTNBJTIycCUyMiUyQyUyMmNoaWxkcmVuJTIyJTNBJTVCJTdCJTIydGV4dCUyMiUzQSUyMlRoYXQncyUyMGl0LiUyMFlvdSUyMG5vdyUyMGhhdmUlMjBvYnNlcnZhYmlsaXR5JTIwaW4lMjB5b3VyJTIwZGF0YSUyMHBpcGVsaW5lLiUyMiU3RCU1RCU3RCU1RA==">
           <div data-slate-node="element">
            <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">That's it. You now have observability in your data pipeline.</span></span></span>
           </div>
          </div>
         </div>
         <h2 data-anchor="conclusion%3Aobservabilitysavesmodels" data-slate-node="element" data-slug="conclusion%3Aobservabilitysavesmodels80"><span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Conclusion: Observability Saves Models</span></span></span></h2>
         <div data-slate-node="element">
          <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Your AI model isn't failing because it's bad. It's failing because the data feeding it is bad. And you won't know the data is bad until you look.</span></span></span>
         </div>
         <div data-slate-node="element">
          <br>
         </div>
         <div data-slate-node="element">
          <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">The best models in the world can't save you from garbage data. But good observability can. dbt tests, Great Expectations, and custom validation aren't fun. They don't make it into conference talks. But they'll save your production system at 3:00 AM.</span></span></span>
         </div>
         <div data-slate-fragment="JTVCJTdCJTIydHlwZSUyMiUzQSUyMmhlYWRpbmclMjIlMkMlMjJsZXZlbCUyMiUzQTIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJDb25jbHVzaW9uJTNBJTIwT2JzZXJ2YWJpbGl0eSUyMFNhdmVzJTIwTW9kZWxzJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJZb3VyJTIwQUklMjBtb2RlbCUyMGlzbid0JTIwZmFpbGluZyUyMGJlY2F1c2UlMjBpdCdzJTIwYmFkLiUyMEl0J3MlMjBmYWlsaW5nJTIwYmVjYXVzZSUyMHRoZSUyMGRhdGElMjBmZWVkaW5nJTIwaXQlMjBpcyUyMGJhZC4lMjBBbmQlMjB5b3UlMjB3b24ndCUyMGtub3clMjB0aGUlMjBkYXRhJTIwaXMlMjBiYWQlMjB1bnRpbCUyMHlvdSUyMGxvb2suJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJUaGUlMjBiZXN0JTIwbW9kZWxzJTIwaW4lMjB0aGUlMjB3b3JsZCUyMGNhbid0JTIwc2F2ZSUyMHlvdSUyMGZyb20lMjBnYXJiYWdlJTIwZGF0YS4lMjBCdXQlMjBnb29kJTIwb2JzZXJ2YWJpbGl0eSUyMGNhbi4lMjBkYnQlMjB0ZXN0cyUyQyUyMEdyZWF0JTIwRXhwZWN0YXRpb25zJTJDJTIwYW5kJTIwY3VzdG9tJTIwdmFsaWRhdGlvbiUyMGFyZW4ndCUyMHNleHkuJTIwVGhleSUyMGRvbid0JTIwbWFrZSUyMGl0JTIwaW50byUyMGNvbmZlcmVuY2UlMjB0YWxrcy4lMjBCdXQlMjB0aGV5J2xsJTIwc2F2ZSUyMHlvdXIlMjBwcm9kdWN0aW9uJTIwc3lzdGVtJTIwYXQlMjAzJTIwQU0uJTIyJTdEJTVEJTdEJTJDJTdCJTIydHlwZSUyMiUzQSUyMnAlMjIlMkMlMjJjaGlsZHJlbiUyMiUzQSU1QiU3QiUyMnRleHQlMjIlM0ElMjJTdGFydCUyMHNtYWxsLiUyMFRlc3QlMjBlYXJseS4lMjBWYWxpZGF0ZSUyMG9mdGVuLiUyMiU3RCU1RCU3RCU1RA==">
          <div data-slate-node="element">
           <br>
          </div>
          <div data-slate-node="element">
           <span data-slate-node="text"><span data-slate-leaf="true"><span data-slate-string="true">Start small. Test early. Validate often.</span></span></span>
          </div>
         </div>
        </div>
       </div>
      </div>
     </div>
    </div>
   </div>
  </div>
 </div>
</div></p><img src="https://feeds.dzone.com/link/23568/17368711.gif" height="1" width="1"/>]]></description>
      <pubDate>Fri, 26 Jun 2026 16:00:05 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3643570</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19061479&amp;w=600"/>
      <dc:creator>Abhilash Rao Mesala</dc:creator>
    </item>
    <item>
      <title>A Tool Is Not a Platform (And Your Team Knows the Difference)</title>
      <link>https://feeds.dzone.com/link/23568/17367991/a-tool-is-not-a-platform</link>
      <description><![CDATA[<p>Most infrastructure teams have a moment where someone says “we should build a platform.” The motivation is real: teams are duplicating work, the current setup is hard to use consistently, and a more structured approach would help. A few months later, the platform is a Terraform module collection, a GitLab CI template, a shared repository of scripts, and a README that several people have tried to keep current.</p>
<p>That is a useful thing. It is not a platform.</p><img src="https://feeds.dzone.com/link/23568/17367991.gif" height="1" width="1"/>]]></description>
      <pubDate>Thu, 25 Jun 2026 19:00:05 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3653764</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19059920&amp;w=600"/>
      <dc:creator>Jeleel Muibi</dc:creator>
    </item>
    <item>
      <title>Implementing Asynchronous Communication Between Microservices Using Kafka and Spring Boot</title>
      <link>https://feeds.dzone.com/link/23568/17366594/asynchronous-microservices-communication-kafka-spring-boot</link>
      <description><![CDATA[<p>In a microservices system, that tight coupling turns a small hiccup into a cascading slowdown. Thread pools fill, retries amplify traffic, and suddenly your simple request is blocked on half the fleet. My executive summary: asynchronous messaging with Kafka helps systems keep moving when individual components inevitably slow down or fail. It does this by decoupling producers from consumers, absorbing traffic spikes, and allowing services to evolve without tying their availability directly to one another.</p>
<h2>Code Patterns in Spring Boot With Kafka</h2>
<p>Spring for Apache Kafka gives me two primitives that feel pleasantly old Spring <code>KafkaTemplate</code> for sending and <code>@KafkaListener</code> for receiving. That template/listener model is intentionally similar to other Spring integration tech, which keeps application code focused on domain logic instead of raw client plumbing.&nbsp;</p><img src="https://feeds.dzone.com/link/23568/17366594.gif" height="1" width="1"/>]]></description>
      <pubDate>Wed, 24 Jun 2026 13:00:05 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3643443</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19056287&amp;w=600"/>
      <dc:creator>Mallikharjuna Manepalli</dc:creator>
    </item>
    <item>
      <title>Architectural Collapse: How Extension Poisoning, Node Vulnerabilities, and Infrastructure Fog Enabled the GitHub Repository Breach</title>
      <link>https://feeds.dzone.com/link/23568/17366153/extension-poisoning-github-breach</link>
      <description><![CDATA[<p data-selectable-paragraph="">Enterprise perimeter defenses are fundamentally built on an obsolete assumption that the developer’s workstation is a secure, trusted anchor point. The massive security breach executed by the threat group <strong>TeamPCP</strong>, resulting in the exfiltration of <strong>3,800 internal GitHub source code repositories</strong>, completely shattered this illusion.</p>
<p data-selectable-paragraph="">This was not a standalone exploit. It was a multi-vector convergence where vulnerabilities in the Node/NPM ecosystem, the systemic ungoverned architecture of the Visual Studio Code Marketplace, and the tactical “fog of war” caused by a period of historic GitHub infrastructure instability came together to create the perfect attack.</p><img src="https://feeds.dzone.com/link/23568/17366153.gif" height="1" width="1"/>]]></description>
      <pubDate>Tue, 23 Jun 2026 19:00:00 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3655846</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19032602&amp;w=600"/>
      <dc:creator>Akash Lomas</dc:creator>
      <dc:creator>Akash Lomas</dc:creator>
    </item>
    <item>
      <title>Automating Power Automate: How to Ensure Cloud Flows Are Active After Every Pipeline Deployment</title>
      <link>https://feeds.dzone.com/link/23568/17364020/automating-power-automate-cloud-flows</link>
      <description><![CDATA[<p lang="EN-US"><span data-contrast="auto" lang="EN-US">You've spent hours — maybe days — building and testing a Dynamics 365 Power Platform solution. Your Azure DevOps pipeline runs clean. The managed solution imports successfully into the target environment. All green.</span><span data-ccp-props="{&quot;134233117&quot;:false,&quot;134233118&quot;:false,&quot;335551550&quot;:0,&quot;335551620&quot;:0,&quot;335559738&quot;:240,&quot;335559739&quot;:240}">&nbsp;</span></p>
<p lang="EN-US"><span data-contrast="auto" lang="EN-US">Then the business calls. Nothing is working. The&nbsp;automations aren't&nbsp;firing.</span><span data-ccp-props="{&quot;134233117&quot;:false,&quot;134233118&quot;:false,&quot;335551550&quot;:0,&quot;335551620&quot;:0,&quot;335559738&quot;:240,&quot;335559739&quot;:240}">&nbsp;</span></p><img src="https://feeds.dzone.com/link/23568/17364020.gif" height="1" width="1"/>]]></description>
      <pubDate>Fri, 19 Jun 2026 18:00:00 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3643558</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19054524&amp;w=600"/>
      <dc:creator>karthik nallani chakravartula</dc:creator>
    </item>
    <item>
      <title>Your AI Coding Agent Can't Steal What It Never Had: The Docker Sandbox Isolation Story</title>
      <link>https://feeds.dzone.com/link/23568/17363860/docker-sandbox-isolation-story</link>
      <description><![CDATA[<p>I ran an AI coding agent against a broken Kubernetes deployment for five minutes. The agent called Anthropic's API dozens of times — reasoning about manifests, running kubectl commands, redeploying workloads. It made fully authenticated requests throughout the entire session.</p>
<p>The API key was never in its environment.</p><img src="https://feeds.dzone.com/link/23568/17363860.gif" height="1" width="1"/>]]></description>
      <pubDate>Fri, 19 Jun 2026 13:00:00 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3659752</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19059379&amp;w=600"/>
      <dc:creator>Shamsher Khan</dc:creator>
    </item>
    <item>
      <title>Cutting Data Pipeline Costs and Data Freshness Issues With Netflix Maestro and Apache Iceberg: A Practical Tutorial</title>
      <link>https://feeds.dzone.com/link/23568/17362153/netflix-maestro-apache-iceberg</link>
      <description><![CDATA[<p>Analytics pipelines tend to scale in both cost and the age of their data sources: costs increase with data volume growth, while data freshness decreases due to longer batch jobs. The common approach, scaling out the cluster, addresses the symptom rather than the architectural issue.</p>
<p>In this tutorial, we will look at an alternative solution that addresses both problems at their root: using Netflix Maestro, a horizontally scalable workflow orchestrator open-sourced by Netflix in July 2024, along with Apache Iceberg, a standard table format for analytics on object storage. The former helps by shifting from time-based scheduling to event-driven, whereas the latter removes the overhead of listing files that slows down queries on large datasets and increases their costs.</p><img src="https://feeds.dzone.com/link/23568/17362153.gif" height="1" width="1"/>]]></description>
      <pubDate>Tue, 16 Jun 2026 16:00:01 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3534378</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19051306&amp;w=600"/>
      <dc:creator>Intiaz Shaik</dc:creator>
    </item>
    <item>
      <title>Getting Started With GitHub Copilot CLI for Coding Tasks</title>
      <link>https://feeds.dzone.com/link/23568/17362130/github-copilot-cli-coding-tasks</link>
      <description><![CDATA[<p>Nowadays, there are quite a lot of AI coding assistants. In this blog, you will take a closer look at GitHub Code CLI, a terminal-based AI coding assistant. GitHub Copilot CLI integrates smoothly with GitHub Copilot, so if you have a GitHub Copilot subscription, it is definitely worth looking at. Enjoy!</p>
<h2>Introduction</h2>
<p>There are many AI models and also many AI coding assistants. Which one to choose is a hard question. It also depends on whether you run the models locally or in the cloud. When running locally, Qwen3-Coder is a very good AI model to be used for programming tasks. In previous posts, <a href="https://mydeveloperplanet.com/2024/10/08/devoxxgenie-your-ai-assistant-for-idea/" rel="noopener noreferrer" target="_blank">DevoxxGenie</a>, a JetBrains IDE plugin, was often used as an AI coding assistant. DevoxxGenie is nicely integrated within the JetBrains IDE's. But it is also a good thing to take a look at other AI coding assistants. In previous blogs, <a href="https://mydeveloperplanet.com/2026/02/25/getting-started-with-qwen-code-for-coding-tasks/" rel="noopener noreferrer" target="_blank">Qwen Code</a> and <a href="https://mydeveloperplanet.com/2026/03/18/setting-up-claude-code-with-ollama-a-guide/" rel="noopener noreferrer" target="_blank">Claude Code</a> were used in combination with local models.</p><img src="https://feeds.dzone.com/link/23568/17362130.gif" height="1" width="1"/>]]></description>
      <pubDate>Tue, 16 Jun 2026 14:30:00 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3659567</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19050609&amp;w=600"/>
      <dc:creator>Gunter Rotsaert</dc:creator>
    </item>
    <item>
      <title>From ETL to Lakeflow: Shifting to a Declarative Data Paradigm</title>
      <link>https://feeds.dzone.com/link/23568/17361533/shifting-to-declarative-data-paradigm</link>
      <description><![CDATA[<p dir="ltr">If you've worked on a data platform for more than a few years, you've almost certainly built the same pipeline twice. First, the way the team wrote pipelines in 2019: a notebook here, a Python script there, an <a href="https://dzone.com/articles/airflow-dag-failure-detection-ai">Airflow DAG</a> to glue it all together, and a long document explaining the order things had to run in. Then the rewrite, two years later, when somebody quit, and nobody could remember why a particular task had a sleep(180) in it.&nbsp;</p>
<p dir="ltr">Lakeflow is Databricks' answer to that pattern, and the shift it's pushing for is bigger than the marketing makes it sound. It isn't a new orchestrator. It's a move from imperative pipelines, where you write the steps, to declarative pipelines, where you write the destination and let the engine figure out the steps. What follows is the practical version of that shift — what's actually different, where the gains are real, and how to migrate without ending up with a half-converted lakehouse.</p><img src="https://feeds.dzone.com/link/23568/17361533.gif" height="1" width="1"/>]]></description>
      <pubDate>Mon, 15 Jun 2026 15:00:00 GMT</pubDate>
      <guid isPermaLink="false">https://dzone.com/articles/3505797</guid>
      <media:thumbnail url="https://dz2cdn1.dzone.com/thumbnail?fid=19049183&amp;w=600"/>
      <dc:creator>Seshendranath Balla Venkata</dc:creator>
    </item>
  </channel>
</rss>
