From 5da4e21b4201623adc5fa722a28204af4933cd8b Mon Sep 17 00:00:00 2001 From: Robert Raposa Date: Thu, 9 Jan 2025 10:01:03 -0500 Subject: [PATCH 1/4] docs: introduce DEPR pilot into OEP --- oeps/processes/oep-0021-proc-deprecation.rst | 27 ++++++++++++-------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/oeps/processes/oep-0021-proc-deprecation.rst b/oeps/processes/oep-0021-proc-deprecation.rst index f464af34..7e17e6f5 100644 --- a/oeps/processes/oep-0021-proc-deprecation.rst +++ b/oeps/processes/oep-0021-proc-deprecation.rst @@ -211,19 +211,25 @@ considers the timing of the next `Open edX named release`_. * **Proposed** on Day 1 * **Communicated** from Day 2 to Day 13 * **Accepted** on Day 14 *(depending on influx of feedback)* -* **Deprecated/Removing/Removed** - from Day 15 onwards *(depending on resources and technology being removed).* +* **Deprecated/Removing/Removed** - TODO: UPDATE TO MATCH NEW RECOMMENDATION: from Day 15 onwards *(depending on resources and technology being removed).* Consider when the next Named Release is cut; if it is very soon, you may wish to delay final removal until after the cut date. -Consider choosing deprecation and removal dates that allow for a full -release cycle for transition planning. For example, a deprecation -proposal could be accepted while Maple is being finalized, then -implement the removal some time after Maple is released so that the -removal itself will land in Nutmeg. (Removal could even happen as soon as -a named release's branches are cut, but this may interfere with fixes that -need to be backported.) Any deployment following the -named releases would then have a number of months to prepare before -Nutmeg comes out. + +The removal date should default to 6 months of advance communication, +including at least 1 month window of overlapping support between old +and new features. + +Additionally, the ability to negotiate dates on the DEPR ticket is an +explicit part of the process. This could include adjusting the default +dates for a specific ticket, or negotiating extensions as-needed (e.g. +difficulties that arise, or too many maintenance requests landing at +the same time, etc.). It could also include providing a very short +window for changes that don't require much warning. + +The 6 month window has the benefit of givig at least one named release +(e.g. Redwood) worth of warning, because the named releases are +currently on a 6 month window. This approach would be most appropriate for features that can be left in place for an extended period before removal and where a transition @@ -231,6 +237,7 @@ to an alternative would require a moderate to large amount of effort. For more trivial deprecations, it may be appropriate to simply deprecate and remove within the same release cycle. +TODO: UPDATE THIS AND ALL OTHER PLACES TO MENTION target month + named release. Check the DEPR issue template as well. And scan throught the rest of this DEPR. Remember to use the named release's *cut date* when determining the appropriate named release. Additionally, if the named release is far enough in the future that it only has a letter (and not a full name), From b6fc7cc6446844a996bcccf7d9ffa21484339e35 Mon Sep 17 00:00:00 2001 From: Feanil Patel Date: Thu, 9 Jan 2025 12:01:53 -0500 Subject: [PATCH 2/4] docs: Update oep-0021-proc-deprecation.rst Add some more thoughts and we'll come back with more edits in the next meeting. --- oeps/processes/oep-0021-proc-deprecation.rst | 36 ++++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/oeps/processes/oep-0021-proc-deprecation.rst b/oeps/processes/oep-0021-proc-deprecation.rst index 7e17e6f5..7b0cae64 100644 --- a/oeps/processes/oep-0021-proc-deprecation.rst +++ b/oeps/processes/oep-0021-proc-deprecation.rst @@ -218,14 +218,17 @@ considers the timing of the next `Open edX named release`_. The removal date should default to 6 months of advance communication, including at least 1 month window of overlapping support between old -and new features. +and new features. If you have a high level of confidence that it's not +used elsewhere and you still comunicate it to the community you may use +a more accelerated process which is as short as 2 weeks. Additionally, the ability to negotiate dates on the DEPR ticket is an explicit part of the process. This could include adjusting the default dates for a specific ticket, or negotiating extensions as-needed (e.g. difficulties that arise, or too many maintenance requests landing at the same time, etc.). It could also include providing a very short -window for changes that don't require much warning. +window for changes that don't require much warning or where there are +very few actual users of the code. The 6 month window has the benefit of givig at least one named release (e.g. Redwood) worth of warning, because the named releases are @@ -433,13 +436,8 @@ in the release notes of the next named release. then the contributor must provide an ADR justifying its usage. This is because using the deprecated feature obviously adds new technical debt to the system. -Deprecated -========== - -If you decided to mark the code for deprecation during your Analyze_ or -`Monitor Feedback`_ phases, invest time in doing so and update the state of the -**DEPR** ticket to *Deprecated* once that is completed and make a comment on the -issue saying you've done so. +As a part of acceptance, all relevant warnings should go into code/documentation to indicate what +will be removed or replaced. Here are some common ways to mark a technology as deprecated: @@ -463,21 +461,29 @@ Here are some common ways to mark a technology as deprecated: .. _OEP-17: https://open-edx-proposals.readthedocs.io/en/latest/oep-0017-bp-feature-toggles.html .. _OEP-14 Archiving Open edX GitHub Repositories: https://open-edx-proposals.readthedocs.io/en/latest/oep-0014-proc-archive-repos.html +If the new version of the code will be using toggles/waffles, the names and settings of those waffles should be communicated to operators. +e.g. "If you don't want to use the new content libraries, set "xxx" waffle flag to false before that lands. Do we need more here? + +Ready for Migration +=================== +For code where there is a replacement, this state indicates that the replacement is ready for use and we are in a period where both the old and new code are working. This is a temporary state that allows developers/operators to migrate to the replacement option before the old code is removed. Unless otherwise negotiated/communicated, this stage will last one month to give everyone ample time to transition. + +This state implies that there are flags or toggles to be able to switch between the two versions, and the DEPR ticket should communicate if the default is changing with enough time for operators to be able to set relevant flags to choose between the implementations. + Removing ======== -When a team begins development work to remove the code, change the **DEPR** -ticket's state to *Removing* and make a comment on the issue saying you've done so. +This state indicates that support for the old implementation has been officially dropped and developers are able to begin removing code. If an item is in this state you should not expect the old implementation to work. -During this phase, remember the following: +During this phase, the following will occur: -* Implement the proposed and agreed upon migration path. * Remove related code from all places, including the frontend, APIs, and the backend, perhaps even in that order. -* Remove any related documentation on docs.edx.org_ and elsewhere. +* Remove any unnecessary feature flags introduced as a part of the transition. +* Remove any related documentation on docs.openedx.org_ and elsewhere. * Continue to update the ticket with any delays or issues that may arise. -.. _docs.edx.org: https://docs.edx.org/ +.. _docs.openedx.org: https://docs.openedx.org/ Removed ======= From c19683d83ce0da9d2b3d5c1469b9f8130549cdf8 Mon Sep 17 00:00:00 2001 From: Feanil Patel Date: Thu, 23 Jan 2025 11:56:21 -0500 Subject: [PATCH 3/4] docs: Apply suggestions from code review Co-authored-by: Diana Huang <2952947+dianakhuang@users.noreply.github.com> --- oeps/processes/oep-0021-proc-deprecation.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/oeps/processes/oep-0021-proc-deprecation.rst b/oeps/processes/oep-0021-proc-deprecation.rst index 7b0cae64..f9af7c18 100644 --- a/oeps/processes/oep-0021-proc-deprecation.rst +++ b/oeps/processes/oep-0021-proc-deprecation.rst @@ -209,9 +209,11 @@ considers the timing of the next `Open edX named release`_. periods will vary by the type and scope of the technical change. * **Proposed** on Day 1 -* **Communicated** from Day 2 to Day 13 +* **Communicated** - Up to 6 months before the change is expected to land. * **Accepted** on Day 14 *(depending on influx of feedback)* -* **Deprecated/Removing/Removed** - TODO: UPDATE TO MATCH NEW RECOMMENDATION: from Day 15 onwards *(depending on resources and technology being removed).* +* **Replacement Ready** - At least 1 month to allow operators to transition. +* **Removal Pending** - Once the transition period has concluded (However long the replacement ready phase was). +* **Removed** - The resolved state. Consider when the next Named Release is cut; if it is very soon, you may wish to delay final removal until after the cut date. @@ -464,13 +466,13 @@ Here are some common ways to mark a technology as deprecated: If the new version of the code will be using toggles/waffles, the names and settings of those waffles should be communicated to operators. e.g. "If you don't want to use the new content libraries, set "xxx" waffle flag to false before that lands. Do we need more here? -Ready for Migration +Replacement Ready =================== For code where there is a replacement, this state indicates that the replacement is ready for use and we are in a period where both the old and new code are working. This is a temporary state that allows developers/operators to migrate to the replacement option before the old code is removed. Unless otherwise negotiated/communicated, this stage will last one month to give everyone ample time to transition. This state implies that there are flags or toggles to be able to switch between the two versions, and the DEPR ticket should communicate if the default is changing with enough time for operators to be able to set relevant flags to choose between the implementations. -Removing +Removal Pending ======== This state indicates that support for the old implementation has been officially dropped and developers are able to begin removing code. If an item is in this state you should not expect the old implementation to work. From 487e1807716692fb6690fb452515ffe4533aa2d6 Mon Sep 17 00:00:00 2001 From: Feanil Patel Date: Thu, 6 Feb 2025 15:16:18 -0500 Subject: [PATCH 4/4] docs: Swap out the old image with a new process chart. --- oeps/processes/oep-0021-proc-deprecation.rst | 38 +++++++++++-------- oeps/processes/oep-0021/timeline.png | Bin 16828 -> 0 bytes 2 files changed, 23 insertions(+), 15 deletions(-) delete mode 100644 oeps/processes/oep-0021/timeline.png diff --git a/oeps/processes/oep-0021-proc-deprecation.rst b/oeps/processes/oep-0021-proc-deprecation.rst index f9af7c18..e2d65be7 100644 --- a/oeps/processes/oep-0021-proc-deprecation.rst +++ b/oeps/processes/oep-0021-proc-deprecation.rst @@ -201,18 +201,26 @@ with all team members so the removal can be prioritized and completed in a timely manner. A suggested timeline is shown in the diagram below, which considers the timing of the next `Open edX named release`_. -.. image:: oep-0021/timeline.png - :align: center - :alt: A diagram that suggests having a 2 week time period between the - *Proposed* and *Accepted* states, giving the community enough time to provide - feedback. After which, the *Deprecated*, *Removing*, and *Removed* transition - periods will vary by the type and scope of the technical change. +.. https://dreampuf.github.io/GraphvizOnline +.. graphviz:: + + digraph shells { + + node [fontsize=20, shape = box]; + + Draft -> RFC [label=" Someone is ready to own the ticket and does RFC work"]; + RFC -> "Plan Accepted" [label=" 2 weeks (negotiable)"]; + "Plan Accepted" -> "Transition Unblocked" + "Plan Accepted" -> "Breaking Changes Unblocked" [label=" 6 months (negotiable)"] + "Transition Unblocked" -> "Breaking Changes Unblocked" [label=" 1 month (negotiable)"]; + "Breaking Changes Unblocked" -> "Plan Completed" + } * **Proposed** on Day 1 * **Communicated** - Up to 6 months before the change is expected to land. * **Accepted** on Day 14 *(depending on influx of feedback)* -* **Replacement Ready** - At least 1 month to allow operators to transition. -* **Removal Pending** - Once the transition period has concluded (However long the replacement ready phase was). +* **Replacement Ready** - At least 1 month to allow operators to transition to the replacement. +* **Removal Pending** - Once the transition period has concluded (However long the ``Replacement Ready`` phase was). * **Removed** - The resolved state. Consider when the next Named Release is cut; if it is very soon, you may wish to delay final removal until after the cut date. @@ -226,15 +234,15 @@ a more accelerated process which is as short as 2 weeks. Additionally, the ability to negotiate dates on the DEPR ticket is an explicit part of the process. This could include adjusting the default -dates for a specific ticket, or negotiating extensions as-needed (e.g. -difficulties that arise, or too many maintenance requests landing at +dates for a specific ticket, or negotiating extensions as-needed (e.g. +difficulties that arise, or too many maintenance requests landing at the same time, etc.). It could also include providing a very short window for changes that don't require much warning or where there are very few actual users of the code. The 6 month window has the benefit of givig at least one named release (e.g. Redwood) worth of warning, because the named releases are -currently on a 6 month window. +currently on a 6 month window. This approach would be most appropriate for features that can be left in place for an extended period before removal and where a transition @@ -286,7 +294,7 @@ Do the following to document your proposal: #. **Removal**: A description with links to what is being removed. #. **Replacement**: A description with links to what it is being replaced by. #. If you plan to mark the code for deprecation, explain how in the - **Deprecation** section. See Deprecated_ for considerations. + **Deprecation** section. See Deprecated for considerations. #. If automated migration will be needed, explain your migration plan in the **Migration** section. #. **Additional Info**: @@ -439,7 +447,7 @@ in the release notes of the next named release. using the deprecated feature obviously adds new technical debt to the system. As a part of acceptance, all relevant warnings should go into code/documentation to indicate what -will be removed or replaced. +will be removed or replaced. Here are some common ways to mark a technology as deprecated: @@ -467,13 +475,13 @@ If the new version of the code will be using toggles/waffles, the names and sett e.g. "If you don't want to use the new content libraries, set "xxx" waffle flag to false before that lands. Do we need more here? Replacement Ready -=================== +================= For code where there is a replacement, this state indicates that the replacement is ready for use and we are in a period where both the old and new code are working. This is a temporary state that allows developers/operators to migrate to the replacement option before the old code is removed. Unless otherwise negotiated/communicated, this stage will last one month to give everyone ample time to transition. This state implies that there are flags or toggles to be able to switch between the two versions, and the DEPR ticket should communicate if the default is changing with enough time for operators to be able to set relevant flags to choose between the implementations. Removal Pending -======== +=============== This state indicates that support for the old implementation has been officially dropped and developers are able to begin removing code. If an item is in this state you should not expect the old implementation to work. diff --git a/oeps/processes/oep-0021/timeline.png b/oeps/processes/oep-0021/timeline.png deleted file mode 100644 index 7cbd30cdc7a70d94595459406ef1656b9d192cc5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16828 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