Modern Data Workflows - Explained

workflow Mar 06, 2024

A modern data workflow is the day to day process a data team follows to get a change into production: separate environments, logic kept in code under version control, a branch per developer, and automated checks before anything goes live. The older approach is to edit a stored procedure in the database and have it take effect the moment you save, with no testing beyond whatever the developer did on their own. The modern approach keeps the logic in a tool like dbt, backed up on GitHub, so every change is visible line by line and goes through a pull request before it merges. Each developer builds into their own schema, a QA schema tests the merge, and production is refreshed from the main code every day. The result is production data that stays safe and quality checked without slowing anyone down.

Key takeaways

  • Modern data engineering is about more than tools. The team workflow around them is what keeps production stable.
  • Saving straight to a production database, stored procedure style, means no branch, no diff and no automated test between a developer and your stakeholders.
  • Keep the transformation logic in code in a project, like dbt backed by GitHub, so every change is a branch you can review line by line.
  • Each developer gets a separate schema. They select from the same production raw data but write their transformed results somewhere safe.
  • A pull request deploys the change to a QA or UAT schema for automated tests and peer review before it merges to main.
  • Storing dev and QA copies costs a little more. It's worth it, and you can limit the data to a subset if you need to.

Why workflow matters

Picture a simple architecture. Batch loads move data in, and somewhere in the middle there's transformation. For many teams that transformation means changes made directly in the database. Some stored procedures, a few edits, save.

The moment you save, it's production. It's live. The only testing that happened is whatever that developer did on their own, and none of it was automated.

I'll admit those can be fun times, and it feels like you can execute incredibly fast. It comes at the cost of quality and unnecessary errors.

The modern alternative

With the modern approach, and this is more than a tooling choice, the logic lives in code in a project. You can open the repository and read exactly what the code is.

When somebody wants to push a change, it's not a direct save. They create a branch, check out their own development version of the code, and test it there. You see every change line by line, and you can put automated testing in front of production.

It's a completely different way of thinking about the work. It catches errors early and protects the long term stability of the project.

The design and process

Let's say the whole thing runs on Snowflake, transformation is dbt, and the code is backed up on GitHub. How do we test changes along the way?

Production

Start with the production version of everything. For simplicity that's staging, warehouse and marts schemas, all in one database.

All of the code behind that logic is stored in the GitHub repository. The main branch is the live version of it.

A developer's side version

If you want to make changes, you create your own development version of the code on a branch. Done correctly, you also set up a separate database schema to test those changes in.

The goal is a safe space. Nothing stops you from selecting from the production raw data, since that's only a read. It's the transformed results that land in your own schema, so nothing in production is overridden.

Now imagine four developers. Each has their own branch and their own schema, working separately.

The pull request and QA

At some point you want that work in the main version. You open a pull request, or a merge request depending on the platform, through your version control tool.

That triggers a build into a separate schema or database called QA, or UAT, or whatever you name it. It takes the changes you're trying to move forward and tests them there, automatically.

So the flow for a change is:

  1. A developer gets the code and makes changes on a branch.
  2. They build into their own dev schema.
  3. They push the branch and open a pull request.
  4. Automated tests run against the QA schema and a teammate reviews the code.
  5. Once it's good to go, it merges to main and deploys to production.

All of that happens behind the scenes to keep production safe, quality checked, and free of accidental saves.

Living below the surface

One more way to see it. The pipeline runs across Snowflake, dbt and GitHub. Dev and QA live underneath production, still reading the same raw data, because dbt only selects and creates new results. Nothing upstream is inserted or deleted.

On GitHub that shows up as several branches, three in my example, with pull requests and automation in place to validate code and keep the team on good practices.

What it looks like in Snowflake

Here's a sample Snowflake environment. In an analytics database there's the raw data, then staging, warehouse and marts. Those three are the production schemas.

The developer schemas

Behind the scenes a developer, say me or someone named John Doe, has separate schemas. Same source, deployed separately.

It can feel redundant to store that data twice. Storage isn't the cost it once was, so it's usually not a big deal, and you can limit the scope to a subset of the data if you don't need all of it.

The tradeoff is a bit more storage in dev and QA for a lot more confidence. That beats going straight to production and having stakeholders find the errors.

From dev to QA to production

You change the code and deploy only to your dev schema. In GitHub you open a pull request to merge into main. It's automatically checked and deployed to the QA, UAT or CI schema, whichever name you use. The naming isn't the important part.

That schema takes the changes from your branch, deploys them, and tests them. Only then do you merge to production.

From that point the production code is updated, and every daily run of staging, warehouse and marts is based on the code you tested.

Where to start

You don't have to adopt all of this at once. Some teams need to introduce the whole workflow. Others already have most of it and only need to tweak one or two areas.

Three areas to check

  • Environments. Does every developer have a schema that isn't production, and is there a QA schema in between? If changes still save straight to the live tables, start here.
  • Automated checks. Does opening a pull request build and test the change somewhere, or does that depend on someone remembering to do it?
  • Naming conventions. With the same models existing in dev, QA and production, can you tell at a glance which schema is which and whose it is?

Pick the piece that's missing from your current process and add that first. For most teams it's a dev schema or an automated check on pull requests, and either one is a quick win.

Key terms

Modern data workflow

The process of environments, version control, branches and automated checks that moves a change into production without editing production directly.

Development schema

A per-developer schema that reads the same raw data as production but stores transformed results separately.

Pull request

A request through the version control platform to merge a branch into main. It triggers the automated build and the peer review.

QA environment

The schema or database, also called UAT or CI, where a pull request's changes are deployed and tested before they merge.

Stored procedure workflow

The older pattern of editing logic directly in the database so a change goes live the moment it is saved.

Common questions

What is a modern data workflow?

It's the process a team uses to move a change into production safely: logic in code, a branch and schema per developer, a QA step on pull requests, and production deployed from the main branch. It applies to any stack, though dbt, GitHub and Snowflake are a common combination.

Why not just edit the database directly?

Because the change is live the moment you save, with no record of what changed and no automated test. Keeping the logic in a project means every change is a branch you can review line by line and test before it reaches production.

Do developers need their own copy of the data?

They need their own copy of the transformed results, not the raw data. Dev schemas read the same production raw data and write their outputs separately. Storage is cheap enough that this is rarely a problem, and you can limit dev builds to a subset.

What is a QA or UAT environment in a data pipeline?

It's a separate schema or database where a pull request's changes are built and tested automatically before they merge. Teams call it QA, UAT, CI or test. The name doesn't matter, the extra check between development and production does.

How does dbt fit into this workflow?

dbt holds the transformation logic as code, which is what makes branches, diffs and automated tests possible. Because dbt only selects from sources and creates new tables, dev and QA builds can read production raw data without changing it.

Related reading

Final takeaway

Most of the teams I work with arrive with the tools already in place and the workflow missing. Separate schemas for development, a pull request that builds to QA, and a main branch that deploys production are what I set up first, because they protect everything else.

 

Additional Free Resources

Starter Guides & Checklists

Explore additional free resources built on the same patterns I use with real clients so you can build your own with structure and confidence. Topics include data architecture, modeling and more specifically for small data teams.

Browse Resources