4.9 KiB
4.9 KiB
Enum vs Class: Single Source of Truth Principle
Document Type: Design Decision
Status: Active
Last Updated: 2025-12-06
Executive Summary
This project follows a strict Single Source of Truth principle for schema elements. When a concept transitions from an enum (simple value list) to a class hierarchy (rich structure with properties), the original enum MUST be deleted to prevent dual representation.
Background
What are Enums?
LinkML enums define constrained value sets:
DataTierEnum:
permissible_values:
TIER_1_AUTHORITATIVE:
description: Authoritative source
TIER_2_VERIFIED:
description: Verified data
Enums are good for:
- Simple value constraints
- Values based on external standards (ISO codes)
- Values that don't need properties or relationships
What are Classes?
LinkML classes define structured entities with properties:
Curator:
is_a: StaffRole
class_uri: schema:curator
slots:
- role_category
- typical_domains
- common_variants
Classes are good for:
- Concepts needing properties
- Inheritance hierarchies
- Rich documentation per value
- Relationships to other entities
The Rule
When an enum is promoted to a class hierarchy, the enum MUST be deleted.
Why This Matters
| Scenario | Single Source | Dual Source |
|---|---|---|
| Where is the definition? | One place | Two places (confusion) |
| Where do I make changes? | One file | Two files (maintenance burden) |
| Can they drift apart? | No | Yes (bugs) |
| Which is authoritative? | Clear | Ambiguous |
Decision Workflow
Is this concept a simple value constraint?
│
├─ YES → Use enum
│ Examples: DataTierEnum, CountryCodeEnum
│
└─ NO, it needs properties/relationships/rich docs
↓
Create class hierarchy
↓
Update slot ranges: enum → class
↓
DELETE the enum (archive it)
↓
Document the migration
Case Study: StaffRoleTypeEnum → StaffRole
Before (Enum)
# StaffRoleTypeEnum.yaml
StaffRoleTypeEnum:
permissible_values:
CURATOR:
description: Museum curator
CONSERVATOR:
description: Conservator
Limitations:
- Can't distinguish formal title from de facto work
- Can't add
role_category,typical_domains,common_variants - Can't express inheritance (e.g.,
DataScientist is_a DataRole)
After (Classes)
# StaffRole.yaml (abstract base)
StaffRole:
abstract: true
description: |
Base class for staff role categories.
**IMPORTANT**: These are FORMAL job appellations/titles.
Actual de facto work may differ or stretch beyond these classifications.
slots:
- role_id
- role_name
- role_category
- typical_domains
- typical_responsibilities
# StaffRoles.yaml (51 subclasses)
Curator:
is_a: StaffRole
class_uri: schema:curator
slot_usage:
role_category:
equals_string: CURATORIAL
Migration Steps Taken
- Created
modules/classes/StaffRole.yaml(base class with RoleCategoryEnum) - Created
modules/classes/StaffRoles.yaml(51 specialized subclasses) - Updated
modules/slots/staff_role.yaml:range: StaffRoleTypeEnum→range: StaffRole - Updated
modules/classes/PersonObservation.yamlslot definition - Updated
01_custodian_name_modular.yamlimports (removed enum, added classes) - Archived enum to
archive/enums/StaffRoleTypeEnum.yaml.archived_20251206
Enums That Remain Permanent
Not all enums should become classes. These remain as enums:
| Enum | Rationale |
|---|---|
DataTierEnum |
Simple 4-tier hierarchy, no properties needed |
DataSourceEnum |
Fixed source types, external classification |
InstitutionTypeEnum |
Matches GLAMORCUBESFIXPHDNT taxonomy, single-letter codes |
CountryCodeEnum |
ISO 3166-1 standard, external authority |
LanguageCodeEnum |
ISO 639 standard, external authority |
Indicators of permanent enums:
- Based on external standards with defined values
- Values are simple strings without properties
- No need for inheritance or relationships
- Used purely for validation constraints
Verification
After any enum-to-class migration:
# Ensure enum is only in archive
grep -r "StaffRoleTypeEnum" schemas/20251121/linkml/modules/
# Should return NO results
# Verify classes are imported
grep "StaffRole" schemas/20251121/linkml/01_custodian_name_modular.yaml
# Should show class imports
Related Documentation
.opencode/ENUM_TO_CLASS_PRINCIPLE.md- Agent-facing rulesschemas/20251121/linkml/archive/enums/README.md- Archive directory- LinkML Enums: https://linkml.io/linkml/schemas/enums.html
- LinkML Classes: https://linkml.io/linkml/schemas/models.html
Change Log
| Date | Change |
|---|---|
| 2025-12-06 | Initial document created |
| 2025-12-06 | StaffRoleTypeEnum migrated to StaffRole class hierarchy |