Slowly changing dimensions are a copy-discipline problem in disguise. SCD Type 1 overwrites history — cheapest, lossy, fine for attributes nobody will ever ask about retroactively. Type 2 versions rows with valid-from / valid-to timestamps and a surrogate key; it's the honest default when the past matters, because it lets a fact join to the dimension as it was, not as it is. Type 3 keeps a prior-value column alongside the current one — a narrow compromise for one or two attributes that change occasionally and are always compared to their previous state. Pick per-attribute, not per-table. Most real dimensions are a mix.
Star schema keeps facts at a single grain surrounded by conformed dimensions read straight through: one join, no re-shaping, cache-friendly. Snowflake normalizes those dimensions into sub-tables to eliminate repetition and enforce hierarchy. Snowflake saves bytes; star saves hops. On modern columnar warehouses, hops usually cost more than bytes — start star, snowflake only where a dimension is genuinely large, deeply hierarchical, and shared across many facts.
Whichever you pick, write the grain down. A fact table without a stated grain is a table that will silently double-count within a quarter, and no amount of dashboard polish will surface it. Dimensional modeling is not decoration on top of a warehouse — it's the contract that keeps downstream reads honest without copying the source another five times to reconcile what the grain should have been in the first place.