Monday's standup starts with a familiar question: why does the marketing dashboard show 1.4 million active customers while finance reports 980,000? Both teams query the same warehouse. The pipelines are green. The SQL runs. Yet the business is arguing about which number is real.
The root cause is often modeling drift, not ingestion failure. One team defines an active customer by a recent session, another uses a completed transaction, and neither definition is governed as a shared business concept. The result is rework, broken handoffs, disputed dashboards, and less confidence in every downstream product.
Modern data modeling best practices have to address more than tables and joins. A model may feed BI, reverse ETL, feature stores, operational workflows, retrieval systems, and agents at the same time. Treating it as a data product with consumers, interfaces, ownership, service expectations, and a lifecycle is the discipline that keeps those uses aligned.
Why a Disciplined Model Still Pays Off
The customer-count conflict becomes expensive quickly. Analysts rebuild queries to reconcile definitions, engineers add patches to dashboards, finance delays reporting, and executives stop trusting metrics that should be routine. The warehouse hasn't necessarily lost data. It has lost a shared interpretation of the data.
A disciplined model prevents that failure by making three decisions visible: who owns the entity, what each row represents, and which definition applies. A customer table needs an explicit grain. A customer-order relationship needs a documented cardinality. An “active” flag needs a business definition that marketing, finance, product, and machine-learning teams can use consistently.
Practical rule: If two teams can produce different answers from the same entity without either team violating a documented contract, the model is underspecified.
The payoff appears in daily engineering work. New analysts can start from an understandable diagram instead of reverse-engineering a maze of views. Upstream changes are easier to absorb when raw, standardized, and curated layers have clear responsibilities. Data scientists receive cleaner inputs for feature stores because keys, history, and definitions don't change unexpectedly between training and serving.
Design for every consumer
The same customer model may support a retention dashboard, a sales-alert workflow, a reverse-ETL audience, and an agent answering account questions. Those consumers don't need identical physical tables, but they do need compatible semantics. A dashboard might need a conformed customer dimension, while an agent needs a governed semantic layer with clear descriptions, permitted joins, and freshness expectations.
Enterprise modeling has moved toward governance, reusability, shared definitions, and alignment with business meaning, rather than table design alone, as described in guidance on enterprise data modeling for AI. That shift matters because a model consumed by machines needs an explicit interface. Column names, descriptions, valid values, ownership, lineage, and access rules become part of how an AI system interprets the data.
Make the model maintainable
Normalization has a durable foundation in relational theory. Edgar F. Codd introduced the relational model in 1970, and normalization became a core design principle for reducing redundancy and improving integrity, as documented in this history of data normalization. The lesson isn't that every downstream table must remain normalized. The lesson is that teams should store facts deliberately and understand the consequences of duplication.
A model that survives production treats documentation, validation, naming, and review as operating practices. It also evolves incrementally, so teams can balance consistency, performance, and usability rather than forcing a disruptive redesign whenever a requirement changes. The model isn't a side effect of ETL. It's a product.
The Three Layers of a Modern Model Explained
A modern model becomes easier to govern when teams separate conceptual, logical, and physical decisions. These layers connect business meaning to implementation details, a structure that remains widely recognized in contemporary data modeling practice.
Start with a customer-order-product example. The conceptual layer says:
Customer → places → Order → contains → Product
That sketch identifies entities and relationships without committing to column names, database types, or Snowflake objects. It's also the right place to define glossary terms such as “customer,” “order,” “line item,” and “active account.” If business stakeholders disagree here, adding SQL won't solve the disagreement.

Put structure in the logical layer
The logical layer adds attributes, keys, relationships, and cardinalities without tying the design to Snowflake-specific implementation. You can define customer_id, order_id, product_id, order status, and order date here. You can also declare that an order contains one or more order lines, while a product can appear on many order lines.
Grain belongs here. A fact table might represent one order, one order line, one shipment event, or one sensor reading. Those are different business events, even if they share an order_id. If a team confuses an order-level fact with a line-level fact, a later join can multiply revenue or units without producing a SQL error.
Slowly changing dimension behavior also belongs in the logical design. Choosing a Type 2 history means the model preserves versions of an entity over time. The physical decision is how to implement that behavior, perhaps as a Type 2 view over a streams-fed raw table, a snapshot process, or a curated table.
Reserve implementation for the physical layer
The physical layer translates the logical design into Snowflake objects and runtime behavior. Teams decide whether to use tables or views, transient or permanent tables, clustering keys, materialization strategies, and micro-partition organization. A dbt project can express transformation dependencies and tests, while Snowflake DDL expresses storage and execution choices.
The common mistake is treating physical storage as the definition of the business model. A table's clustering key doesn't change its grain. A materialized view doesn't resolve ambiguous ownership. A streams-fed process doesn't justify changing the meaning of customer_id.
Keep the artifacts aligned:
- Conceptual artifact: ER diagram, glossary, domain map.
- Logical artifact: model specification, grain statement, key definitions, history rules.
- Physical artifact: dbt models, tests, Snowflake DDL, clustering and materialization configuration.
When late-arriving facts or duplicate joins appear, review the logical grain first. Storage tuning may improve runtime, but it won't correct a model that counts the same business event more than once.
Choosing Between Normalized, Dimensional, and Hybrid Models
No modeling style wins every workload. 3NF, dimensional, and hybrid designs solve different problems, and cloud warehouses make it practical to expose more than one representation when consumers need different abstractions.
A normalized model is strongest when integrity, deduplication, and flexible relationships dominate. Normalization stores each fact in one place and reduces insert, update, and delete anomalies. It can also create a join-heavy analytical experience, which is why reporting teams often consume curated denormalized views or marts instead, as explained in this comparison of database modeling techniques.
A dimensional model organizes measurable events in fact tables and readable context in dimensions. Kimball's process is concrete: select the business process, declare the grain, identify the dimensions, and identify the facts, as described in this guide to dimensional modeling. That sequence prevents teams from designing abstract tables before deciding which business question the model must answer.
Model StyleWorkload SignalStrengthsWatch Out ForNormalizedMany relationships, frequent transactional updates, or strong integrity requirementsReduces redundancy, preserves a clear source of truth, supports detailed integrationAnalysts may face complex joins and inconsistent query patternsDimensionalPredictable BI dashboards, conformed dimensions, and repeated analytical questionsMakes metrics readable, supports fast analytical access, limits join complexityPoorly declared grain can produce double countingHybridRapid source change, auditability needs, mixed consumers, or separate operational and analytical pathsPreserves raw history while serving curated marts and wide productsMore layers mean more ownership, lineage, and operational work
Use workload signals, not ideology
Frequent schema evolution and a need to preserve source history can favor a Data Vault-style integration layer. Predictable dashboards with 5 to 20 joins often fit a star schema when the dimensions are conformed and the grain is stable, a workload-oriented recommendation discussed in data warehouse architecture guidance. Machine-learning feature pipelines may prefer a wide table or One Big Table because repeated feature assembly can be more expensive and harder to govern when every consumer rebuilds the same joins.
Snowflake's separation of storage and compute changes the tradeoff. Storage pressure alone no longer needs to dictate whether a team duplicates a curated attribute. Query patterns, freshness, governance, and team capability matter more than choosing a style to minimize disk usage.
Before selecting a pattern, evaluate source-system count, change rate, primary consumers, and governance maturity. A hybrid portfolio is often more honest than a single canonical schema. Keep operational integration structures optimized for integrity, then publish dimensional, wide, or semantic products for the people and systems that consume them.
Snowflake-Optimized Patterns for Analytics and IoT
Snowflake rewards models that match access patterns to physical behavior. A large event table with a useful time range and stable business keys can benefit from well-organized micro-partitions and selective clustering. A poorly designed table won't become efficient merely because the warehouse is elastic.
Start with the fact table's grain. For telemetry, one row might represent a device reading at an event timestamp. Keep high-use structured columns such as device_id, account_id, event_ts, metric_name, and metric_value explicit. Store irregular sensor payloads in VARIANT when the fields vary, but promote frequently filtered or joined attributes into typed columns after the access pattern becomes clear.
create table fct_sensor_reading (
device_id varchar not null,
account_id varchar,
event_ts timestamp_ntz not null,
metric_name varchar not null,
metric_value number,
payload variant,
source_received_at timestamp_ntz,
primary key (device_id, event_ts, metric_name)
);
For account history, model the logical Type 2 behavior with effective dates and a current-row indicator. The physical implementation can be a table maintained by incremental transformations, a view over change data, or another governed serving object.
create table dim_account (
account_sk varchar not null,
account_id varchar not null,
account_name varchar,
account_status varchar,
valid_from timestamp_ntz not null,
valid_to timestamp_ntz,
is_current boolean not null,
primary key (account_sk)
);
Match Snowflake features to the workload
WorkloadRecommended StructureKey Snowflake FeatureCommon MisstepDashboard factsTyped fact tables with conformed dimensionsMicro-partition organization and targeted clusteringClustering every table without a query-driven reasonPoint lookupsCurated tables with selective searchable attributesSearch optimization where lookup behavior justifies itUsing clustering as a substitute for selective access designIoT ingestionWide event rows with typed hot fields and VARIANT payloadsAuto-ingest patterns and schema-on-read flexibilitySplitting one event across dozens of tiny tablesOperational time-series readsHot operational representation alongside analytical historyHybrid tables where operational access requires themSending every raw event directly into a star schema
A single oversized warehouse isn't automatically efficient. Size virtual warehouses to workload classes and separate transformation, dashboard, and ad hoc behavior where that improves isolation and cost control. For a concrete Snowflake time-series example, see Faberwork's time-series data success story.
Don't force a star schema onto raw events before you understand the event lifecycle. In IoT, over-normalizing telemetry into many small tables can create unnecessary scans and joins. Conversely, leaving every payload field buried in VARIANT makes contracts, masking, and analyst discovery harder. Use a hybrid physical design, structured columns for stable access paths and semi-structured storage for variable attributes.
Governance, Testing, and Data Contracts in Practice
Governance works when it can stop a release. A model boundary should state its schema, owner, freshness expectation, lineage, access classification, and breaking-change policy before downstream teams depend on it.
A customer-360 contract can be expressed as repository configuration, for example:
model: customer_360
owner_team: customer_data
grain: one row per customer
schema:
customer_id:
type: varchar
nullable: false
customer_name:
type: varchar
nullable: true
account_status:
type: varchar
nullable: false
freshness:
max_delay: agreed_business_slo
lineage:
upstream: [crm_customer, billing_account]
breaking_changes:
require_version: true
prohibited: [rename_column, change_semantics, change_unit]
The important part is not the file format. It's the explicit boundary. If customer_id is allowed to be null, a downstream join may drop customers or create unmatched records while every pipeline task still reports success. If the contract says it's non-null, contract validation and a dbt not_null test can block the release and identify the failure before publication.
Separate test types
dbt tests should cover model logic and relationships:
- Uniqueness: Validate the declared grain on
customer_idor a composite business key. - Nullability: Require identifiers and other mandatory fields.
- Relationships: Check that foreign keys resolve to approved dimensions.
- Freshness: Detect stale upstream sources.
- Business thresholds: Add custom row-count or volume checks where a sudden change indicates a broken load.
Governance adds controls that SQL tests don't provide. Tag PII, apply row access policies, define tag-based masking, and record lineage independently from whether a query returns the expected rows. Faberwork's Snowflake data engineering practice is one example of a consulting option that addresses governed intermediate and serving layers alongside pipeline and ELT design.
Contract linting belongs in pull requests. Schema-diff checks should run in staging, and a changelog should notify subscribed consumers. The CI loop should answer two different questions: does the transformation produce correct results, and does the published interface remain compatible?
A short explanation of the release boundary can help teams distinguish those concerns before the next deployment.
Logic tests protect today's implementation. Contracts protect the relationship between producers and consumers. You need both, but only an enforceable interface tells a producer what downstream teams are entitled to expect.
Migrating Legacy Models Without Downstream Chaos
A finance warehouse migration rarely fails because engineers can't create new tables. It fails because nobody knows which old columns matter. A monolithic warehouse may serve sales dashboards, finance close processes, risk models, feature pipelines, and thousands of unregistered ad hoc queries. Replacing its tables without inventory turns a technical migration into a trust incident.
A safer approach separates compatibility from redesign. First, freeze the old model behind a stable view layer. Stop adding new business logic to the legacy tables, but keep the published interface available while the replacement is built.
Use a staged cutover
Build the domain-oriented replacement for sales, finance, and risk through backfill or dual-write patterns. Reconcile row counts, keys, historical behavior, and metric definitions before asking consumers to move. Then cut over dashboards and other products by subscription, not through a single big-bang switch.
The consumer inventory comes before the migration plan. For each column, identify:
- Dashboards: Which reports filter, aggregate, or display it?
- Machine-learning features: Which training and serving jobs depend on its meaning?
- Operational uses: Which reverse-ETL or application workflows consume it?
- Ad hoc dependencies: Which queries or extracts need a compatibility view?
Additive columns, widened compatible types, and new tables are usually easier to introduce without breaking consumers. Renames, semantic reinterpretations, and unit changes are interface breaks even when the underlying Snowflake table remains the same. Version the contract, publish the replacement, and give consumers a clear retirement path.
Teams often underestimate legacy risk during platform work. The warning in this discussion of legacy code applies to data models too. Familiar SQL can conceal undocumented dependencies, and a successful warehouse upgrade doesn't prove that a semantic migration is safe.
Don't combine a model redesign with a Snowflake warehouse upgrade, a regulatory cutoff, or another deadline that already has limited rollback options. Those events need operational stability. Migrate semantics in a controlled window, retain the compatibility layer until consumers sign off, and record every exception rather than relying on verbal agreement.
Your Monday Morning Modeling Checklist
Start the week by making the model inspectable. The checklist below is deliberately operational, because the strongest patterns from a design review are useless if they don't change what engineers commit and publish.
Start doing these things
- Name the grain: Put the row meaning in the model description and in the review checklist. “One row per order line” is more useful than
fct_orderswith an implied meaning. - Declare keys: Define business keys, surrogate keys, uniqueness expectations, and relationship behavior. A key should explain how the consumer can safely join.
- Default to explicit history: Use Type 2 behavior for slowly changing dimensions when historical state matters, then document exceptions rather than hiding them in transformations.
- Separate raw and curated layers: Preserve source fidelity, standardize types and names in staging, and place business definitions in governed marts or serving models.
- Register every shared model: Put owners, descriptions, lineage, consumers, and access classifications in a catalog that analysts and engineers can search.
- Add contracts at boundaries: Pin schemas, nullability, freshness expectations, breaking-change rules, and ownership for products consumed by BI, ML, operations, or agents.
- Parameterize warehouse behavior: Match Snowflake warehouse sizing and materialization choices to workload classes instead of allowing one default to serve builds, dashboards, and exploration.
These actions support the broader principle that models should align to a high-visibility business process and use validation, standardization, cleaning, and deduplication to keep results trustworthy, as outlined in outcome-focused data modeling guidance.
Stop doing these things
- Don't skip physical reviews: Logical correctness doesn't guarantee acceptable scans, materialization behavior, or cost.
- Don't treat clustering as modeling: A clustering key can support access patterns, but it can't repair a wrong grain or duplicated fact.
- Don't overuse
VARIANT: Keep flexible payloads where they belong, but use structured columns for stable filters, joins, governance, and common metrics. - Don't bury business rules in opaque views: Put definitions in reusable, documented models with tests and ownership.
- Don't migrate without sign-off: Consumer inventory and contract approval are release requirements, not cleanup tasks.
The practical standard is simple, though not easy. A data model is a product with a contract, interfaces for humans and machines, governed consumers, and a lifecycle. Review yours this week, identify one ambiguous grain or undocumented dependency, and open a change that makes its meaning enforceable before another dashboard invents its own answer.
If your organization is redesigning Snowflake models for analytics, IoT, or AI products, contact Faberwork to review your current layers, consumer contracts, governance boundaries, and migration risks, then turn the findings into a maintainable implementation plan.