-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
docs: ADRs for modeling containers capability #251
base: main
Are you sure you want to change the base?
Changes from all commits
2906792
b1b1a88
413b66c
0deab25
22eb1ae
db61fda
b5f05d8
9d2c62d
8648f16
80cf370
b98c02c
ccada60
778ce2b
e738778
3a28fa5
bbce789
af7dce4
506d9cd
466b450
46999f8
0c426d2
46dfa9e
d37a414
64e4db9
46e5a09
822d9a0
8646225
1f1c962
f260756
86141e5
aff8b9b
76e89d5
6ecde96
f7cc446
dc5a0a2
d0f1fc8
83f8d04
8fa418e
6fd6864
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
17. Modeling Containers as a Generalized Capability for Holding Content | ||
======================================================================== | ||
|
||
Context | ||
------- | ||
|
||
This ADR proposes a model for containers that can hold different types of content and can be used to model other content types with similar behavior, such as units, subsections, sections, or courses. The model defines containers' core structure and purpose, the types of containers, content constraints, container children, version control, publishing, and pruning. | ||
|
||
Decisions | ||
--------- | ||
|
||
1. Core Structure and Purpose of Containers | ||
=========================================== | ||
|
||
This section defines the purpose and structure of containers, explaining how they are designed to hold various types of content through a parent-child setup. | ||
|
||
- A container is designed as a generalized capability to hold different types of content. | ||
- A container is a publishable content type that holds other content types through a parent-child relationship. For example, sections, subsections and units. | ||
- The generalized container capability will have its own Django application as part of the authoring application allowing other types of containers and content types will build on top of. For instance: | ||
|
||
- Generalized containers (containers app is lowest level of these applications) | ||
- Selectors for dynamically selecting 0-N PublishableEntities, i.e., how we're going to do things like SplitTest and Randomized (a selectors Django application that builds on containers). | ||
- Units (units Django application, builds on containers and selectors). | ||
|
||
2. Container Types and Content Constraints | ||
========================================== | ||
|
||
This section defines container types, content constraints, hierarchy, and extensibility. It introduces the main types of containers and outlines how content limitations and configurations are handled at the application level to support flexible content structures. | ||
|
||
- A container marks any PublishableEntity, such as sections, subsections, units, or any other custom content type, as a type that can hold other content. | ||
- Containers can be nested within other containers, allowing for complex content structures. For example, subsections can contain units. | ||
- Containers might be of different types, with each type potentially having different restrictions on the type of content it can hold but that will not be enforced by containers. | ||
- Content restrictions for containers are implemented at the app layer, allowing specific container types, like units, to limit their children to particular content types, e.g., units are restricted to contain only components. | ||
- The course hierarchy Course > Section > Subsection > Unit will be implemented as relationships between containers, with each level acting as a container that holds other content. The hierarchy will be enforced by the content restrictions of each particular container but allowed to be overridden to support `Approach to Content Flexibility <0002-content-flexibility.rst>`_. | ||
- Containers will follow extensibility principles in `Content Extensibility Through Model Relations <0003-content-extensibility.rst>`_ for creating new container types or subtypes. | ||
|
||
3. Container Children and Relationships | ||
======================================= | ||
|
||
This section defines container children, their order, and relationships, covering flexible connections and support for draft and published states of their children. | ||
|
||
- Each container version holds a list of children that the author has defined for that version. | ||
- The author-defined list is used to show the content of a container version as the author specified it. | ||
- The author-defined list won't change for a specific container version even if its members change. E.g., a unit version UV1 with three components (CV1, CV2, CV3) will always have those three components in the author-defined list, even if one of the components is soft-deleted or a new version for the component is created. | ||
- The children of a container can be any type of publishable content. E.g., sections, subsections, units, components, and any other publishable thing. For more details on publishable content, see `PublishableEntity`_. | ||
- Children within a container are maintained in a specific order as an ordered list. E.g., components within a unit, or units within a subsection, are presented in a specific order. | ||
- Containers represent their content hierarchy through a structure, like Course > Section > Subsection > Unit > Component, which defines parent-child relationships at each level. | ||
- Containers can reference a specific version of their children or be set to point to their latest versions. For instance, component V1 might be used in a unit instead of its latest version. The latest version of a child can be referenced by setting its version to ``None`` which consists of the chosen standard for this representation. | ||
- A single child (publishable entity) can be shared by multiple containers, allowing for reuse of content across different containers. For instance, a component can be shared by multiple units. | ||
|
||
4. Next Container Versions | ||
========================== | ||
|
||
This section defines the rules for version control in containers, explaining when new versions are created based on changes to container structure or metadata. | ||
|
||
- A new version is created if and only if the container itself changes (e.g., title, ordering of children, adding or removing children) and not when its children change (e.g., a component in a Unit is updated with new text). For instance, a new version of a unit is created when a component is removed, not when a new version of a component is created. | ||
- No external change to a child will trigger the creation of a new version for the container. For example, updating or soft-deleting a component will not trigger the creation of a new version for the unit. | ||
- Containers with invalid references (e.g., references to soft-deleted children) will be filtered out as needed to ensure consistency. | ||
|
||
5. Publishing | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Question: |
||
============= | ||
|
||
This section explains the publishing process for containers, detailing how containers and their children become accessible, either together or independently, based on their publication state. The publishing process happens on container versions, but throughout this section we'd call them containers for simplicity. | ||
|
||
- Containers can be published, allowing their content to be accessible from where the container is being used. | ||
- When a draft container is published, all its draft children are also published. For instance, after publishing a draft version of subsection which contains a draft unit with an updated title, the latest published version of the unit will be the one with the updated title, reflecting the changes made previously. | ||
- Children of a container can be published independently of the container itself. E.g., a shared component can be published independently of the unit if it also exists outside the unit. | ||
- Containers are not affected by the publishing process of its children. This means that publishing a component won't trigger new publishing processes for a container. | ||
|
||
6. Pruning | ||
========== | ||
|
||
This section defines the rules for pruning container versions, explaining when a container version can be pruned and the effects of pruning on the container and its children. | ||
|
||
- A container version can be pruned if it's not being used by any other container, it's not a published version and it's not the latest version of the container. | ||
- In a top-down approach, start the deletion process with the parent container and work your way down to its children. E.g., when pruning Section V2 > Subsection V1 > Unit V3, the deletion process starts in the greater container working its way down to the smaller. | ||
- Pruning a container version will not affect the container's history or the children of other container versions, so containers will not be deleted if they are shared by other containers. | ||
|
||
.. _PublishableEntity: https://github.com/openedx/openedx-learning/blob/main/openedx_learning/apps/authoring/publishing/models.py#L100-L184 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
18. Modeling Units as a Concrete Implementation of the Container Capability | ||
mariajgrimaldi marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure if this requires its own ADR, but it helps illustrate the decisions using a more familiar concept like units. |
||
=========================================================================== | ||
|
||
Context | ||
------- | ||
|
||
The container capability is a generalized capability to hold different types of content. This decision focuses on modeling units as a concrete implementation of the container capability. | ||
|
||
Decisions | ||
--------- | ||
|
||
All decisions from `0017-generalized-containers.rst <0017-generalized-containers.rst>`_ are still valid but are written here alongside unit-specific decisions for better illustration. | ||
|
||
1. Units as Containers | ||
======================= | ||
|
||
- A unit is a concrete type of container that holds components. | ||
- A unit is a container, making it also a publishable entity. | ||
- Units build on the generalized container capability to hold components and selectors for dynamically selecting 0-N PublishableEntities. | ||
- Units have their own Django application that builds on containers and selectors. | ||
|
||
2. Unit Types and Content Constraints | ||
====================================== | ||
|
||
- Units can only hold components as their children but will not enforce this restriction at the model level. | ||
- Units are the first level of nested content types Unit > Components. | ||
- Content restrictions for units are implemented at the application layer, allowing units to limit their children to only components. None of this is enforced at the model level. | ||
- Unit subtypes can be created by following the extensibility principles in `Content Extensibility Through Model Relations <0003-content-extensibility.rst>`_. | ||
|
||
3. Unit Children and Relationships | ||
================================== | ||
|
||
- The children of a unit can only be components. | ||
- Components in a unit are referenced as an ordered list. For example, a unit can have a list of components that are ordered by the author. | ||
- Units can hold both static and dynamic content (using selectors), such as user-specific variations. For example, a unit can have components that won't change for all users and components that are dynamically selected based on particular criteria, like A/B tests or Random selection. | ||
- Units can reference pinned and unpinned versions of its components. The latest version of a component can be set by using ``None`` as the version. For example, a unit can have a component that is always the latest version so it always shows the latest content or a component that is pinned to a specific version so it always shows the same content regardless of the latest version. | ||
- A single component can be reference by multiple units. | ||
|
||
4. Next Unit Versions | ||
====================== | ||
|
||
Only changes to the unit itself (e.g., title, ordering of components, adding or removing a component, or changes to the unit's metadata) will create a new version of the unit. Changes to the components of a unit will not create a new version of the unit. | ||
|
||
5. Publishing | ||
============== | ||
|
||
- Units can be published, allowing their content to be accessible from where the unit is being used. Only after a unit is published it can be reused as content for other containers. | ||
- When a draft unit is published, all its draft components are also published. | ||
- Components within a unit can be published independently of the unit itself. This could happen for components that are shared by multiple units. | ||
- Units are not affected by the publishing process of its components. | ||
|
||
6. Pruning | ||
========== | ||
|
||
- A unit version can be pruned if it's not being used by any subsections, it's not a published version, and it's not the latest version of the unit. | ||
- In a top-down approach, start with the unit and work your way down to its component versions. | ||
- Component versions will not be deleted if they are shared by other units. | ||
- Pruning a unit version will not affect the unit's history or the components of other unit versions that are still in use. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
19. Selectors for Dynamically Selecting Content | ||
=========================================== | ||
|
||
Context | ||
------- | ||
|
||
This ADR proposes a way to represent dynamic members of a container, where dynamic means selecting members from a specified pool. Some examples of dynamic selection are: | ||
|
||
1. A/B Testing: testing two different groups of components to see which perform better. | ||
2. Per Student: randomly selecting three problems from a set of 20 per student. | ||
|
||
And any other custom use case to dynamically select members for a container. This proposal introduces the concepts of selectors and variants to implement this type of dynamic selection. | ||
|
||
1. Core Structure | ||
================= | ||
|
||
This section explains the concepts and behaviors used to build dynamic selection, selectors and variants. | ||
|
||
- Selectors determine what the container should display based on the selector type. For example, based on the nature an A/B split test or a randomization selector members of the container would vary. | ||
- Selectors are used to dynamically select 0-N publishable entities from a specified pool. E.g., take 5 components from this pool of 20. | ||
- The logic for pushing members into variants depends on the selector selection method. For example, A/B split testing two different sets of components or select three problems from a set of twenty. | ||
- Variants hold the members selected for a container based on what the selection method is. E.g., if the selector is "select 5 components out this pool of 20 components" then the variant would be the 5 components selected for the user. | ||
- Variants are build on the parent-child relationship used for containers and their members, storing the dynamically selected content as an ordered list as containers do. | ||
|
||
2. Selector Types and Selecting Content | ||
======================================= | ||
|
||
This section describes how different types of selectors work and how they handle the selection of dynamic content. | ||
|
||
- A selector can be of any type, which means it can implement any method to select members from a pool. Therefore, selectors will follow extensibility principles in `0003-content-extensibility.rst <0003-content-extensibility.rst>`_ for creating new selector types. | ||
- Selection versions encode the rules and holds useful details for the selection process like: where to get members from, number of items to select, and other criteria. For instance, for the "select 5 components out of this pool of 20 components" its selector version would encode where to get the 20 components, how many to get for each user and any other detail needed to create the specific variants. | ||
- Depending on the size of the pool of members, variants can be generated at publishing time or on-demand. This behavior should be determined by the selector version based on high vs low permutation scenarios. | ||
- A compositor is responsible for populating the variants but will not be implemented as part of the selector application which belongs to the authoring app. | ||
|
||
3. Versioning | ||
============= | ||
|
||
A new version of a selector is created whenever the pool of concent changes by adding, removing or reordering existing members. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to be more specific about the unit, is the unit in a content library o within the context of a course?