Loading…
Loading…
A concrete schema for tracking software development cost without organising everything around development stages, and what each table is for.
If the stage column is the weak point in a capitalization tracker, the obvious question is what replaces it. This article is the concrete answer: four layers, what belongs in each, and why the separation matters.
This is a systems design piece. It says nothing about which costs should be capitalized, which is your accounting policy and your accountants' decision. It is about where that policy lives once it has been decided, so that acting on it does not require rebuilding a spreadsheet every quarter.
The design that survives a change of categories separates four things that a spreadsheet usually merges into one grid.
1 ACTIVITY what happened, as a fact
2 ALLOCATION how effort divides across projects
3 POLICY rules that turn activity into a treatment
4 OUTPUT schedule, journal, and the evidence trail
Each layer only depends on the one above it. Change layer 3 and layers 1 and 2 are untouched. That property is the whole point.
The base layer records what happened, with no interpretation applied. One row per unit of work per period.
| Field | Holds | Comes from |
|---|---|---|
| person_id | Who did the work | HR or payroll |
| project_id | What they worked on | Project system |
| period | Which month or sprint | Project system |
| effort | Hours, points, or a percentage | Project or source control |
| cost_basis | The loaded cost for that effort | Payroll |
| source_ref | Pointer to the underlying record | Project system, payroll run |
Two things about this table matter more than its exact columns.
It contains no treatment. There is no capitalize flag and no stage. A row says an engineer spent time on a project and it cost this much. That statement does not expire when guidance changes.
source_ref is not optional. It is the field that turns an amount into something you can stand behind. Without it, the number is an assertion. With it, the number is a claim with a receipt.
Most engineers do not work on one thing. Allocation is how a person's cost for a period divides across the projects they touched.
The mistake here is treating allocation as a monthly judgement call. It should be derived from something already recorded: sprint assignment, ticket time, or commits against a repository mapped to a project. Derived allocation has two advantages over estimated allocation. It is consistent, because the same rule runs every period. And it is defensible, because the derivation is inspectable.
Where a derivation genuinely is not possible, record that the number is an estimate and who made it. An estimate labelled as an estimate is fine. An estimate indistinguishable from a measurement is the problem.
This is where your accounting policy lives, and the only layer that changes when guidance changes.
A policy rule reads activity and allocation, and outputs a treatment. Expressed plainly, a rule looks like:
WHEN project.type IN (...)
AND activity.kind IN (...)
AND project.status = ...
THEN treatment = capitalize
ELSE treatment = expense
Three properties are worth insisting on.
Rules are configured, not coded. A rule you can read and change without a deployment is a rule your controller can own. A rule buried in a formula is a rule only its author can change.
Rules are versioned with dates. When policy changes, the old rule does not get overwritten. It gets an end date and the new rule gets a start date. That is what lets you answer how a prior period was treated without reconstructing it, and it is the difference between a system that can restate and one that cannot.
Rules produce a reason, not just an answer. The output records which rule fired. That reason is what makes the schedule readable a year later, by someone who was not there.
The last layer is the part the ERP already does well, plus the part it does not.
The schedule, the journal, and the amortization all belong here. So does the evidence trail, which is the join back through layers 3, 2, and 1 to source_ref. That join is what makes a number answerable: from a balance you can reach the rule, from the rule the allocation, from the allocation the activity, and from the activity the record it came from.
Your ledger takes the resulting asset and depreciates it. It is good at that. What it does not do is hold layers 1 through 3, which is why those layers currently live in a spreadsheet.
The test of this design is not whether it is tidier. It is what happens on the day the categories change.
In a stage-organised spreadsheet, that day means: reread every row, retag against a vocabulary that did not exist when the row was written, rebuild formulas, rebuild pivots, and hope nothing was missed. Prior periods cannot be restated under the new framing without redoing all of it.
In the layered design, that day means: write new rules with a start date. Activity and allocation are untouched, because they never encoded the old vocabulary. Prior periods can be reported under either set of rules, because the rules are data rather than structure.
That is the difference between one afternoon and one quarter.
Little of this needs new infrastructure. Layers 1 and 2 are usually already in project systems, source control, and payroll. Layer 4 is largely your ERP. The work is layer 3 and the plumbing between them: getting activity out of the source systems, holding rules where a controller can edit them, and keeping source_ref intact all the way through so the evidence trail actually joins.
Not sure where your process sits?
Seven questions, three minutes. Score your capitalization process and see the gaps.