Skip to main content
Multi-Cloud · lesson 1 of 8
Multi-Cloud intermediate Lesson 1 of 8

Choosing a Cloud: A Decision Framework With Real Numbers

A weighted scoring framework — team skills, egress cost, service maturity, lock-in risk — run against three real scenarios to a concrete recommendation.

By SkillByExample · Published

cloud aws azure gcp architecture

“It depends” is true and useless. What makes it useful is naming what it depends on, putting a number on each factor, and running the same four-factor scoresheet against your actual scenario instead of a generic one.

The four factors

Score each cloud 0-10 on each factor, weight the factors by what your scenario actually cares about, and take the weighted sum. The factors:

  • Team skills — what your engineers already know. Ramp-up time is a real, recurring cost that shows up as slower delivery for months, not a one-time tax.
  • Egress cost — the list-price rate per GB to move data out to the internet. It only matters in proportion to how much data you actually move out.
  • Service maturity for your workload — not “which cloud has more services” in the abstract, but which one has the specific managed service your workload needs, and how battle-tested it is.
  • Lock-in risk — how much of your architecture depends on a proprietary API versus a portable one (standard SQL, Kubernetes, S3-compatible object storage).

Scoring three real scenarios

# choose_cloud.py
def recommend(name, weights, scores):
    clouds = ("AWS", "Azure", "GCP")
    totals = {c: sum(w * scores[f][c] for f, w in weights.items()) for c in clouds}
    ranked = sorted(totals.items(), key=lambda kv: -kv[1])
    print(name)
    for cloud, total in ranked:
        print(f"  {cloud:<6}{total:5.2f}")
    print(f"  -> recommend {ranked[0][0]}\n")


# Scenario 1: 5-engineer startup, greenfield SaaS, shipping speed matters most.
recommend(
    "Startup, greenfield SaaS",
    {"team_skills": 0.45, "service_maturity": 0.30, "egress_cost": 0.05, "lock_in_risk": 0.20},
    {
        "team_skills":      {"AWS": 8, "Azure": 5, "GCP": 6},  # two engineers used AWS at a bootcamp
        "service_maturity": {"AWS": 9, "Azure": 7, "GCP": 7},
        "egress_cost":      {"AWS": 7, "Azure": 7, "GCP": 5},
        "lock_in_risk":     {"AWS": 5, "Azure": 5, "GCP": 7},
    },
)

# Scenario 2: 300-engineer enterprise migrating an on-prem Windows/AD estate.
recommend(
    "Enterprise .NET migration",
    {"team_skills": 0.40, "service_maturity": 0.30, "egress_cost": 0.05, "lock_in_risk": 0.25},
    {
        "team_skills":      {"AWS": 4, "Azure": 9, "GCP": 3},  # existing AD, SCCM, on-prem Windows
        "service_maturity": {"AWS": 8, "Azure": 9, "GCP": 5},  # Entra hybrid join is the deciding line
        "egress_cost":      {"AWS": 7, "Azure": 7, "GCP": 5},
        "lock_in_risk":     {"AWS": 6, "Azure": 5, "GCP": 6},
    },
)

# Scenario 3: analytics platform moving ~40 TB/month out to partner systems.
recommend(
    "Data-heavy analytics platform",
    {"team_skills": 0.15, "service_maturity": 0.30, "egress_cost": 0.35, "lock_in_risk": 0.20},
    {
        "team_skills":      {"AWS": 6, "Azure": 5, "GCP": 6},
        "service_maturity": {"AWS": 8, "Azure": 6, "GCP": 9},  # BigQuery's serverless model fits this shape
        "egress_cost":      {"AWS": 6, "Azure": 6, "GCP": 4},  # GCP's list rate is the highest of the three
        "lock_in_risk":     {"AWS": 5, "Azure": 5, "GCP": 6},
    },
)
$ python choose_cloud.py
Startup, greenfield SaaS
  AWS    7.65
  GCP    6.45
  Azure  5.70
  -> recommend AWS

Enterprise .NET migration
  Azure  7.90
  AWS    5.85
  GCP    4.45
  -> recommend Azure

Data-heavy analytics platform
  AWS    6.40
  GCP    6.20
  Azure  5.65
  -> recommend AWS

The first two results are unsurprising once you see the weights: a startup with no Windows estate weights team skills and service breadth over everything else, and lands on AWS’s larger catalog of battle-tested building blocks; an enterprise with an existing Active Directory forest weights team skills and identity-service maturity hard enough that Azure wins even though it scores lower on raw service count.

The third result is the one worth sitting with. GCP scores highest on service maturity for analytics — BigQuery’s serverless model genuinely fits this shape of workload better than Redshift or Synapse for many teams. But this scenario weights egress at 0.35 because the platform serves results out to partner systems on other clouds, and GCP’s list-price egress rate is the highest of the three. That single factor, at that weight, is enough to flip the recommendation to AWS. Change the scenario so results stay inside GCP — feeding Looker Studio or BigQuery ML instead of exporting to partners — and egress drops to near zero, the weight on it should drop too, and GCP wins outright. The framework isn’t rigged toward any cloud; it’s rigged toward whatever you tell it actually costs you money.

Why this beats “it depends”

Vendor documentation cannot honestly run this scoring, because a vendor can’t assign its own competitors a fair score, and won’t publish a scenario where it loses. That’s the gap this lesson fills: the same four factors, scored against your actual constraints, computed the same way every time.

Practice

1. Change scenario 3 so results stay entirely inside GCP (BigQuery to Looker Studio, no partner export) and re-run.
recommend(
    "Data-heavy analytics platform (internal only)",
    {"team_skills": 0.15, "service_maturity": 0.45, "egress_cost": 0.10, "lock_in_risk": 0.30},
    {
        "team_skills":      {"AWS": 6, "Azure": 5, "GCP": 6},
        "service_maturity": {"AWS": 8, "Azure": 6, "GCP": 9},
        "egress_cost":      {"AWS": 6, "Azure": 6, "GCP": 4},
        "lock_in_risk":     {"AWS": 5, "Azure": 5, "GCP": 6},
    },
)
Data-heavy analytics platform (internal only)
  GCP    6.95
  AWS    6.75
  Azure  5.65
  -> recommend GCP

Dropping the egress weight from 0.35 to 0.10 and raising service maturity’s weight is enough to flip the winner to GCP — the same inputs, a different scenario, a different honest answer.

2. Add a fifth factor, "compliance certifications," and give it real weight in the enterprise scenario.
weights = {"team_skills": 0.30, "service_maturity": 0.25, "egress_cost": 0.05,
           "lock_in_risk": 0.20, "compliance": 0.20}
scores["compliance"] = {"AWS": 8, "Azure": 9, "GCP": 7}

Re-running with these weights keeps Azure on top (compliance reinforces the existing lean here), but the margin changes — which is the point of scoring instead of guessing: you can see how sensitive the recommendation is to a factor you just added.

3. Set every weight equal (0.25 each) for all three scenarios and compare to the weighted results above.

Equal weights erase the scenario-specific reasoning entirely — a startup and an enterprise get scored identically, which is exactly the “it depends” answer this framework exists to avoid. The lesson: the weights, not the raw scores, are where your actual judgment lives.

4. Score your own current project against these four factors.

Write down honest 0-10 scores for the cloud(s) you’re evaluating and weights that reflect what actually matters for the project — not what you’d like to matter. If the result disagrees with your gut, that disagreement is worth investigating before you commit.

Next: the same “grant read-only access to one bucket” task, done three ways, to see where the IAM vocabulary differs and where the underlying model doesn’t.

Frequently Asked Questions

Is AWS, Azure, or GCP the best cloud?
None of them, in general — the honest answer depends on what you're weighting. A team that already runs Active Directory has a real cost advantage on Azure that a greenfield startup doesn't. The framework in this lesson makes that dependency explicit with numbers instead of settling it with a preference.
How much does egress actually matter when choosing a cloud?
It matters in proportion to how much data leaves the cloud, not how much you store. A media company serving files to end users pays it on nearly every byte; an internal analytics team that keeps everything inside one cloud barely notices it. List-price egress runs $0.08-$0.12 per GB on all three providers, so weight it by your actual monthly egress volume, not by reputation.
What is cloud lock-in risk, concretely?
The cost of leaving, measured in rework — not a legal or contractual trap. Using RDS PostgreSQL is low lock-in (the wire protocol is standard Postgres); using DynamoDB, Cosmos DB's proprietary APIs, or Step Functions is high lock-in, because the replacement isn't a connection-string change, it's a rewrite.
Should I always pick the cloud my team already knows?
It's the single highest-weighted factor in most real decisions, because ramp-up time is a real, recurring cost, not a one-time one. But it shouldn't be the only factor — the scoring framework here treats it as one of four inputs so a strong service-maturity or cost advantage elsewhere can still outweigh it.