Content
View differences
Updated by Oliver Günther 10 months ago
We still have open questions regarding complexity and limitations of different ways to model specific work package types (Risks, Milestones, Goals, etc) and how to deal with additional attributes.
<br>
### Why do we think to model Risks etc. as work packages?
<br>
* [x] We want to show and plan them together or separately, using Baselines, Gantt Charts, and other functionality already present in the work packages module.
* [x] We want to collaborate on them, commenting and informing other users (comments, notifications, emails, etc.)
* [x] We want to customize these types to add additional tailored information (e.g., additional custom fields on Risks for responsible, measures, escalation steps etc.)
* [x] A work package is basically a "planning element" internally, so anything that has dates and assignments as basic properties.
<br>
### Considered options for attributes
Modeling Risks requires storing additional attributes, at least:
1. A numerical + text represented **Probability** (e.g., "1" - "very low"). This might be a fixed set of values, or configurable
2. A numerical + text represented **Impact** (e.g., "5" - "very high"). This might be a fixed set of values, or configurable
3. A calculated **Risk level**, assumed to be either the sum or product of the above values.
<br>
The main question is how to model these additional attributes, given that the surrounding object remains a work package.
Up until now, we have considered these options:
1. Attributes as custom fields
2. Attributes as new columns on work package
3. Attributes as a separate join table (with one record per work package) and a set of columns
<br>
### 1\. **Custom Fields**
* **✅ Configuration**: If risk values are custom fields, we have a UI to allow modifications of the available attributes (e.g., when using a list custom field)
* Users can migrate to these new risk types and attributes through the UI
* Users might want to change the values of the risk attributes if they don't follow the same standard
* **✅ Journaling**: Built-in journaling support through Journal::CustomizableJournal and CustomValue models
* **✅ API Integration**: Already integrated with the API schema system, but **without semantic names**
* **✅ Validation**: Existing validation framework for custom fields
* **✅ Form Integration**: We can already render customized forms in primer (e.g., create work package dialog)
* **✅ Subclassing for Logic**: We can introduce subclasses for "Risks", which defines semantic getters and setters for risk attributes that refer to the configured custom fields
* **❌ Complexity**:
* Requires handling (or rather, limitation) custom field activation logic at the application level rather than database level
* Requires additional constraints, e.g., hiding built-in custom fields from view on project modules
* **❌ Performance**: Additional joins and queries for custom field values, as values are defined as one rec ord per custom field
* **❌ Type Safety**: Less type safety compared to native columns, no foreign keys available
* **❌ Migration Complexity**: Need to manage custom field creation and assignment during seeding
<br>
### 2\. **Sparse Columns**
<br>
* **✅ Simplicity**: Direct database columns, no additional joins needed
* **✅ Performance**: Fast queries without additional joins
* **✅ Type Safety**: Native database types and constraints
* **✅ Journaling**: Automatic journaling through the existing acts\_as\_journalized system
* **✅ API Integration**: Direct attribute mapping in API schemas
* **❌ No configuration:** We will have no UI for building customizable attributes as with custom fields out of the box
* **❌ Database Bloat**: Null columns for work packages that don't use these attributes
* **❌ Schema Evolution**: Adding new attributes requires database migrations
* **❌ Limited Flexibility**: Hard to make attributes conditional per project/type
* **❌ Maintenance**: Need to handle these attributes in all places where work package attributes are processed
* **❌ Migration Complexity**: New attributes directly impact `work_packages` table, possibly larger migration impact
<br>
### 3\. **Join Table**
###
* **✅ Separation of Concerns**: Keeps risk-specific data separate from core work package data
* **✅ Extensibility**: Easy to add new risk-specific attributes
* **✅ Type Safety**: Can use proper database types for risk-specific fields
* **❌ Journaling Complexity**: Would need custom journaling implementation similar to `AttachableJournals` for the associated model, which bloats the CreateService even more
* **❌ API Integration**: More complex to integrate with existing API schema system
* **❌ Query and Columns/Filters Complexity**: Requires joins for all risk-related queries in all places where we might show risks, leaking into Work package
* **❌ Validation**: Need to handle validation across the association, which means leaking semantics into work packages
* **❓ Performance**: Additional joins for all risk-related operations
* better performance than custom fields
* likely worse performance than sparse columns
<br>
<br>
<figure class="table op-uc-figure_align-center op-uc-figure"><table class="op-uc-table"><thead class="op-uc-table--head"><tr class="op-uc-table--row"><th class="op-uc-table--cell op-uc-table--cell_head"><p class="op-uc-p">Criteria</p></th><th class="op-uc-table--cell op-uc-table--cell_head"><p class="op-uc-p">Custom Fields</p></th><th class="op-uc-table--cell op-uc-table--cell_head"><p class="op-uc-p">Sparse Columns</p></th><th class="op-uc-table--cell op-uc-table--cell_head"><p class="op-uc-p">Join Table</p></th></tr></thead><tbody><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p">Configuration</p></td><td class="op-uc-table--cell"><p class="op-uc-p">✅</p></td><td class="op-uc-table--cell"><p class="op-uc-p">❌</p></td><td class="op-uc-table--cell"><p class="op-uc-p">✅</p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p">Journaling</p></td><td class="op-uc-table--cell"><p class="op-uc-p">✅</p></td><td class="op-uc-table--cell"><p class="op-uc-p">✅</p></td><td class="op-uc-table--cell"><p class="op-uc-p">❌</p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p">API Integration</p></td><td class="op-uc-table--cell"><p class="op-uc-p">✅</p></td><td class="op-uc-table--cell"><p class="op-uc-p">✅</p></td><td class="op-uc-table--cell"><p class="op-uc-p">❌</p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p">Validation</p></td><td class="op-uc-table--cell"><p class="op-uc-p">✅</p></td><td class="op-uc-table--cell"><p class="op-uc-p">✅</p></td><td class="op-uc-table--cell"><p class="op-uc-p">❌</p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p">Type Safety</p></td><td class="op-uc-table--cell"><p class="op-uc-p">❌</p></td><td class="op-uc-table--cell"><p class="op-uc-p">✅</p></td><td class="op-uc-table--cell"><p class="op-uc-p">✅</p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p">Performance</p></td><td class="op-uc-table--cell"><p class="op-uc-p">❌</p></td><td class="op-uc-table--cell"><p class="op-uc-p">✅</p></td><td class="op-uc-table--cell"><p class="op-uc-p">❓</p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p">Migration Complexity</p></td><td class="op-uc-table--cell"><p class="op-uc-p">❌</p></td><td class="op-uc-table--cell"><p class="op-uc-p">❌</p></td><td class="op-uc-table--cell"><p class="op-uc-p">✅</p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p">Flexibility</p></td><td class="op-uc-table--cell"><p class="op-uc-p">✅</p></td><td class="op-uc-table--cell"><p class="op-uc-p">❌</p></td><td class="op-uc-table--cell"><p class="op-uc-p">✅</p></td></tr></tbody></table></figure>
<br>
###
<br>
* [x] We want to show and plan them together or separately, using Baselines, Gantt Charts, and other functionality already present in the work packages module.
* [x] We want to collaborate on them, commenting and informing other users (comments, notifications, emails, etc.)
* [x] We want to customize these types to add additional tailored information (e.g., additional custom fields on Risks for responsible, measures, escalation steps etc.)
* [x] A work package is basically a "planning element" internally, so anything that has dates and assignments as basic properties.
<br>
###
Modeling Risks requires storing additional attributes, at least:
1. A numerical + text represented **Probability** (e.g., "1" - "very low"). This might be a fixed set of values, or configurable
2. A numerical + text represented **Impact** (e.g., "5" - "very high"). This might be a fixed set of values, or configurable
3. A calculated **Risk level**, assumed to be either the sum or product of the above values.
<br>
The main question is how to model these additional attributes, given that the surrounding object remains a work package.
Up until now, we have considered these options:
1. Attributes as custom fields
2. Attributes as new columns on work package
3. Attributes as a separate join table (with one record per work package) and a set of columns
<br>
### 1\. **Custom Fields**
* **✅ Configuration**: If risk values are custom fields, we have a UI to allow modifications of the available attributes (e.g., when using a list custom field)
* Users can migrate to these new risk types and attributes through the UI
* Users might want to change the values of the risk attributes if they don't follow the same standard
* **✅ Journaling**: Built-in journaling support through Journal::CustomizableJournal and CustomValue models
* **✅ API Integration**: Already integrated with the API schema system, but **without semantic names**
* **✅ Validation**: Existing validation framework for custom fields
* **✅ Form Integration**: We can already render customized forms in primer (e.g., create work package dialog)
* **✅ Subclassing for Logic**: We can introduce subclasses for "Risks", which defines semantic getters and setters for risk attributes that refer to the configured custom fields
* **❌ Complexity**:
* Requires handling (or rather, limitation) custom field activation logic at the application level rather than database level
* Requires additional constraints, e.g., hiding built-in custom fields from view on project modules
* **❌ Performance**: Additional joins and queries for custom field values, as values are defined as one rec ord per custom field
* **❌ Type Safety**: Less type safety compared to native columns, no foreign keys available
* **❌ Migration Complexity**: Need to manage custom field creation and assignment during seeding
<br>
### 2\. **Sparse Columns**
<br>
* **✅ Simplicity**: Direct database columns, no additional joins needed
* **✅ Performance**: Fast queries without additional joins
* **✅ Type Safety**: Native database types and constraints
* **✅ Journaling**: Automatic journaling through the existing acts\_as\_journalized system
* **✅ API Integration**: Direct attribute mapping in API schemas
* **❌ No configuration:** We will have no UI for building customizable attributes as with custom fields out of the box
* **❌ Database Bloat**: Null columns for work packages that don't use these attributes
* **❌ Schema Evolution**: Adding new attributes requires database migrations
* **❌ Limited Flexibility**: Hard to make attributes conditional per project/type
* **❌ Maintenance**: Need to handle these attributes in all places where work package attributes are processed
* **❌ Migration Complexity**: New attributes directly impact `work_packages` table, possibly larger migration impact
<br>
### 3\. **Join Table**
###
* **✅ Separation of Concerns**: Keeps risk-specific data separate from core work package data
* **✅ Extensibility**: Easy to add new risk-specific attributes
* **✅ Type Safety**: Can use proper database types for risk-specific fields
* **❌ Journaling Complexity**: Would need custom journaling implementation similar to `AttachableJournals` for the associated model, which bloats the CreateService even more
* **❌ API Integration**: More complex to integrate with existing API schema system
* **❌ Query and Columns/Filters Complexity**: Requires joins for all risk-related queries in all places where we might show risks, leaking into Work package
* **❌ Validation**: Need to handle validation across the association, which means leaking semantics into work packages
* **❓ Performance**: Additional joins for all risk-related operations
* better performance than custom fields
* likely worse performance than sparse columns
<br>
<br>
<figure class="table op-uc-figure_align-center op-uc-figure"><table class="op-uc-table"><thead class="op-uc-table--head"><tr class="op-uc-table--row"><th class="op-uc-table--cell op-uc-table--cell_head"><p class="op-uc-p">Criteria</p></th><th class="op-uc-table--cell op-uc-table--cell_head"><p class="op-uc-p">Custom Fields</p></th><th class="op-uc-table--cell op-uc-table--cell_head"><p class="op-uc-p">Sparse Columns</p></th><th class="op-uc-table--cell op-uc-table--cell_head"><p class="op-uc-p">Join Table</p></th></tr></thead><tbody><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p">Configuration</p></td><td class="op-uc-table--cell"><p class="op-uc-p">✅</p></td><td class="op-uc-table--cell"><p class="op-uc-p">❌</p></td><td class="op-uc-table--cell"><p class="op-uc-p">✅</p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p">Journaling</p></td><td class="op-uc-table--cell"><p class="op-uc-p">✅</p></td><td class="op-uc-table--cell"><p class="op-uc-p">✅</p></td><td class="op-uc-table--cell"><p class="op-uc-p">❌</p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p">API Integration</p></td><td class="op-uc-table--cell"><p class="op-uc-p">✅</p></td><td class="op-uc-table--cell"><p class="op-uc-p">✅</p></td><td class="op-uc-table--cell"><p class="op-uc-p">❌</p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p">Validation</p></td><td class="op-uc-table--cell"><p class="op-uc-p">✅</p></td><td class="op-uc-table--cell"><p class="op-uc-p">✅</p></td><td class="op-uc-table--cell"><p class="op-uc-p">❌</p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p">Type Safety</p></td><td class="op-uc-table--cell"><p class="op-uc-p">❌</p></td><td class="op-uc-table--cell"><p class="op-uc-p">✅</p></td><td class="op-uc-table--cell"><p class="op-uc-p">✅</p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p">Performance</p></td><td class="op-uc-table--cell"><p class="op-uc-p">❌</p></td><td class="op-uc-table--cell"><p class="op-uc-p">✅</p></td><td class="op-uc-table--cell"><p class="op-uc-p">❓</p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p">Migration Complexity</p></td><td class="op-uc-table--cell"><p class="op-uc-p">❌</p></td><td class="op-uc-table--cell"><p class="op-uc-p">❌</p></td><td class="op-uc-table--cell"><p class="op-uc-p">✅</p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p">Flexibility</p></td><td class="op-uc-table--cell"><p class="op-uc-p">✅</p></td><td class="op-uc-table--cell"><p class="op-uc-p">❌</p></td><td class="op-uc-table--cell"><p class="op-uc-p">✅</p></td></tr></tbody></table></figure>