← Back to Publications

From Notebook to Platform Pipeline

Taking Exploratory Code to Production — Without Rewriting the Logic

A notebook proves an idea. A platform runs it every night, on schedule, for the business. The gap between "works on my laptop" and "runs on Microsoft Fabric / Snowflake / Databricks / BigQuery" is where a lot of good analytics work quietly dies. The encouraging part: closing that gap is a pattern, not a product. The same five moves take an exploratory notebook — or a Python library like the Data Analytics Library — into a production pipeline, and only the final runner changes from platform to platform. This is the piece that ties the Learn the Pattern series to real, shippable code.

Same logic, productionized — only the runner changes Notebook exploratory cells Modularize cells → functions Parameterize no hard-coded paths Package pin deps · importable Orchestrate platform scheduler

Five moves carry the same logic from a notebook to a scheduled platform pipeline; the runner on the right is the only platform-specific part.

1. Modularize — Cells Become Functions

A notebook is a script with hidden state: cell 12 depends on cell 4 having been run, and re-running out of order breaks it. The first move is to lift the logic into functions and modules — each one taking inputs and returning outputs, with no reliance on global notebook state. This is exactly the shape the Data Analytics Library is built around: every stage is DataFrame-in, DataFrame-out, so stages chain into a pipeline and each is independently testable.

Python · before (notebook cell) → after (module function)

# BEFORE — a notebook cell that mutates a global and hard-codes a path
df = pd.read_csv("/Users/mario/Downloads/orders_2026.csv")
df = df.dropna()
df["sales"] = df["quantity"] * df["unit_price"]

# AFTER — a pure function in a module (pipeline/transform.py)
def add_sales(orders: pd.DataFrame) -> pd.DataFrame:
    """Derive the sales column. Non-mutating: returns a new frame."""
    out = orders.copy()
    out["sales"] = out["quantity"] * out["unit_price"]
    return out

2. Parameterize — Nothing Hard-Coded

Production code can't carry /Users/mario/Downloads, a fixed date, or a password in plain text. Lift every environment-specific value into parameters — read paths and dates from arguments or config, and pull secrets from the platform's secret store, never the source. The same function then runs against a laptop CSV or a cloud table by changing inputs, not code.

Python · parameterized entry point

import os, argparse

def run(source_uri: str, run_date: str) -> None:
    secret = os.environ["WAREHOUSE_TOKEN"]   # from the platform's secret store
    orders = load(source_uri)                # path/URI is an argument, not a constant
    result = build_pipeline(orders, as_of=run_date)
    write(result, destination=os.environ["OUTPUT_TABLE"])

if __name__ == "__main__":
    p = argparse.ArgumentParser()
    p.add_argument("--source", required=True)
    p.add_argument("--run-date", required=True)
    args = p.parse_args()
    run(args.source, args.run_date)

3. Package — Pin Dependencies, Make It Importable

"It worked yesterday" usually means a dependency moved. Turn the modules into an installable package with pinned versions so the same code resolves to the same libraries everywhere. A pyproject.toml with version constraints, an importable package, and a test suite (the library ships 81 pytest tests on CI) is what lets a platform install and run your code unattended.

Python · pinned, importable

# pyproject.toml (excerpt) — pin the ranges you tested against
# dependencies = ["pandas>=2.0,<3.0", "scikit-learn>=1.3,<2.0"]

# On the platform, install and import — no copy-paste of cells
# pip install data-analytics-library==1.0.0
from analytics import predictiveanalysis as pa
model = pa.train(features, target)

4. Orchestrate — Wrap It in the Platform's Scheduler

The last move hands the packaged code to a scheduler that runs the steps in order, on a cadence, with retries and alerting. Model the work as a DAG (a flow of dependent tasks), point the scheduler at your parameterized entry point, and the pipeline becomes hands-off. This is the only step that is genuinely platform-specific — and even here the concept (a scheduled DAG of tasks) is identical everywhere.

5. Same Logic, Every Platform

The Python you wrote in steps 1–3 does not change between platforms. Only the storage it reads, the engine it runs on, and the scheduler that triggers it differ — and each maps cleanly:

The Piece Snowflake Databricks BigQuery Microsoft Fabric
Storage Tables · stages Delta on cloud storage BigQuery tables · GCS OneLake
Run the Python Snowpark · Python worksheets Notebooks / jobs on clusters BigQuery DataFrames · Dataproc / Cloud Run Spark / Python notebooks
Orchestrate Tasks & Streams Jobs / Workflows Cloud Composer (Airflow) · scheduled queries Data Factory pipelines
Secrets & params Secret objects · parameters Secret scopes · widgets Secret Manager Key Vault · pipeline parameters

Feature names evolve — treat this as a capability map and confirm specifics against current vendor docs before relying on them.

Tools Commonly Used

Best Practices

Example: The Descriptive Pipeline, Productionized

The companion notebook from the Descriptive Analytics series runs ten steps end to end. Productionizing it is exactly this pattern: lift each step into a library function (collect → clean → transform → … → share), parameterize the source and run-date, pin the dependencies, and schedule the entry point on whichever platform owns the data. The notebook that proved the idea and the pipeline that runs it nightly share the same logic — which is the whole point of learning the pattern, not the product.

← Back to Publications