Skip to main content
  1. writings/
  2. AI-Assisted Data Engineering/

Declarative Pipelines Are Easier to Assist

·6 mins·
Table of Contents

Introduction
#

AI agents work best when the system they are helping with is legible. Declarative pipelines make the desired result visible in one place, which gives both the agent and the human reviewer a better surface to reason over than a scattered chain of tasks, schedules, and merge scripts.

That is why this chapter is not really about any one warehouse feature. Dynamic tables are the example I know best, but the durable lesson is broader. The more your pipeline says what result should exist and how fresh it should be, the more useful an agent becomes. The more your pipeline hides intent inside imperative machinery, the more the agent has to guess.

Imperative Pipelines Hide the Intent
#

I spent years maintaining the imperative version of this work. Raw records landed first, scheduled tasks ran on fixed intervals, custom merge statements updated downstream tables, and parent-child task links tried to force the right order. It worked, but the logic of the pipeline was spread across too many places. To understand one output, I had to read the table definition, the merge statement, the task schedule, the dependency chain, and the operational history.

That layout is awkward for humans and awkward for agents for the same reason. The intent is not local. An agent can read the SQL, but the SQL alone does not explain when it runs, what upstream state it expects, or why the schedule is shaped the way it is. It can read the task graph, but the task graph does not explain the business freshness requirement. The pipeline contains the answer, but it is smeared across machinery.

This is where AI assistance can make a fragile system look more manageable than it really is. The agent can draft another task, another merge, another dependency, or another retry rule, and the output will seem competent. But if the underlying design keeps intent scattered, the agent is helping you maintain a maze. Sometimes the better assisted move is to ask what code can disappear.

Declaration Gives the Agent a Better Surface
#

A declarative pipeline changes the review surface. Instead of telling the system exactly when to run and how to merge, you define the destination as a query and state the freshness target. The platform owns more of the scheduling and dependency management, and the repository carries more of the intent in one place.

create or replace dynamic table reporting_orders
  target_lag = '1 hour'
  warehouse = standard_wh
  refresh_mode = incremental
  as
    select
        orders.order_id,
        orders.customer_id,
        segments.segment,
        orders.order_total
    from raw_orders as orders
    left join customer_segments as segments
        on orders.customer_id = segments.customer_id;

The example is small, but the difference is important. A reviewer can see the output layout, the dependency on the two upstream objects, the warehouse, the refresh mode, and the freshness target together. The agent can see the same thing. That shared surface makes better questions possible. Does one hour match the business need? Is incremental refresh appropriate for this query? Which downstream objects inherit this lag? What old tasks and merge scripts become redundant?

This does not mean declarative objects remove judgment. They move judgment to a better place. I still have to decide how fresh is fresh enough, what cost that freshness is worth, and whether the platform behavior matches the reliability requirements of the product. The agent can reason over those choices only because the choices are now visible enough to discuss.

Migration as Structured Translation
#

The strongest agent use case here is migration. Moving from imperative orchestration to declarative materialization is not pure invention. It is a structured translation from scattered procedure into explicit definitions. The agent can read the old task chain, extract the intended outputs, draft the new declarative objects, and list the old machinery that should be removed after validation.

That last part matters. The value is not only that a dynamic table or similar object exists. The value is that tasks, schedules, and hand-written merge scripts can go away. Deleting operational code is a real engineering win, because every deleted path is one fewer place for drift, stale assumptions, and silent failure to live.

I do not want the agent to perform that migration as a blind rewrite. I want it to produce a mapping. Old task to new object. Old merge predicate to new query logic. Old schedule to new freshness target. Old dependency chain to new model dependency. Old monitor to new refresh-history check. When the work is expressed that way, I can review the migration as a set of claims instead of a pile of generated SQL.

Validate the Contract, Not the Vibe
#

Declarative systems can create a comforting feeling that the platform has everything handled. That feeling is not validation. The contract still has to be checked in the three places that matter most, freshness, correctness, and cost.

Freshness comes first because it is the promise the declarative object makes. If the target lag says one hour, I need to confirm the refresh history actually meets that target under real load, not only in the happy path after creation. Correctness matters even more. A fresh table that translates the old merge logic incorrectly is worse than the rigid system it replaced. The comparison against the old output needs to be boring, row counts, key counts, totals, null behavior, and representative row-level samples.

Cost is the part the agent can help analyze but cannot decide for me. A tight freshness target feels impressive until it buys compute nobody needed. I want the agent to read refresh history, summarize patterns, identify objects that refresh more often than the business requirement demands, and propose looser targets where the evidence supports it. I still own the call, because “fresh enough” is a product and business decision, not a syntax decision.

Putting It Into Practice
#

  1. Prefer pipelines where intent is visible in definitions rather than scattered across tasks, schedules, and merge scripts.
  2. Use declarative materialization to give both the agent and the reviewer a cleaner surface to reason over.
  3. Ask the agent to map old imperative machinery to new declarative objects before accepting generated SQL.
  4. Delete the tasks, schedules, and merge scripts that the declarative design truly replaces.
  5. Keep the freshness, refresh-mode, cost, and reliability decisions with the human reviewer.
  6. Validate freshness against refresh history, correctness against the old output, and cost against real usage.
  7. Treat declarative pipelines as easier to assist because they make intent reviewable, not because they make judgment unnecessary.

Related