Temporary Field¶
The code smell in which an object carries an instance variable meaningful only during one operation or state yet visible as permanent structural state everywhere — a mismatch between the field's structural scope (every instance) and its validity scope (the subset where it holds a real value).
Core Idea¶
Temporary field is the code-smell pattern, named by Martin Fowler in the Refactoring catalog, in which an object carries an instance variable that is meaningful only during one specific operation or in one specific state — populated during a password-reset flow, relevant only when an order is canceled, set transiently during a complex calculation — while remaining visible as permanent structural state on every instance in every other circumstance, where it holds null, a default, or a stale value. The field misrepresents the object: it promises by its structural position that every instance of the type always carries this piece of information, when in fact only some instances, or only instances during particular operations, do.
The structural mismatch is between the structural scope of the field — the entire class, every instance — and its validity scope — the subset of instances or lifetimes in which the field has a defined, meaningful value. When these scopes diverge, every consumer of the object must either know by convention to ignore the field except when it is valid (a convention that is invisible to the compiler and frequently violated), defensively null-check the field before each use (which propagates the conditional logic across the codebase), or use the field without checking and risk a null-pointer fault or semantically incorrect result. The named refactoring move — extract the operation that needs the field into a method object, a separate class whose instances exist only for the duration of that operation — restores correspondence between structural scope and validity scope: the field lives on the method object, which is instantiated and discarded exactly when the field is meaningful, and the original class no longer carries conditional state.
Structural Signature¶
Sig role-phrases:
- the carrier object — a class, record, or aggregate that holds the conditional state as a structural field
- the conditional state — data operationally meaningful only in a subset of the carrier's lifetimes or use-cases (a reset token, a cancellation reason, a transient calculation value)
- the structural scope — every instance of the type, where the field's position promises the information is always carried
- the validity scope — the narrower subset of instances or operations in which the field actually holds a defined, meaningful value
- the scope mismatch — structural scope exceeding validity scope, so the field is null, default, or stale wherever the two diverge
- the defensive contamination — every consumer forced to cope by ignore-it convention (fragile), propagated null-checks (leaking the conditional), or unchecked use (faults and wrong results)
- the split-the-type remedy — relocate the field onto an object whose lifetime matches the validity scope, selected by its shape: method object for a transient operation, state subtype/sum type for a mode, separate associated record for a long-lived conditional association, optional/Maybe when genuinely optional
What It Is Not¶
- Not just "a field that's sometimes null." That phrasing names a symptom; the diagnosis names the cause — the field's structural scope (every instance, by its position in the class) exceeds its validity scope (the subset of lifetimes where it holds a meaningful value). The null-ness is not an accident of one code path but a designed-in scope mismatch that every consumer must pay for.
- Not fixed by null-checking. Defensive null-checks before each use are the wrong branch: they cement the misalignment and spread the conditional logic further across the codebase. The correct remedy is structural — relocate the field onto an object whose lifetime matches its validity (method object, state subtype, separate associated record, optional type), so the conditional state lives only where it is meaningful.
- Not a genuinely optional field. A nullable field whose absence is itself meaningful — where "no value" is a real, defined state of every instance — has a validity scope equal to the whole type, so there is no mismatch and no smell. Temporary field fires only when the field is structurally permanent but operationally meaningful in just a subset of lifetimes.
- Not a documented precondition. A field with a stated contract ("valid only after
initialize()") expresses its conditionality; that is a contract, not a mismatch. The diagnosis applies specifically when the conditional validity is left unexpressed in the type, so consumers must discover it by convention, defensive check, or crash. - Not lazy class or data class. Lazy class is responsibility-magnitude misalignment (an abstraction doing too little); temporary field is state-shape misalignment (conditional state encoded as unconditional structure). A data class has fields but no behaviour — a different smell that can co-occur. The mechanism here is specifically the scope gap, not under-loading or behaviour-absence.
Scope of Application¶
Temporary field lives across the object-oriented-design and data-modelling subfields of software and computing; its reach is bounded to that domain (the more general "scope of state should match scope of its validity" principle that recurs in statute drafting, org policy, and configuration is handled there by each domain's own machinery and carried at the catalogue level by parent primes such as modularity and abstraction, not by this OO diagnostic).
- Object-oriented design — the canonical home: a
Usercarrying password-reset token/expiry fields set only during a reset, anOrdercarrying acancellationReasonset only when canceled. - Database schema design — its clean relational counterpart: columns meaningful only when other columns take certain values, resolved by the same scope-matching move (normalization into a separate table).
- UI / form design — relationship-dependent fields shown regardless of relevance, the UI-side analog where conditional-display logic is the proper fix.
- Type-system-rich functional code — where sum types / algebraic data types let the conditional validity be encoded directly in the type rather than as nullable structural state.
Clarity¶
Naming temporary field promotes a scatter of symptoms into a single structural diagnosis. Without the label, the situation surfaces only as local complaints — "this field is sometimes null," "ignore cancellationReason unless the order is canceled," a null-pointer crash in the reporting path — each describing a place where the field misbehaves but none naming why. The concept supplies the cause: the field's structural scope (every instance of the type, by its position in the class) is wider than its validity scope (the subset of instances or lifetimes where it holds a meaningful value). Holding those two scopes apart is the whole clarifying act — it tells the reader that the null-ness is not an accident of one code path but a designed-in mismatch that every consumer must pay for, by convention, by defensive checking, or by bug.
That same distinction sharpens the question of what to do about it. Once the problem is read as scope-mismatch rather than as "a field that's often null," the obvious remedy — null-check before each use — is visibly the wrong one: it cements the misalignment and spreads the conditional logic further across the codebase. The legible alternative is structural: make the field's structural scope match its validity scope by splitting the type — extract a method object whose lifetime is exactly the operation that needs the field, or model the conditional state as a subtype or separate associated record. So the practitioner's question stops being the defensive "where might this field be null?" and becomes the structural "what is the actual lifetime over which this state is meaningful, and which object should own it?" — and the field is moved onto an object that exists only when, and only where, the field means something.
Manages Complexity¶
A type whose fields are only conditionally meaningful generates a diffuse maintenance burden that, untracked, manifests as scattered unlike incidents: a null-pointer crash in the settlement path, a reporting query surfacing NULL rows that must be filtered, a code review flagging an ignore-this-unless convention, an onboarding engineer asking when cancellationReason is populated. Each looks like a separate local defect calling for its own local patch — add a null-check here, a filter there, a comment somewhere. Temporary field compresses that whole scatter into one quantity the maintainer tracks: the gap between a field's structural scope (every instance of the type, fixed by the field's position in the class) and its validity scope (the subset of instances or lifetimes where the field holds a defined value). Every one of those incidents is read off as the same thing — a consumer forced to cope with structural state that is invalid in its context — so the maintainer stops cataloging symptoms and instead measures one mismatch per field. The diagnosis is a single comparison of two scopes, not an open-ended inventory of where the field misbehaves.
That single quantity also collapses the remedy space, which is what keeps the management tractable rather than merely diagnostic. Once the problem is the scope gap, the defensive move that each local symptom invites — null-check before use — is visibly the wrong branch, because it cements the misalignment and propagates the conditional logic further; the correct branch is always the structural one of making structural scope match validity scope. And that structural branch resolves to a short, fixed menu selected by the shape of the validity scope: if validity is a transient operation, extract a method object whose lifetime is exactly that operation; if validity tracks a mode or state, extract a state subtype or sum type that owns the field; if validity is a long-lived but conditional association, use a separate associated record joined only when needed; if the state is genuinely optional rather than mode-specific, an optional/Maybe type makes the conditionality part of the contract. So the maintainer's question contracts from the diffuse "where might this field be null, and what do I do at each site?" to a uniform two-step: measure the scope gap, then read the remediation off the validity scope's shape. A wide field of independent null-handling decisions becomes one mismatch measurement feeding one small, deterministic branch — the move from re-deriving a fix at every consumer to reading the owning object off a single structural parameter.
Abstract Reasoning¶
Temporary field licenses moves that read a type's structure as a set of promises and check them against operational reality. The core diagnostic runs from a scatter of symptoms to a single structural cause: a null-pointer crash in the settlement path, NULL rows a reporting query has to filter, an "ignore cancellationReason unless the order is canceled" convention, an onboarding question about when a field is populated — the engineer reads all of these as one fact, that the field's structural scope (every instance of the type, fixed by its position in the class) exceeds its validity scope (the subset of instances or lifetimes where it holds a meaningful value). The surface signature is the field misbehaving at a particular site; the inferred cause is a designed-in scope mismatch that every consumer must pay for. This is reasoning FROM "this field is sometimes null" TO "conditional state has been encoded as unconditional structure," and it is what turns a list of local defects into one diagnosis.
A predictive move follows from the same reading: because a field promises by its structural position that every instance always carries the information, the analyst can forecast, before reading the consuming code, that consumers will have coped in one of three ways — an invisible ignore-it convention (fragile, compiler-unchecked, frequently violated), defensive null-checks propagated across the codebase (the conditional logic leaking outward), or unchecked use that faults or returns a semantically wrong result. Predicting which coping strategy a given consumer used, and where the next null-fault will surface, comes straight from the scope gap.
The interventionist move is structural and explicitly rejects the obvious local fix. The remedy a single symptom invites — null-check before each use — is the wrong branch, because it cements the misalignment and spreads the conditional further; the reasoner predicts that defensive checking makes the smell worse, not better. The correct branch is always to make structural scope match validity scope by relocating the field onto an object whose lifetime is exactly the field's validity, and the prediction is concrete: pricing, settlement, and history paths stop having to know about the conditional state once it moves off the shared type, and only the operation that genuinely needs the field carries it.
The decisive move is boundary-drawing on the shape of the validity scope, which selects among remedies and also separates temporary field from look-alikes. The reasoner classifies why the field is conditional and routes accordingly: if validity is a transient operation, extract a method object instantiated and discarded with that operation; if validity tracks a mode or state, extract a state subtype or sum type that owns the field; if validity is a long-lived but conditional association, use a separate associated record joined only when needed; if the state is genuinely optional rather than mode-specific, an optional/Maybe type makes the conditionality part of the contract. Reasoning FROM the shape of the validity scope TO the owning object is what makes the remediation deterministic. The same boundary excludes neighbors: a nullable field whose absence is itself meaningful is not a temporary field (the validity scope is the whole type), and a field with a documented precondition is a contract, not a mismatch — the diagnosis fires only when conditional validity is left unexpressed in the type.
Knowledge Transfer¶
Within software the smell transfers as mechanism across object-oriented design and the data-modelling work adjacent to it. The diagnostic — measure the gap between a field's structural scope (every instance, fixed by its position in the type) and its validity scope (the subset of lifetimes where it holds a defined value) — and the remedy menu selected by the shape of the validity scope (method object for a transient operation; state subtype or sum type for a mode; separate associated record for a long-lived conditional association; optional/Maybe when the state is genuinely optional) carry intact. The named refactorings travel together: extract-method-object, replace-nullable-with-optional, state-pattern refactoring, algebraic data types where the language supports them. The pattern even has a clean relational counterpart inside software — database normalization is the same scope-matching move applied to columns meaningful only when other columns take certain values, and conditional form-display logic is its UI-side analog. Across these the conditional-state-encoded-as-unconditional-structure diagnosis and the split-the-type response mean the same thing — mechanism, recognised across the subfield.
Beyond software the honest account is the shared-abstract-mechanism case, with one sharpening the entry must not blur: the more-general balance the scope of state should match the scope of its validity genuinely recurs across substrates — statutory definitions or schedules that apply only under named conditions yet sit in the main text as if always applicable (legal drafting), a "remote-work approval status" field on every employee record but meaningful only for some roles (organisational policy), configuration keys present in every deployment's config but read only by certain feature flags (configuration management), relationship-dependent form fields shown regardless of relevance (form design). But in each of these the conditional structure is already handled by the domain's own established machinery — relational normalization, statutory schedules, employee-record schema design, conditional-display rules, feature-flag systems — not by importing the object-oriented temporary-field diagnostic, which is calibrated against OO design norms and relies on type-system and refactoring machinery (method objects, sum types) that those substrates do not share. So what travels is the abstract principle, which the catalogue partially carries through the parent primes modularity (factor a unit's conditional state into a separate unit), abstraction (this is the failure mode where an abstraction misrepresents the validity scope of its state), and cohesion/encapsulation-adjacent content — and which may merit a future dedicated prime ("state-validity-scope correspondence"). The cross-domain lesson should carry that general principle and let each domain apply its own machinery; "temporary field," as named, stays the OO code smell, too tightly bound to its substrate to serve as the portable structure itself (see Structural Core vs. Domain Accent).
Examples¶
Canonical¶
Consider an Order class with fields id, items, total — plus cancellationReason and cancelledAt, set only when the order is canceled. For every order that ships normally (the vast majority) those two fields sit null. A reporting query that reads cancellationReason across all orders returns mostly NULL rows; a settlement path that touches it must null-check or risk a null-pointer fault; a new engineer must learn by convention that the field means something "only when status == CANCELLED." Fowler's remedy is to extract a Cancellation object — a method object or a Cancelled state/subtype — that exists only for canceled orders and owns those fields, leaving Order free of conditional state.
Mapped back: Order is the carrier object and cancellationReason/cancelledAt the conditional state; every Order carrying the field is the structural scope while only-canceled-orders is the validity scope; the null fields on shipped orders are the scope mismatch driving the defensive contamination; and extracting a Cancellation object whose lifetime is exactly the canceled state is the split-the-type remedy.
Applied / In Practice¶
The identical scope-matching move is the everyday content of relational database normalization. Suppose an employees table gains columns termination_date and termination_reason, meaningful only for former staff. For current employees they are perpetually NULL, queries must filter them, and a NOT NULL constraint is impossible. Normalization resolves it by extracting a separate terminations table keyed by employee_id, holding a row only for employees who have actually left — so the columns exist exactly where they are valid. This is the same diagnosis and the same remedy, applied with the database's own machinery rather than the object-oriented refactoring toolkit.
Mapped back: The employees table is the carrier object and the termination columns the conditional state; all rows carrying the column is the structural scope, former employees the validity scope; the perpetual NULLs are the scope mismatch; and the separate terminations table joined only when needed is the split-the-type remedy in its separate-associated-record form — the relational counterpart the entry names explicitly.
Structural Tensions¶
T1: The locally-obvious fix versus the structural cause (each symptom demands the wrong patch). Every place the smell surfaces — a null-pointer crash, NULL rows a report must filter, an "ignore this unless canceled" convention — locally invites the smallest patch: add a null-check, add a filter, add a comment. Those patches each work at their site, which is exactly what makes them seductive and dangerous: they cement the scope mismatch and propagate the conditional logic further across the codebase, so the diffuse maintenance burden grows with every defensive fix. The correct move is structural — relocate the field onto an object whose lifetime matches its validity — but it requires refusing the patch the symptom is demanding and touching code far from where the pain appeared. The tension is that the fix each incident calls for is the one that worsens the underlying defect, and the fix that resolves the defect is invisible from any single incident. Diagnostic: Is the response a defensive null-check/filter at the failing site (cements the mismatch), or a relocation of the field onto an object whose lifetime matches its validity (dissolves it)?
T2: Scope correspondence versus structural proliferation (the cure can be heavier than the disease). The remedy restores correspondence by splitting the type — method objects, state subtypes, separate associated records — so the field lives only where it is meaningful. That is right in principle, but applied indiscriminately it multiplies classes, tables, joins, and indirection, fragmenting a cohesive concept into a swarm of transient objects for a field that was only occasionally null. The relational counterpart makes the trade explicit: full normalization matches column-scope to validity exactly, yet mature practice sometimes denormalizes on purpose, tolerating the conditional column for query simplicity or performance. So the scope-correspondence the smell demands competes with cohesion, performance, and plain simplicity, and there is a real judgment about when a nullable field is the lesser evil. The tension is that the structural purity the diagnosis prescribes has a genuine cost the diagnosis alone does not price. Diagnostic: Does the conditional state's rarity and independence justify splitting the type, or would the split's proliferation of objects/joins cost more than the nullable field it removes?
T3: A structural diagnosis that depends on unexpressed intent (the same nullable field is a smell or not). The diagnosis claims to read structure objectively — compare structural scope to validity scope — yet whether a given nullable field is a temporary field turns on a semantic fact the structure does not encode: is the field's absence itself meaningful (a genuinely optional field, validity scope = whole type, no smell), or is conditional validity being silently left unexpressed (the smell)? A field with a documented precondition is a contract, not a mismatch. So two byte-identical nullable fields can be one a smell and one not, distinguished only by designer intent about what "no value" means. The tension is that a diagnosis presented as reading structure actually rests on an intent judgment invisible in the code it critiques, which is exactly why the smell resists purely automated detection. Diagnostic: Is the field's absence a real, defined state of every instance (optional, no smell) or an unexpressed conditional validity consumers must discover by convention (the smell)?
T4: A deterministic remedy menu versus the classification it hides (the mechanical fix rests on a modeling call). The concept advertises a clean, deterministic remedy: read the shape of the validity scope and route accordingly — method object for a transient operation, state subtype/sum type for a mode, separate associated record for a long-lived conditional association, optional/Maybe when genuinely optional. But that determinism is entirely downstream of correctly classifying why the field is conditional, and that classification is the hard, judgment-laden step. Misread a mode as a transient operation and you extract a method object where a state subtype belonged; misread genuinely optional state as mode-specific and you over-engineer a subtype hierarchy. The tension is that the apparatus looks mechanical — measure the gap, read off the fix — while its correctness hinges on a modeling decision about the state's real lifetime that the menu presupposes rather than makes. Diagnostic: Has the validity scope's shape (transient operation vs mode vs long-lived association vs genuinely optional) actually been established, or is a remedy being read off a misclassification?
T5: Autonomy versus reduction (an OO code smell, or the state-validity-scope-correspondence principle). Within software the smell transfers as mechanism — the scope-gap diagnosis and the split-the-type menu carry across OO design, its named refactorings, database normalization, and conditional UI display, because those substrates share type systems and refactoring machinery. But the general balance it embodies — the scope of state should match the scope of its validity — genuinely recurs beyond software: statutory schedules that apply only under named conditions yet sit in the main text, a remote-work-status field meaningful only for some roles, config keys read only by certain feature flags. In each, the conditional structure is already handled by the domain's own machinery (statutory schedules, schema design, feature-flag systems), not by importing an OO diagnostic calibrated against method objects and sum types those substrates lack. What travels is the abstract principle, carried at the catalogue level by modularity, abstraction, and cohesion (and perhaps a future "state-validity-scope correspondence" prime); "temporary field," as named, stays the OO smell. The tension is between a fully specified code smell and the recognition that its portable content is a substrate-neutral correspondence principle each domain implements its own way. Diagnostic: Resolve toward the general principle (state scope should match validity scope) and the domain's own machinery when the substrate is not OO software; toward the named smell when the fix is a method object, sum type, or normalized table.
Structural–Framed Character¶
Temporary field sits at the framed-leaning position on the structural–framed spectrum — closer to the framed pole than a neutral mechanism like isostasy, because it is a normatively charged defect diagnosis constituted by a design practice, though it rests on an unusually crisp structural skeleton that keeps it off the pole itself. Three criteria point firmly framed. Its evaluative weight is high: "smell" is a verdict, not a description — to call a field a temporary field is to convict the design, to say the state-shape is wrong and ought to be refactored, exactly as "fallacy" convicts an argument. It is strongly human-practice-bound: the diagnosis exists only within the practice of object-oriented design, code review, and refactoring, and it dissolves the moment that practice is removed — strip away the engineers who read structure as a set of promises and the maintainers who pay for the mismatch, and what remains is a plain instance variable that is sometimes null, with no "smell" anywhere, because a smell is a thing a practitioner discerns, not a fact the code holds independent of anyone judging it (the entry's own T3 makes this decisive: two byte-identical nullable fields can be one a smell and one not, distinguished only by unexpressed designer intent). Its institutional origin is explicit and specific: the concept is a named entry in Fowler's Refactoring catalog, taxonomic furniture of a particular engineering tradition, complete with its remedy menu (method object, state subtype, sum type) drawn from that tradition's toolkit — an artifact of a discipline, not a fact of nature. On vocab_travels it is domain-pinned: within software the diagnosis carries as mechanism across OO design, relational normalization, and conditional UI display (substrates that share type systems and refactoring machinery), but the moment the substrate is not OO software the operative vocabulary — method objects, sum types, null-checks — loses its referents. And on import_vs_recognize it patterns as recognition inside software but as analogy beyond it, where the general principle recurs only under each domain's own machinery.
The one feature that pulls back toward structure — and it pulls harder here than in a pure verdict-label like ad hominem — is the portable skeleton the entry isolates: state-validity-scope correspondence, the substrate-neutral balance that the structural scope of a piece of state should match its validity scope, with conditional state factored into a unit whose lifetime matches the subset where it is meaningful. That skeleton is genuinely portable — it recurs in statutory schedules, org-policy fields, and configuration keys — and the entry candidly flags it as possibly meriting its own future prime. But it does not lift temporary field off the framed side, because that correspondence principle is precisely what temporary field instantiates from its umbrella primes — modularity (factor a unit's conditional state into a separate unit), abstraction (the failure mode where an abstraction misrepresents the validity scope of its state), and cohesion — not what makes "temporary field" itself travel: the cross-domain reach belongs to the scope-correspondence pattern carried by those parents, while the named entry's distinctive content — the "smell" verdict, Fowler's catalog placement, and the OO refactoring remedy menu — is exactly the part that stays home on the software substrate. Its character: a normatively charged, practice-constituted OO code-smell verdict, structural only in the state-validity-scope-correspondence skeleton it borrows from modularity and abstraction and frames as a design defect.
Structural Core vs. Domain Accent¶
This section decides why temporary field is a domain-specific abstraction and not a prime, and it carries the case for its domain-specificity in the same move.
What is skeletal (could lift toward a cross-domain prime). Strip the code and a thin relational structure survives: the scope over which a piece of state is structurally present should match the scope over which it is actually valid; where structural scope exceeds validity scope, factor the conditional state into a unit whose lifetime matches the subset where it is meaningful. The portable pieces are abstract — a carrier that advertises some state as always-present, a narrower set of circumstances in which the state truly holds, and a re-organization that relocates the state to a unit scoped to its real validity. That skeleton is modularity (factor conditional state into its own unit), abstraction (the failure mode where an abstraction misrepresents the validity of the state it exposes), and cohesion (keep in a unit only what belongs to its whole lifetime), and it is genuinely substrate-portable — a state-validity-scope-correspondence principle the entry candidly flags as possibly meriting its own future prime. But it is the core temporary field shares with those parents, not what makes it the particular thing it is.
What is domain-bound. Almost everything that makes the concept temporary field in particular is object-oriented-design furniture that does not survive extraction. The "smell" verdict, its place in Fowler's Refactoring catalog, and above all the remedy menu — extract a method object whose lifetime is the operation, a state subtype or sum type for a mode, a separate associated record for a long-lived conditional association, an optional/Maybe type when genuinely optional — are the worked vocabulary and instruments of a specific engineering tradition, calibrated against OO design norms and relying on type-system and refactoring machinery. The pattern's clean travel to relational normalization and conditional UI display works precisely because those substrates share that machinery (tables, columns, null constraints, display rules). The decisive test is constitutive, and the entry's own T3 supplies it: two byte-identical nullable fields can be one a smell and one not, distinguished only by unexpressed designer intent about whether "no value" is a real state — so strip away the engineers who read structure as a set of promises and the maintainers who pay for the mismatch, and what remains is a plain instance variable that is sometimes null, with no "smell" anywhere. The defect is a thing a practitioner discerns, not a fact the code holds independent of anyone judging it.
Why this does not clear the prime bar. A prime is a relational structure whose vocabulary travels and whose cross-domain transfer is recognition of the same mechanism, not analogy. Temporary field's transfer is bimodal. Within software it travels as mechanism: the scope-gap diagnosis and the split-the-type remedy menu carry intact across OO design, its named refactorings, database normalization, and conditional form-display, because those substrates share type systems and refactoring tools — genuine recognition. Beyond software the general balance — the scope of state should match the scope of its validity — genuinely recurs (statutory schedules that apply only under named conditions but sit in the main text, a remote-work-status field meaningful only for some roles, config keys read only by certain feature flags), but in each the conditional structure is already handled by the domain's own machinery (statutory schedules, schema design, feature-flag systems), not by importing the OO diagnostic, whose method objects and sum types those substrates lack. That is the tell that the reach is analogy at the level of the named smell and recognition only at the level of the principle. And when the bare structural lesson is wanted cross-domain, it is already carried, in more general form, by the parents temporary field instantiates — modularity, abstraction, and cohesion (with a "state-validity-scope correspondence" prime a plausible future home). The cross-domain reach belongs to those parents; "temporary field," as named, carries the "smell" verdict, Fowler's catalog placement, and the refactoring menu as baggage too tightly bound to the OO substrate to travel.
Relationships to Other Abstractions¶
Current abstraction Temporary Field Domain-specific
Parents (1) — more general patterns this builds on
-
Temporary Field is a kind of Code Smell Domain-specific
Temporary Field is the code-smell species whose always-present field provides defeasible evidence that structural scope exceeds the state item's validity scope.It inherits an observable trace, hidden design hypothesis, contextual test, predicted misuse cost, and behavior-preserving refactoring probe. The child adds conditional object state and extraction into a method object, sum type, or other unit whose lifetime matches the field's validity scope.
Hierarchy paths (4) — routes to 4 parentless roots
- Temporary Field → Code Smell → Evidence → Provenance → Traceability → Observability
- Temporary Field → Code Smell → Evidence → Provenance → Attestation → Authentication
- Temporary Field → Code Smell → Evidence → Provenance → Traceability → Transformation → Function (Mapping)
- Temporary Field → Code Smell → Evidence → Provenance → Custody Transfer → State and State Transition → Phase Space
Not to Be Confused With¶
-
Java
transientfield (serialization modifier). A near-perfect name collision: thetransientkeyword marks a field to be skipped during serialization, a persistence directive with nothing to say about design quality. Temporary field is a scope-mismatch code smell — conditional state encoded as unconditional structure. A field can betransientand perfectly well-shaped, or a temporary field and fully serialized. Tell: is the property about whether the field is written out on save (thetransientkeyword) or about whether its structural scope exceeds its validity scope (the smell)? -
Speculative generality (Fowler sibling smell). The neighbouring code smell in which a field, parameter, or hook is added for an anticipated future use that has not arrived, so it sits unused today. Temporary field's state is used — but only in a subset of lifetimes, where it holds a real value; speculative generality's is used in no lifetime yet. Tell: is the field meaningful in some current operations and null elsewhere (temporary field), or meaningful in none of them because it exists only for a hypothetical future (speculative generality)?
-
Lazy class and data class (Fowler sibling smells). Neighbouring catalog entries that can co-occur: lazy class is responsibility-magnitude misalignment (an abstraction doing too little to justify itself), and data class is a type with fields but no behaviour. Temporary field is state-shape misalignment — the scope gap — and is orthogonal to how much the class does or whether it has methods. Tell: is the complaint that the unit carries too little responsibility (lazy class) or no behaviour (data class), or specifically that a field is structurally permanent yet valid only conditionally (temporary field)?
-
A field that should be a local variable or parameter. The near-miss where transient calculation state was promoted to an instance field purely to pass it between methods, when a local variable or an explicit parameter would do. This overlaps temporary field's method-object remedy but is a simpler fix — demote to a local — for state whose validity is a single method call, not a mode or a conditional association. Tell: does the state's validity span exactly one method invocation (demote to a local/parameter) or a broader-but-still-conditional lifetime that warrants its own object, subtype, or record (temporary field proper)?
-
Database normalization (the relational counterpart, not a rival). Splitting columns meaningful only when other columns take certain values into a separate table. This is not a different concept to be told apart — it is the identical scope-matching move applied with the database's own machinery, one of the entry's own worked examples. It is listed here only because a reader may ask "isn't this just normalization?": within software they are the same mechanism, differing only in substrate (tables/joins versus classes/method objects). Tell: is the fix carried out with type-system and refactoring tools (temporary field, OO) or with tables and NOT-NULL constraints (normalization, relational) — same diagnosis, different toolkit.
-
Modularity / abstraction / cohesion (the parent primes it instantiates). The substrate-neutral principle beneath the smell — the scope of a piece of state should match the scope of its validity, factoring conditional state into a unit whose lifetime fits — is carried by these primes (and a possible future "state-validity-scope correspondence" prime). Not a confusable peer but the umbrella; the cross-domain reach belongs to them, while the "smell" verdict and refactoring menu are temporary field's OO accent. Tell: outside OO software (statutory schedules, employee-record fields, config keys), the portable lesson is the correspondence principle carried by these parents — treated more fully elsewhere — not the named smell, which stays home.
Neighborhood in Abstraction Space¶
Temporary Field sits in a sparse region of the domain-specific corpus (92nd percentile for distinctiveness): few abstractions share its structure, so a faithful description tends to retrieve it precisely.
Family — Unclustered & Miscellaneous (309 abstractions)
Nearest neighbors
- Data Class — 0.83
- Quality inherence — 0.82
- Closure (programming) — 0.82
- Mass Assignment — 0.82
- Primitive Obsession — 0.80
Computed from structural-signature embeddings · 2026-07-12