Skip to content
academia.sh

Lesson 09 / 11

Stakeholder Management

Measuring communication with a non-technical counterpart in a stakeholder model: the same decision's technical-terminology narrative produces 27 questions and 8 rounds, while its outcome-focused narrative produces 0 questions and 3 rounds by eliminating four of six constraints and turning them into four surprises; a third narrative that restores the constraints in plain language brings the total to 3 rounds for four additional statements.

Contents

The previous lesson turned a decision into an object and classified it by reversibility: it settled which decision gets which method. One thing it did not settle: who approves the decision is not who makes it. In the regional library network’s model, changing the loan service’s data flow touches the budget, changes what branch staff do, and concerns the contract of an externally sourced catalog system. A non-technical person holds all three of these gates.

This lesson does not say “the architect must communicate.” It turns communication into a data structure: a stakeholder is a vocabulary plus a set of concerns, a narrative is a sequence of statements. The same decision runs through the same model with two separate narratives, and two numbers get counted: questions answered per decision and rounds needed for approval. A third number gets counted too, because there is a reason the outcome-focused narrative looks cheap: the number of constraints the narrative eliminates.

A Stakeholder Is a Vocabulary and a Set of Concerns

A stakeholder is the party that bears the outcome of a decision but does not make it. The model has three stakeholders and none is drawn from a real organization: the budget owner, the service owner, the procurement owner. Each one has a known vocabulary of terms and a set of concerns that must be addressed for approval.

AP10: a stakeholder grants approval once every concern in its concern set is addressed and no open question remains. If either condition is missing, approval does not come; the meeting runs another round.

AP11: a statement containing an unknown term is not understood in that round. It does not address its concern, does not carry its constraint; instead it produces one question per term. The answer to a question permanently adds the term to the vocabulary, so the same term is never asked about twice.

AP12: every constraint that is not carried later produces a surprise for the stakeholder affected by that constraint, and a surprise adds one more round of cost. If the constraint was carried, no one is surprised when the event happens.

// stakeholder/model.mjs — model of communication with a non-technical counterpart. There is no
// real organization or person; a stakeholder is a vocabulary plus a set of concerns, a narrative
// is a sequence of statements. Time is not measured; questions answered, rounds, and constraints carried are counted.

// The constraints the decision carries. A narrative is not required to carry all of them; every
// constraint it does not carry is a later surprise candidate.
export const CONSTRAINTS = {
  C1: "the nightly report is produced fifteen minutes late",
  C2: "branch staff take training once",
  C3: "old records are double-written for two weeks",
  C4: "the decision can be reversed within a week",
  C5: "the contract with the external catalog provider does not change",
  C6: "delivery is delayed if backlog builds up during peak hours",
};

// Terms everyone knows in the organization's own language. Technical terms are not in this set.
const COMMON = ["branch", "staff", "duration", "cost", "risk", "report", "reader",
  "service outage", "training", "contract", "provider"];

export const STAKEHOLDERS = [
  { name: "budget owner", concerns: ["cost", "reversal"], vocabulary: [...COMMON, "budget"] },
  { name: "service owner", concerns: ["service outage", "training"], vocabulary: [...COMMON, "shelf"] },
  { name: "procurement owner", concerns: ["contract", "cost"], vocabulary: [...COMMON, "tender"] },
];

// The statement the architect adds when an unaddressed concern remains. Written in plain language.
export const ADDITIONAL_STATEMENT = {
  "cost": { terms: ["cost", "staff"], concerns: ["cost"], constraint: [] },
  "reversal": { terms: ["duration", "risk"], concerns: ["reversal"], constraint: ["C4"] },
  "service outage": { terms: ["service outage"], concerns: ["service outage"], constraint: [] },
  "training": { terms: ["staff", "branch"], concerns: ["training"], constraint: ["C2"] },
  "contract": { terms: ["contract", "provider"], concerns: ["contract"], constraint: ["C5"] },
};

// AP10 + AP11: one stakeholder, one narrative. An unknown term turns into a question; the answer is added to the vocabulary.
export function meeting(stakeholder, narrative, maxRounds = 12) {
  const vocabulary = new Set(stakeholder.vocabulary);
  const addressed = new Set(), carried = new Set(), additional = [];
  let questions = 0, round = 0;
  while (round < maxRounds) {
    round += 1;
    let roundQuestions = 0;
    for (const f of [...narrative, ...additional]) {
      const unknown = f.terms.filter((t) => !vocabulary.has(t));
      if (unknown.length > 0) {
        roundQuestions += unknown.length;
        for (const t of unknown) vocabulary.add(t);
        continue;
      }
      for (const c of f.concerns) addressed.add(c);
      for (const c of f.constraint) carried.add(c);
    }
    questions += roundQuestions;
    const missing = stakeholder.concerns.filter((c) => !addressed.has(c));
    if (roundQuestions === 0 && missing.length === 0) return { round, questions, carried, additional: additional.length };
    if (roundQuestions === 0) additional.push(ADDITIONAL_STATEMENT[missing[0]]);
  }
  return { round, questions, carried, additional: additional.length, unapproved: true };
}

// AP12: events a stakeholder who does not know a constraint is later surprised by: constraint -> affected stakeholder.
export const EVENTS = {
  C1: "budget owner", C2: "service owner", C3: "budget owner",
  C4: "budget owner", C5: "procurement owner", C6: "service owner",
};

// One narrative's total across the three stakeholders. Stakeholders are informed separately.
export function runNarrative(narrative, extraVocabulary = []) {
  const carriedByStakeholder = new Map();
  let questions = 0, round = 0, additional = 0;
  for (const s of STAKEHOLDERS) {
    const r = meeting({ ...s, vocabulary: [...s.vocabulary, ...extraVocabulary] }, narrative);
    questions += r.questions; round += r.round; additional += r.additional;
    carriedByStakeholder.set(s.name, r.carried);
  }
  const surprises = Object.entries(EVENTS)
    .filter(([c, name]) => !carriedByStakeholder.get(name).has(c)).map(([c]) => c);
  const combined = new Set([...carriedByStakeholder.values()].flatMap((s) => [...s]));
  const skipped = Object.keys(CONSTRAINTS).filter((c) => !combined.has(c));
  return { statements: narrative.length, questions, round, additional, skipped, surprises, totalRounds: round + surprises.length };
}

Three Narratives of the Same Decision

The decision is singular: converting loan records from a nightly batch transfer to a continuous stream. Narrative A carries the decision’s technical rationale as it is and carries all six constraints. Narrative B tells the same decision in outcome language. Narrative C keeps B’s language and puts the constraints B eliminates back in as plain sentences.

// stakeholder/narrative.mjs — three narratives of the same decision run through the same stakeholder model
import { CONSTRAINTS, STAKEHOLDERS, runNarrative, meeting } from "./model.mjs";

// A: technical-terminology narrative. Carries all six constraints, never mentions cost.
const A = [
  { terms: ["event stream", "queue", "backpressure"], concerns: ["service outage"], constraint: ["C6"] },
  { terms: ["double write", "transition window", "report"], concerns: [], constraint: ["C1", "C3"] },
  { terms: ["version pinning", "risk", "duration"], concerns: ["reversal"], constraint: ["C4"] },
  { terms: ["endpoint", "schema", "contract", "provider"], concerns: ["contract"], constraint: ["C5"] },
  { terms: ["client interface", "staff", "branch"], concerns: ["training"], constraint: ["C2"] },
];

// B: outcome-focused narrative. Addresses every concern, terms are in the organization's own language, eliminates constraints.
const B = [
  { terms: ["reader", "duration", "service outage"], concerns: ["service outage"], constraint: ["C6"] },
  { terms: ["cost", "staff"], concerns: ["cost"], constraint: [] },
  { terms: ["duration", "risk"], concerns: ["reversal"], constraint: ["C4"] },
  { terms: ["branch", "staff", "training"], concerns: ["training"], constraint: [] },
  { terms: ["contract", "provider"], concerns: ["contract"], constraint: [] },
];

// C: outcome-focused narrative + the eliminated constraints put back in plain language.
const C = [...B,
  { terms: ["report", "duration"], concerns: [], constraint: ["C1"] },
  { terms: ["branch", "staff", "training"], concerns: [], constraint: ["C2"] },
  { terms: ["duration", "risk", "cost"], concerns: [], constraint: ["C3"] },
  { terms: ["contract", "provider"], concerns: [], constraint: ["C5"] },
];

console.log(`stakeholders ${STAKEHOLDERS.length}, constraints ${Object.keys(CONSTRAINTS).length}, decisions 1\n`);
console.log("narrative  statements  questions  approval rounds  additional  constraints carried  surprises  total rounds");
console.log("--------- ----------- ---------- ---------------- ----------- -------------------- ---------- ------------");
const result = {};
for (const [name, narrative] of [["A", A], ["B", B], ["C", C]]) {
  const r = result[name] = runNarrative(narrative);
  console.log(`${name.padStart(9)} ${String(r.statements).padStart(11)} ${String(r.questions).padStart(10)} ` +
    `${String(r.round).padStart(16)} ${String(r.additional).padStart(11)} ` +
    `${`${6 - r.skipped.length}/6`.padStart(20)} ${String(r.surprises.length).padStart(10)} ` +
    `${String(r.totalRounds).padStart(12)}`);
}
console.log(`\nconstraints B skips: ${result.B.skipped.join(", ")}`);
console.log(`constraints that become surprises in B: ${result.B.surprises.join(", ")}`);
console.log(`constraints A skips: ${result.A.skipped.length === 0 ? "none" : result.A.skipped.join(", ")}`);
console.log(`constraints C skips: ${result.C.skipped.length === 0 ? "none" : result.C.skipped.join(", ")}`);

console.log(`\nper stakeholder (narrative A):`);
console.log("stakeholder           questions  rounds  additional");
for (const s of STAKEHOLDERS) {
  const r = meeting(s, A);
  console.log(`${s.name.padEnd(20)} ${String(r.questions).padStart(9)} ${String(r.round).padStart(6)} ` +
    `${String(r.additional).padStart(11)}`);
}

console.log(`\nA's cost depends on the listener (technical terms added to the stakeholder vocabulary):`);
console.log("terms added  questions  rounds");
const technical = ["event stream", "queue", "backpressure", "double write", "transition window",
  "version pinning", "endpoint", "schema", "client interface"];
for (const n of [0, 3, 6, 9]) {
  const r = runNarrative(A, technical.slice(0, n));
  console.log(`${String(n).padStart(11)} ${String(r.questions).padStart(10)} ${String(r.round).padStart(7)}`);
}
stakeholders 3, constraints 6, decisions 1

narrative  statements  questions  approval rounds  additional  constraints carried  surprises  total rounds
--------- ----------- ---------- ---------------- ----------- -------------------- ---------- ------------
        A           5         27                8           2                  6/6          0            8
        B           5          0                3           0                  2/6          4            7
        C           9          0                3           0                  6/6          0            3

constraints B skips: C1, C2, C3, C5
constraints that become surprises in B: C1, C2, C3, C5
constraints A skips: none
constraints C skips: none

per stakeholder (narrative A):
stakeholder           questions  rounds  additional
budget owner                 9      3           1
service owner                9      2           0
procurement owner            9      3           1

A's cost depends on the listener (technical terms added to the stakeholder vocabulary):
terms added  questions  rounds
          0         27       8
          3         18       8
          6          9       8
          9          0       5

All the numbers belong to the computation class: they were counted on a deterministic model.

The Cost of Simplification

The technical narrative produces 27 questions for a single decision, and approval from the three stakeholders arrives in 8 rounds. The outcome-focused narrative gets the same decision approved in 0 questions and 3 rounds. If the story stopped at this table, the conclusion would be obvious: outcome language cuts the round count to a third.

The constraint column breaks this conclusion. Narrative B carries two of the six constraints; C1, C2, C3, and C5 stay outside the narrative. These are not decoration: the nightly report is produced fifteen minutes late, staff take training once, old records get double-written for two weeks, and the contract does not change. All four are real consequences of the decision, and all four show up eventually. In the model this counts as 4 surprises, and every surprise adds one more round: B’s total is not 3 but 7.

The real number here is that the outcome-focused narrative’s total gain is from 8 rounds to 7 rounds — that is, a single round. Simplification lowers the conversation’s cost up front and loads it back on at the end. Narrative B is not a wrong narrative; it is an incomplete one, and its incompleteness is measurable.

Narrative C shows this is fixable. Without breaking B’s language at all, it puts the four eliminated constraints back in as four sentences written in the same organizational language. The cost is 9 statements instead of 5 — four more sentences to write. The gain: 0 questions, 0 surprises, 3 rounds total. The same decision gets approved in roughly a third of A’s rounds, and less than half of B’s. The cost of carrying a constraint is paid in writing, not in meetings.

Term Mismatch and Concern Mismatch

The last table shows the technical narrative’s 27 questions are not a property of the decision. As nine technical terms are added to the stakeholders’ vocabulary, the question count drops from 27 to 18, to 9, and to 0. The same decision, told in the same sentences, produces no questions at all once told to a counterpart who knows the technical terms. A narrative’s cost depends on the listener’s vocabulary.

The same table’s second column draws the boundary of this. As the question count drops to zero, the approval round count drops from 8 to only 5, not to 3. The reason is that none of narrative A’s statements mention cost: cost is in the concern set of both the budget owner and the procurement owner, and teaching terms does not close that gap. The model records this as 2 additional statements — two sentences the architect ends up having to say later in the meeting.

These two failures are handled separately. Term mismatch is solved by translation: the same content, in the counterpart’s own vocabulary. Concern mismatch is not solved by translation; the narrative needs a new statement that addresses that concern. A narrative being perfectly simplified does not mean it has answered the stakeholder’s question.

One consequence of this: the per-stakeholder question counts are equal (9, 9, 9) but the round counts are not (3, 2, 3). The service owner grants approval in two rounds because both items in its concern set are already inside the narrative. The difference does not come from the terms; it comes from who is asking about what.

Summary

  • A stakeholder is modeled as a vocabulary and a set of concerns; approval comes when no open question remains and every concern is addressed (AP10, AP11). This model was run on three stakeholders, six constraints, and a single decision.
  • The technical-terminology narrative produced 27 questions and 8 rounds per decision; the outcome-focused narrative produced 0 questions and 3 rounds. Taken alone, this comparison shows outcome language at a third of the cost.
  • The outcome-focused narrative eliminated four of the six constraints (C1, C2, C3, C5), and all four turned into surprises; its total became 7 rounds, not 3. The real gain is 7 rounds against 8, that is, a single round.
  • The narrative that puts the constraints back in plain language gave 0 questions, 0 surprises, and 3 rounds in exchange for writing four more statements: simplification’s loss can be recovered without breaking the language.
  • The technical narrative’s 27 questions depend on the listener’s vocabulary and drop to 0 once nine terms are taught; but the round count drops from 8 to only 5. Term mismatch is solved by translation, concern mismatch by a new statement.

Next Step

This lesson measured the decision’s narrative; it held the decision’s content fixed. The approved decision was a flow change, and behind it was a choice still to make: which tool would carry that flow. The model has not made that choice yet. The next lesson lays out candidates and asks: how does a tool’s maturity and the ecosystem around it turn into a number, and if the choice turns out wrong, what does leaving that tool cost in modules, records, and lines?

To keep your progress and take notes, Log in

My notes

Log in to take notes.

Start typing to search.

↑↓ Esc navigate · open · close