- 11assessments
- 43scored options
- 0–5score range
- CC BY 4.0licence
Why publish it
Every technology comparison you read is someone's judgement wearing a table. Mine included. The difference I can actually offer is not that my judgement is better — it is that you can take the inputs apart.
The axes I chose reflect what I think matters. Yours will differ. If governance is existential for you and cost is not, re-weight them and see whether the recommendation survives; if it flips, that is a genuinely useful finding and the assessment did its job. A conclusion that only holds under my weights is a conclusion you should not act on.
The second reason is narrower and more practical. This file is the single source of truth for the site: the scorecard tables and the radar charts on every assessment page are generated from it. There is no hand-maintained copy of the numbers to fall out of sync with, which means the data you download is provably the data the pages render.
The shape of it
One object, keyed by assessment slug. Each assessment names its own axes, because the axes that decide an orchestration choice are not the axes that decide a storage format.
{
"scale": { "min": 0, "max": 5, "meaning": "Higher = lower risk for that assessment's stated use case" },
"assessments": {
"clickhouse": {
"title": "ClickHouse",
"url": "/architecture-radar/clickhouse",
"category": "data",
"reviewed": "2026-Q3",
"published": "2026-07-08",
"use_case": "High-volume real-time analytics — observability, events, clickstream…",
"axes": ["Query Performance", "Real-Time Ingestion", "Lakehouse Fit", "…"],
"axes_short": ["Performance", "Real-Time", "Lakehouse", "…"],
"target": "ClickHouse",
"platforms": {
"ClickHouse": [4.7, 4.3, 3.8, 3.9, 4.1, 3.9, 3.4, 3.6, 4.1, 4.5],
"StarRocks": [4.7, 4.3, 4.4, 4.1, 3.9, 3.8, 3.7, 3.6, 3.8, 4.3]
},
"verdict": "Adopt for real-time analytics at volume; Narrow Use as a general warehouse."
}
}
}
| Field | Meaning |
|---|---|
use_case | The most important field. Scores are relative to this. They are not context-free quality ratings, and comparing scores across assessments with different use cases is a mistake the data cannot stop you making. |
reviewed | The quarter the scores were last examined. Treat anything more than about two quarters old as stale. |
axes / axes_short | Same length, same order. axes_short exists only so chart labels fit. |
platforms | Option name to score vector. Every vector is the same length as axes, in the same order. |
target | The option the assessment is primarily about; always a key of platforms. |
category | data or ai — drives the filter on the radar. |
Invariants, and the script that enforces them
Four things are meant to be true of this file at all times:
- Every score vector is the same length as its assessment's axes, and every value falls in 0–5.
targetis one of the options inplatforms, and each assessment compares at least two.- Nothing scores a 5, and the observed ceiling is 4.9. A page full of 5s is a page written by someone who has not operated the thing.
- The same-bar rule: where one option appears in several assessments on identical axes, its vector should be identical across them. Otherwise the radar quietly contradicts itself.
These are checked by a script rather than trusted, because I have already broken two of them by hand:
python3 architecture-radar/validate_scorecards.py
⚠️ Known issue, in the open: ClickHouse in doris-vs-starrocks breaks the same-bar rule. Its vector there sits 0.1–0.3 below the canonical one in the ClickHouse assessment, on identical axes, from an earlier scoring pass. StarRocks and Snowflake are consistent across the same pair, so this is an oversight rather than a deliberate context adjustment. It is not silently corrected because that page's prose cites the specific figures to argue a point about join performance — realigning the numbers means rewriting the argument, which is a judgement call due at the next review of that assessment. Flagged 2026-07-19. The validator carries it as a named exception so it cannot spread.
The other one I broke: the methodology page claimed the highest score anywhere was 4.8, and it had been 4.9 in five places since the 2026-Q3 additions. The prose has been corrected to match the data, and the validator now guards the ceiling in both directions.
Doing something with it
Re-weight the axes for your own context
The most useful thing you can do with this file. Assign your own weights and see whether the ordering holds.
import json, urllib.request
URL = "https://shirokoff.ca/architecture-radar/scorecards.json"
doc = json.load(urllib.request.urlopen(URL))
a = doc["assessments"]["clickhouse"]
# Your priorities, not mine. Anything you leave out counts as 1.0.
weights = {
"Governance & Security": 3.0, # regulated environment
"TCO / Cost Efficiency": 2.0,
"Lakehouse Fit": 0.5, # not part of the plan
}
w = [weights.get(axis, 1.0) for axis in a["axes"]]
total = sum(w)
ranked = sorted(
((sum(s * wi for s, wi in zip(vec, w)) / total, name)
for name, vec in a["platforms"].items()),
reverse=True,
)
for score, name in ranked:
print(f"{score:.2f} {name}")
If your ordering differs from my verdict, you have found either a genuine difference in context or a mistake in my scoring. Both are worth an email.
Flatten it for a spreadsheet
curl -s https://shirokoff.ca/architecture-radar/scorecards.json \
| jq -r '.assessments | to_entries[]
| .key as $slug | .value as $a
| $a.platforms | to_entries[]
| [$slug, .key, ($a.axes | join("|")), (.value | join("|"))]
| @csv'
Query it in DuckDB
-- Every option scored in 2026-Q3, with its assessment's use case
SELECT slug,
option_name,
list_avg(scores) AS mean_score
FROM (
SELECT unnest(map_keys(assessments)) AS slug,
unnest(map_values(assessments)) AS a
FROM read_json_auto('scorecards.json')
), unnest(map_entries(a.platforms)) AS t(option_name, scores)
WHERE a.reviewed = '2026-Q3'
ORDER BY mean_score DESC;
💡 A caution about mean scores. Averaging across axes is convenient and usually wrong — it treats "cheap" as compensating for "insecure." The axes are deliberately not commensurable. Rank on the two or three that decide your case, and use the mean only as a smell test.
Licence and stability
The data is published under CC BY 4.0. Use it, republish it, build on it commercially — attribute it to Dmitry Shirokov, Architecture Radar with a link back, and make clear if you have modified the scores, because my name should not end up on numbers I did not choose.
| Commitment | What you can rely on |
|---|---|
| URL | /architecture-radar/scorecards.json is stable. If it ever moves, the old path will redirect. |
| Structure | Additive changes (new assessments, new optional fields) without notice. Removing or renaming a field means a new $schema version. |
| Scores | Will change — that is the point. reviewed tells you when, and re-scoring is recorded rather than quietly applied. |
| Not a stable identifier set | Option names are human labels, not IDs. Pin to a copy if you need reproducibility. |
📊 Found something wrong? That is the intended use. Mail dmansh@gmail.com with the assessment, the axis, and what you would score it instead — ideally with what you measured. Corrections get made and dated on the methodology page, with credit unless you would rather not have it.