Most production bugs are not crashes.
They are bad data:
- impossible states
- partial writes
- silent corruption
- invalid assumptions
- βthis should never happenβ
And once bad data enters your system, it spreads everywhere.
This post shows how to design data integrity & validation pipelines in SwiftUI that:
- prevent corruption
- enforce correctness
- surface issues early
- stay testable
- scale with complexity
π§ The Core Principle
Data must be validated at every boundary.
If data crosses a boundary without validation, corruption is inevitable.
π§± 1. Identify Trust Boundaries
Every app has trust boundaries:
- network β app
- persistence β memory
- user input β model
- feature β feature
- version β version
Never assume data is valid across boundaries.
𧬠2. Validation Is a Pipeline, Not a Check
Bad:
if value.isValid { save(value) }
Correct:
RawInput
β Sanitization
β Validation
β Normalization
β Domain Model
Each step has a clear responsibility.
π¦ 3. Separate Raw Models from Domain Models
struct UserDTO {
let email: String?
let age: Int?
}
struct User {
let email: Email
let age: Age
}
Domain models cannot represent invalid states.
π 4. Typed Validation Objects
struct Email {
let value: String
init?(_ raw: String) {
guard raw.contains("@") else { return nil }
self.value = raw
}
}
If it exists, itβs valid β no rechecking required.
π§ 5. Central Validation Layer
Never validate in views.
protocol Validator {
func validate(_ input: RawInput) throws -> DomainModel
}
This allows:
- reuse
- testing
- consistent rules
- versioned validation
π§ͺ 6. Validation Errors Are First-Class
enum ValidationError: Error {
case missingField(String)
case invalidFormat(String)
case outOfRange(String)
}
Never use generic errors.
Validation errors:
- inform UX
- inform analytics
- inform monitoring
π§ 7. Persistence Validation
Before saving:
func save(_ model: DomainModel) throws {
try invariantCheck(model)
persist(model)
}
Never trust in-memory state blindly.
π 8. Versioned Validation
Validation rules change over time.
enum ValidationVersion {
case v1
case v2
}
This allows:
- backward compatibility
- safe migrations
- gradual tightening of rules
β οΈ 9. Detect & Surface Corruption
When corruption is detected:
- log it
- capture context
- isolate the data
- fail safely
Silent corruption is worse than crashes.
β 10. Common Data Integrity Anti-Patterns
Avoid:
- optional-everything models
- validation in views
- trusting backend blindly
- skipping validation for βinternalβ data
- mixing validation with UI
- ignoring edge cases
Bad data compounds.
π§ Mental Model
Think:
Input
β Validate
β Normalize
β Persist
β Trust
Not:
βIt looks fineβ
π Final Thoughts
Data integrity architecture gives you:
- fewer bugs
- safer migrations
- predictable behavior
- easier debugging
- long-term stability
Security protects access.
Integrity protects truth.
Top comments (0)