skip to content

What must an engine applying a declarative description do when the desired state already holds?

level: middleimportance: must knowfreq 58%

answer

  1. read, compare, then act on the gap
  2. second application, same effect
  3. target state, never a delta
  4. compare with reality, not a record
  5. one description creates and repairs

basics

~20 s

It must still read reality, compare it with the description, find no gap, and perform no writes. That no-op is idempotence, and it is what lets one description serve as the create path, the repair path and the drift check.

solid answer

~40 s

The engine reads the current state, compares it against what the description asks for, and acts only on the difference — so a run over matching reality inspects everything and changes nothing. The shape that makes this true is read-compare-act per item rather than do-the-operation: `set to 3` instead of `add one`, `ensure exists` instead of `create`. Idempotence is what buys safe retries after a partial failure, a meaningful dry run, and drift detection, because the same description answers "build it", "fix it" and "is it still right?". It is easy to lose: anything that appends, anything that regenerates a value per run, and anything the engine cannot inspect before doing turns the second run into another change.

code

pseudocode · 12 lines
pseudocode
function converge(desired):
    changes = 0
    for each item in desired:
        actual = read(item.id)          // always reads
        if actual is missing:
            create(item)
            changes = changes + 1
        else if actual differs from item:
            update(item)
            changes = changes + 1
        // matching item: neither branch fires, nothing is written
    return changes

go deeper

for a junior

Know the expected outcome of running the same description twice: the first run makes the change, the second finds nothing to do. Be able to say why that is useful — you can re-run after a failure without fearing duplicates.

for a middle

Explain the read-compare-act shape and why phrasing matters: a target state can be re-applied, a delta cannot. Separate idempotence from convergence, and name two things that break it, such as append semantics or a per-run generated value.

for a senior

Bring the operational pay-off: retry after partial failure, a dry run that shows the gap, and a scheduled run used as drift detection. Also be honest about the limit — only properties the engine reads back are actually verified.

for a principal

Treat it as a review standard. Decide what makes an item acceptable in a shared description, how escape hatches must guard themselves, and whether scheduled convergence runs are allowed to act on drift or only to report it.

## What a second run is supposed to do Apply a desired-state description to a system that already matches it, and the correct outcome is: the engine reads everything, compares everything, and writes nothing. That is **idempotence** — applying twice has the same effect as applying once — and on a declarative surface it is not a nice extra, it is the property that makes the whole arrangement usable. It is worth being precise about the quantifier. A second run is not a no-op in the sense of doing nothing at all: it still inspects reality, and if reality has drifted since the first run it will act, because its job is the gap, not the history. The promise is narrower and more useful: **no writes where reality already matches the description**. ## The shape that makes it true Idempotence is not a property the engine can sprinkle on; it comes from how each item is expressed. - **State the target, not the delta.** "Three instances" is idempotent; "add an instance" is not. - **Ensure, do not create.** An operation that first asks whether the thing exists can be run repeatedly; an unconditional create fails or duplicates the second time. - **Compare against reality, not against the last run.** A cached record of what you did drifts away from the world; the world is the thing to read. - **Make the comparison total.** If the description mentions a property the engine never reads back, that property silently drifts and no run ever notices. ## Three properties people blur together | Property | What it promises | How you test it | |---|---|---| | Idempotence | applying twice has the effect of applying once | run it twice on a matching system; the second must write nothing | | Convergence | repeated application reaches the described state from any starting point | start half-built, damaged or empty; run until stable | | Determinism | the same description and state produce the same plan | compare plans across runs and engines | They are independent. A run can converge without being idempotent (it reaches the state, but keeps churning). It can be idempotent and non-deterministic (writes nothing, but would have ordered the work differently). Interviewers who ask about "idempotent config" usually want you to separate at least the first two. ## What breaks it 1. **Append semantics.** An item that adds a line, a member or an entry rather than declaring the whole collection grows on every run. 2. **A value generated per run.** A fresh random suffix, a timestamp, or a name derived from the current time makes every comparison a mismatch, so every run writes. 3. **Properties that cannot be read back.** Anything write-only is invisible to the comparison, and engines usually resolve that either by never touching it again or by rewriting it every time — both are surprises. 4. **Recreating instead of updating.** An item whose only strategy for a mismatch is to destroy and rebuild is disruptive rather than repairing, and any state it held is gone. 5. **The unguarded escape hatch.** A literal procedural step inside an otherwise declarative description runs whenever it is reached, unless you gave it its own check — this is where most lost idempotence actually comes from. 6. **External drift between read and write.** Something else changes the system in the gap between comparison and action, so the write no longer matches the plan. ## What idempotence buys - **Safe retry.** A run that failed half-way can simply be run again; the items already done are no-ops and the rest proceed. - **A meaningful dry run.** Because the engine computes the gap before acting, it can show you the gap without acting — which is what makes review of a change possible before it lands. - **Drift detection.** Scheduling the same description on a timer turns it into a monitor: a run that suddenly wants to write is telling you something changed underneath you. - **One description, three jobs.** Create, repair and verify stop being three different artifacts that can disagree with one another. ## How to check it in review Read every item and ask: *if this were applied to a system where it is already true, what would happen?* If the honest answer is "it would do it again", the item is a delta or an unguarded step dressed as a declaration, and it should be rewritten to name the target state. Then run the description twice on a fresh system and require the second run to report no changes — an engine that cannot tell you that is one you cannot use for drift detection either.

  • How is idempotence different from convergence?
    Idempotence is about the second application: on a system that already matches, it writes nothing. Convergence is about reaching the target at all: from any starting point — empty, half-built, damaged — repeated application ends at the described state. A run can converge while churning on every pass, which is convergent but not idempotent, and that churn is what hides real change in the noise.
  • Which kinds of item most often destroy idempotence?
    Anything phrased as a delta rather than a target: add a member, append an entry, increment a count. Anything whose value is regenerated each run, such as a fresh suffix or a timestamp, because the comparison can never match. And an unguarded literal step inside an otherwise declarative description, which executes every time it is reached unless you wrote its own precondition.
  • If a run writes nothing, has the engine actually verified anything?
    Only the properties it reads back. A description can mention attributes the engine never inspects, and those drift invisibly — no run will ever report them as a difference. So "no changes" means "no gap in what was compared", which is why it matters to know which properties a given engine actually reads.

saying these in an interview costs you the question

  • A second run must repeat the same operations
  • Idempotence means the engine skips reading the current state
  • Add-one and set-to-three are equally safe to re-run
  • Comparing against a record of the last run is as good as reality
  • No changes reported proves every described property is correct
  • Idempotence and convergence are two names for one property