# Postmortem: Silent Failure in Google Sheets Macro Due to Missing Write Operation
## Summary
A Google Sheets macro was created to add a value from cell B21 to cell B4. Despite correct value calculation, the updated result wasn't saved because the script lacked a write operation to persist changes to the spreadsheet.
## Root Cause
- **Missing sheet update call**: The script calculated `HomeScore = HS + HP` but never wrote this value back to the sheet
- **Variable scope confusion**: Re-declaring `HomeScore` as a local variable instead of updating the cell
- **No range assignment**: Failure to use `setValue()` to push the calculated result to cell B4
## Why This Happens in Real Systems
- Automated tools often abstract persistence mechanics, leading developers to assume automatic write-backs
- Transitioning between different automation environments (e.g., Excel VBA vs. Google Apps Script) causes API misunderstandings
- Logic focus shifts from I/O operations to calculation steps during development
- Stack Overflow examples often omit "obvious" persistence steps
## Real-World Impact
| Impact Area | Consequences |
|--------------------|---------------------------------------------|
| **Data Accuracy** | Correct calculations not reflected in reports |
| **Decision Making** | Stakeholders receive outdated metrics |
| **User Trust** | Repeated failures reduce confidence in automation |
## Example or Code
**Original Code (Flawed):**
```javascript
function SimPossession() {
var spreadsheet = SpreadsheetApp.getActive();
var PossessionSim = spreadsheet.getSheetByName('Possession Simulation');
var HomeScore = PossessionSim.getRange("B4").getValue();
var HomePossession = PossessionSim.getRange("B21").getValue();
var HomeScore = HomeScore + HomePossession; // Never saves to sheet
}
Corrected Code:
function SimPossessionFixed() {
var sheet = SpreadsheetApp.getActive()
.getSheetByName('Possession Simulation');
var updatedValue = sheet.getRange("B4").getValue() +
sheet.getRange("B21").getValue();
sheet.getRange("B4").setValue(updatedValue); // Critical write step
}
How Senior Engineers Fix It
- Trace data flow: Verify each variable’s read/write path through execution
- API contract validation: Confirm setValue() is called appropriately
- Boundary checks: Add logs with
Logger.log()before/after write operations - Idempotency guard: Prevent duplicate writes with
Sheet.flush() - Regression test: Create unit test that:
function testSimPossession() { const initialValue = 5; sheet.getRange("B4").setValue(initialValue); SimPossessionFixed(); const newValue = sheet.getRange("B4").getValue(); if (newValue <= initialValue) throw "Write failed!"; }
Why Juniors Miss It
- 🔍 API unfamiliarity: Assumption that
.getValue()/.setValue()work symmetrically - 🧠 Mental model mismatch: Applying Excel VBA persistence patterns to Google Apps Script
- ⏱️ Overfocus on arithmetic: Reading/calculating values feels like “real work” vs. “administrative” I/O
- 🌫️ Abstraction blindness: Mistaking ranges as direct value containers rather than references
graph LR A[Junior's Flow] --> B[Read Data] B --> C[Compute] C --> D[Assume Persistence]
E[Actual Flow] –> F[Read Data]
F –> G[Compute]
G –> H[Explicit Write]