---
title: 'The Pillars of the Design Framework'
source: 'https://academia.sh/en/courses/cloud-fundamentals/design-framework-pillars'
course: 'Cloud Fundamentals'
language: en
updated: '2026-09-13T05:07:33+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - "Defines the design framework's five pillars as types and scores a decision set against them"
    - 'Counts the tension between pillars with a matrix: how many decisions lower which pillar while raising another'
    - 'Derives the pillar no decision improves and the most tense pillar pair'
    - 'Compares the pillar profile of handed-over decisions against what remains and counts the share that cannot carry at exit'
---

# The Pillars of the Design Framework

Scoring a decision set across five pillars and counting the tension between pillars: how many decisions raise one pillar while lowering another, which pillar pair is most tense, deriving the pillar no decision improves, and comparing the pillar profile of handed-over decisions against what remains and the share that does not carry at exit.

The first two lessons measured geography on two separate axes, and both ended in the same
shape: a decision raised one number and lowered another. Spreading across three zones
raised the item left standing and hurt the rent and the synchronous write time. Three
edge locations lowered latency and produced more than ten thousand stale responses a day.
Each of these two observations is, on its own, an anecdote; to turn into a decision
ledger they have to be written down with the same measures and in the same form.

The design frameworks used to evaluate rented infrastructure do exactly this. They score
a decision not as good or bad but **separately, pillar by pillar**. This lesson uses five
pillars — operations, security, reliability, performance, and cost — because those five
are the common core of the widely used frameworks; the number of pillars varies from
framework to framework, and some add a sixth such as sustainability. The framework's name
does not appear in this lesson; what is measured is not a name but how the pillars
constrain one another. A tension matrix built the same way was set up for quality
attributes in a previous course; the method is the same, but the numbers there do not
carry over here.

## Five Pillars and the Decision Set

- **CG13.** The pillars are called by their type name: operations, security, reliability,
  performance, cost.
- **CG14.** The decision set consists of 12 decisions made in this course and the previous
  two lessons; all are geography, resilience, or leasing decisions.
- **CG15.** The scores are an **assumption** between -2 and +2, not a measured value; what
  is meaningful is the ranking and the sign, not the absolute size.
- **CG16.** A decision counts as a **handoff** if implementing it requires renting a
  service the provider operates.
- **CG17.** The exit class has three values: `definition` (can be written down and built
  again unchanged in another lease), `partial`, `none`.
- **CG18.** Decisions are scored independently of one another. In real sets they affect
  each other; this is a known limit of the model.

```js
// framework/model.mjs — decision set and pillar scores is a MODEL. Pillars are called by their type
// name; scores are this lesson's assumption, not measured values. There is no real product or catalog.
export const PILLAR = ["operations", "security", "reliability", "performance", "cost"];

// name, [operations, security, reliability, performance, cost] (-2..+2), handoff?, exit class
export const DECISION = [
  ["three-zone-spread", [-1, 0, 2, 0, -1], false, "definition"],
  ["full-copy-in-second-region", [-2, 0, 2, 1, -2], false, "definition"],
  ["cross-region-synchronous-write", [-1, 0, 2, -2, -1], false, "definition"],
  ["three-edge-locations", [-1, 1, 1, 2, -1], true, "partial"],
  ["subscriber-summary-cache", [0, 0, 1, 2, 0], true, "definition"],
  ["managed-relational-database", [2, 1, 1, -1, -2], true, "partial"],
  ["function-runtime", [2, 0, 1, -1, -1], true, "none"],
  ["provider-key-management", [1, 2, 0, -1, -1], true, "none"],
  ["per-environment-separate-lease", [-2, 2, 1, 0, -1], true, "definition"],
  ["automatic-patching-handoff", [2, 2, -1, 0, 0], true, "none"],
  ["single-write-endpoint", [1, 0, -2, 1, 0], false, "definition"],
  ["raw-read-in-object-store", [1, 0, 1, -1, -1], true, "partial"],
];

export const score = (k, s) => k[1][PILLAR.indexOf(s)];
export const raising = (s) => DECISION.filter((k) => score(k, s) > 0);
export const lowering = (s) => DECISION.filter((k) => score(k, s) < 0);
export const total = (s) => DECISION.reduce((a, k) => a + score(k, s), 0);

// tension: if decision i raises pillar i while lowering pillar j, the cell increases by one
export function tension(i, j) {
  return DECISION.filter((k) => score(k, i) > 0 && score(k, j) < 0).length;
}
export const tense = (k) => k[1].some((p) => p > 0) && k[1].some((p) => p < 0);
```

## Tension Between Pillars

```js
// framework/score.mjs — pillar totals and the tension matrix between pillars
import { PILLAR, DECISION, score, raising, lowering, total, tension, tense } from "./model.mjs";

const s = (x, n) => String(x).padStart(n);
console.log(`${DECISION.length} decisions, ${PILLAR.length} pillars; scores are in -2..+2 (assumption).`);
console.log();
console.log("decision                          | ops   | sec   | rel   | prf   | cst   | net   | tense  ");
console.log("----------------------------------|-------|-------|-------|-------|-------|-------|--------");
for (const k of DECISION) {
  const net = k[1].reduce((a, b) => a + b, 0);
  console.log(`${k[0].padEnd(33)} |${k[1].map((p) => s(p, 5)).join(" |")} | ${s(net, 5)} | ` +
    `${tense(k) ? "yes" : "no"}`);
}

console.log();
console.log("pillar        | total   | raising decisions   | lowering decisions   | highest   | lowest  ");
console.log("--------------|---------|---------------------|----------------------|-----------|---------");
for (const t of PILLAR) {
  const p = DECISION.map((k) => score(k, t));
  console.log(`${t.padEnd(13)} | ${s(total(t), 7)} | ${s(raising(t).length, 19)} | ` +
    `${s(lowering(t).length, 20)} | ${s(Math.max(...p), 9)} | ${s(Math.min(...p), 8)}`);
}

console.log();
console.log("raising \\ lowering   | operations   | security   | reliability   | performance   | cost    | row  ");
console.log("---------------------|--------------|------------|---------------|---------------|---------|------");
for (const i of PILLAR) {
  const h = PILLAR.map((j) => (i === j ? "-" : String(tension(i, j))));
  const row = PILLAR.filter((j) => j !== i).reduce((a, j) => a + tension(i, j), 0);
  console.log(`${i.padEnd(20)} | ${s(h[0], 12)} | ${s(h[1], 10)} | ${s(h[2], 13)} | ` +
    `${s(h[3], 13)} | ${s(h[4], 7)} | ${s(row, 5)}`);
}

const neverRaised = PILLAR.filter((t) => raising(t).length === 0);
const pair = [];
for (const i of PILLAR) for (const j of PILLAR) if (i !== j) pair.push([i, j, tension(i, j)]);
pair.sort((a, b) => b[2] - a[2]);
console.log();
console.log(`tense decisions ${DECISION.filter(tense).length}/${DECISION.length}; ` +
  `decisions that lower no pillar ${DECISION.filter((k) => !k[1].some((p) => p < 0)).length}.`);
console.log(`pillar no decision improves: ${neverRaised.join(", ") || "none"}.`);
console.log(`most tense pair: ${pair[0][0]} rises while ${pair[0][1]} falls — ${pair[0][2]} decisions.`);
```

```
12 decisions, 5 pillars; scores are in -2..+2 (assumption).

decision                          | ops   | sec   | rel   | prf   | cst   | net   | tense  
----------------------------------|-------|-------|-------|-------|-------|-------|--------
three-zone-spread                 |   -1 |    0 |    2 |    0 |   -1 |     0 | yes
full-copy-in-second-region        |   -2 |    0 |    2 |    1 |   -2 |    -1 | yes
cross-region-synchronous-write    |   -1 |    0 |    2 |   -2 |   -1 |    -2 | yes
three-edge-locations              |   -1 |    1 |    1 |    2 |   -1 |     2 | yes
subscriber-summary-cache          |    0 |    0 |    1 |    2 |    0 |     3 | no
managed-relational-database       |    2 |    1 |    1 |   -1 |   -2 |     1 | yes
function-runtime                  |    2 |    0 |    1 |   -1 |   -1 |     1 | yes
provider-key-management           |    1 |    2 |    0 |   -1 |   -1 |     1 | yes
per-environment-separate-lease    |   -2 |    2 |    1 |    0 |   -1 |     0 | yes
automatic-patching-handoff        |    2 |    2 |   -1 |    0 |    0 |     3 | yes
single-write-endpoint             |    1 |    0 |   -2 |    1 |    0 |     0 | yes
raw-read-in-object-store          |    1 |    0 |    1 |   -1 |   -1 |     0 | yes

pillar        | total   | raising decisions   | lowering decisions   | highest   | lowest  
--------------|---------|---------------------|----------------------|-----------|---------
operations    |       2 |                   6 |                    5 |         2 |       -2
security      |       8 |                   5 |                    0 |         2 |        0
reliability   |       9 |                   9 |                    2 |         2 |       -2
performance   |       0 |                   4 |                    5 |         2 |       -2
cost          |     -11 |                   0 |                    9 |         0 |       -2

raising \ lowering   | operations   | security   | reliability   | performance   | cost    | row  
---------------------|--------------|------------|---------------|---------------|---------|------
operations           |            - |          0 |             2 |             4 |       4 |    10
security             |            2 |          - |             1 |             2 |       4 |     9
reliability          |            5 |          0 |             - |             4 |       8 |    17
performance          |            2 |          0 |             1 |             - |       2 |     5
cost                 |            0 |          0 |             0 |             0 |       - |     0

tense decisions 11/12; decisions that lower no pillar 1.
pillar no decision improves: cost.
most tense pair: reliability rises while cost falls — 8 decisions.
```

The last column of the first table is this lesson's first number: **11 of the 12
decisions are tense**, meaning each raises at least one pillar while lowering at least
one other. The only decision that lowers no pillar is the subscriber summary cache, and
even that one came with a cost in the second lesson — stale responses. If the pillar
scoring did not see the cost, that does not mean there is no cost; it means **it fell
outside the measure set**.

The second table summarizes the pillars on their own. Reliability is raised by 9
decisions and, at +9, is the highest-total pillar. Cost, in contrast, is raised by **0
decisions**, lowered by 9, and totals -11. This does not show the decisions were badly
chosen; it is a consequence of what the set is made of. This lesson gathered geography
and resilience decisions, and none of them raise cost — the decisions that raise cost
come from a different kind and have not been measured yet. Security showing 0 lowering
decisions reads the same way: this set contains no decision that breaks security, not
that security cannot be broken.

The third table is the real measure. The row counts the decisions that raise one pillar;
the column counts the measure they lower. The reliability row, at 17, is by far the most
tense row: the decisions that raise reliability lower cost in 8 decisions, operations in
5, and performance in 4. **The most tense pair is reliability and cost, and 8 decisions
carry this pair.** The cost row being entirely zero is the matrix form of the same
finding as the second table: since no decision raises cost, there is no cell where cost
lowers another pillar either.

Where the matrix earns its keep is not a ranking but a list of **which pair needs to be
settled explicitly**. Because the reliability–cost cell is filled with 8, if that pair is
not discussed once and pinned to an upper bound, eight separate decisions each make their
own trade-off, unaware of the other seven. The reliability–security cell, by contrast, is
0: none of the nine decisions that raise reliability lower security, so there is no need
to write a separate trade-off rule for that pair. Empty cells carry as much information
as full ones.

## The Pillar Profile of the Handed-Over Decision

The tension matrix split decisions across pillars; the second cut splits them by **who
owns them**. A decision is handed over if implementing it requires renting a service the
provider operates.

```js
// framework/handoff.mjs — splitting the pillar profile between handed-over and retained-own decisions
import { PILLAR, DECISION, score } from "./model.mjs";

const s = (x, n) => String(x).padStart(n);
const y = (x) => x.toFixed(2);
const EXIT = { definition: 2, partial: 1, none: 0 };
const group = { handoff: DECISION.filter((k) => k[2]), own: DECISION.filter((k) => !k[2]) };

console.log("group     | decisions   | operations   | security   | reliability   | performance   | cost    | exit score  ");
console.log("----------|-------------|--------------|------------|---------------|---------------|---------|-------------");
for (const [name, g] of Object.entries(group)) {
  const avg = PILLAR.map((t) => g.reduce((a, k) => a + score(k, t), 0) / g.length);
  const exitScore = g.reduce((a, k) => a + EXIT[k[3]], 0) / (2 * g.length);
  console.log(`${name.padEnd(9)} | ${s(g.length, 11)} | ${s(y(avg[0]), 12)} | ${s(y(avg[1]), 10)} | ` +
    `${s(y(avg[2]), 13)} | ${s(y(avg[3]), 13)} | ${s(y(avg[4]), 7)} | ${s(`${y(100 * exitScore)}%`, 12)}`);
}

console.log();
console.log("group     | definition at exit   | partial   | none   | decisions not carried  ");
console.log("----------|----------------------|-----------|--------|------------------------");
for (const [name, g] of Object.entries(group)) {
  const count = (t) => g.filter((k) => k[3] === t).length;
  console.log(`${name.padEnd(9)} | ${s(count("definition"), 20)} | ${s(count("partial"), 9)} | ` +
    `${s(count("none"), 6)} | ${s(`${count("partial") + count("none")}/${g.length}`, 23)}`);
}

const handoffOpsSec = group.handoff.reduce((a, k) => a + score(k, "security") + score(k, "operations"), 0);
const ownOpsSec = group.own.reduce((a, k) => a + score(k, "security") + score(k, "operations"), 0);
console.log();
console.log(`handed-over ${group.handoff.length} decisions total ${handoffOpsSec} in operations + security, ` +
  `retained-own ${group.own.length} decisions ${ownOpsSec}.`);
console.log(`of the handed-over ${group.handoff.length} decisions, those that cannot carry at exit as a ` +
  `definition: ${group.handoff.filter((k) => k[3] !== "definition").length}; of the retained-own ` +
  `${group.own.length}, ${group.own.filter((k) => k[3] !== "definition").length}.`);
```

```
group     | decisions   | operations   | security   | reliability   | performance   | cost    | exit score  
----------|-------------|--------------|------------|---------------|---------------|---------|-------------
handoff   |           8 |         0.63 |       1.00 |          0.63 |          0.00 |   -0.88 |       43.75%
own       |           4 |        -0.75 |       0.00 |          1.00 |          0.00 |   -1.00 |      100.00%

group     | definition at exit   | partial   | none   | decisions not carried  
----------|----------------------|-----------|--------|------------------------
handoff   |                    2 |         3 |      3 |                     6/8
own       |                    4 |         0 |      0 |                     0/4

handed-over 8 decisions total 13 in operations + security, retained-own 4 decisions -3.
of the handed-over 8 decisions, those that cannot carry at exit as a definition: 6; of the retained-own 4, 0.
```

The difference between handed-over and retained-own decisions concentrates in two
pillars. In operations, handed-over decisions average +0.63, retained-own decisions
**-0.75**; in security, +1.00 versus 0.00. Their sums, 13 against -3, mean the payoff of
the lease is paid in these two pillars. In reliability, the ranking reverses —
retained-own decisions average +1.00, handed-over decisions +0.63. The decisions that
raise reliability the most are decisions that cannot be handed to anyone: spreading
across zones, keeping a copy in a second region, making the write synchronous.

The last table gives the exit column, and this lesson's sharpest contrast is here. **All
4** of the 4 retained-own decisions carry at exit as a definition: how many zones, which
region, which write pattern — every one is a sentence that can be written down and built
again unchanged in another lease. Of the 8 handed-over decisions, only **2** carry; 6
carry partially or not at all. The exit score is 100 percent against **43.75 percent**.
Leasing raises the operations and security pillars while pulling the exit column below
half, and this column appears in none of the five above.

## Summary

- The framework scores a decision not as good or bad but pillar by pillar; the five used
  in this lesson are operations, security, reliability, performance, and cost. What is
  measured is not a name but how the pillars constrain one another.
- **11 of the 12 decisions are tense**; there is exactly one decision that lowers no
  pillar, and even its cost fell outside the pillars.
- **0** decisions raise cost, 9 lower it; the pillar no decision improves is cost. This is
  a consequence of the set being made of geography and resilience decisions.
- The most tense pair is reliability and cost: 8 decisions raise reliability while
  lowering cost. The reliability row, at 17, is the most tense row.
- The 8 handed-over decisions average +0.63 and +1.00 in operations and security, the 4
  retained-own decisions -0.75 and 0.00; in reliability the ranking reverses (+1.00
  against +0.63).
- At exit, 4/4 of the retained-own decisions carry as a definition, only 2/8 of the
  handed-over ones: the exit score is 100 percent against 43.75 percent.

## Next Step

This lesson counted cost as a pillar, and that pillar turned up a strange property: none
of the twelve decisions raise it. The reason is not that the decisions were poor, but the
composition of the set — geography and resilience decisions are the side that pays cost,
not the side that earns it. The decisions that raise the cost pillar come from elsewhere,
and not one of them has been measured yet: **under which terms** the same capacity is
rented. The same machine, the same hour, the same work; but capacity carries one price if
it can be requested and released instantly, another if it is tied to a long-term
commitment, and a third if the provider can reclaim it. The next lesson runs three models
against the same load profile and counts, together, the total cost, the work re-run
because reclaimed capacity was lost, and the unused commitment; it shows that as the load
profile changes, the winning model changes too.
