-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[DRAFT] feat: Create OEP-XXX Micro-frontend Domains
- Loading branch information
Showing
1 changed file
with
171 additions
and
0 deletions.
There are no files selected for viewing
171 changes: 171 additions & 0 deletions
171
oeps/architectural-decisions/oep-XXXX-micro-frontend-domains.rst
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
================================ | ||
OEP-XXXX: Micro-frontend Domains | ||
================================ | ||
|
||
.. list-table:: | ||
:widths: 25 75 | ||
|
||
* - OEP | ||
- :doc:`OEP-XXXX <oep-XXXX-micro-frontend-domains>` | ||
* - Title | ||
- Micro-frontend Domains | ||
* - Last Modified | ||
- 2022-11-09 | ||
* - Authors | ||
- Adolfo R. Brandes <[email protected]> | ||
* - Arbiter | ||
- TBD | ||
* - Status | ||
- Draft | ||
* - Type | ||
- Architecture | ||
* - Created | ||
- 2022-11-09 | ||
* - Review Period | ||
- TBD | ||
* - Resolution | ||
- TBD | ||
* - References | ||
- TBD | ||
|
||
|
||
******** | ||
Abstract | ||
******** | ||
|
||
The decision to gradually implement a micro-frontend architecture for Open edX was a largely successful attempt at avoiding some limitations of the monolithic ``edx-platform`` codebase. In particular, it allowed the project to integrate more and better features by leveraging newer frontend technology, all much faster than would have been possible otherwise. At the same time, because features encapsulated in micro-frontends (henceforth, "MFEs") are very loosely coupled to each other, this architecture eliminates most integration bottlenecks, allowing individual teams working on any given feature to not be a lot more *productive*. | ||
|
||
However, roughly 3 years into this gradual re-platforming, several drawbacks to the chosen implentation of complete single-page app ("SPA") independence have been identified. This OEP proposes a middle-ground based on Domain Driven Development ("DDD") and current industry best-practices, where a minor increase in integration costs is traded for large potential gains in user experience, customizability, ease of deployment, and in certain cases, even development efficiency. | ||
|
||
|
||
********** | ||
Motivation | ||
********** | ||
|
||
When moving to micro-frontends, a (now known to be) uncommon choice was made: to have *completely* independent SPAs, each with their separate deployment, endpoint, and different technology stack. While the goal of developing platform features more efficiently was achieved, the price to pay was not insignificant. Here are some critical issues that the new architecture introduced: | ||
|
||
* Inconsistency between MFEs and the legacy codebase | ||
|
||
* UI is designed differently, resulting in poorer UX across boundaries; | ||
* They're also implemented differently, which makes tooling, development, and branding that much harder than before, because both implementations have to be dealt with. | ||
|
||
* Inconsistency between the UIs of MFEs themselves | ||
|
||
* Each MFE can use whatever paradigm was in vogue during its development, leading to differences (some minor, some major) in UX; | ||
* This makes it inordinately difficult to theme components that are not common to all MFEs, such as headers and footers. | ||
|
||
* Regression in customizability | ||
|
||
* To achieve similar customizability to the legacy codebase, MFEs need to be forked, with all the maintenance cost that that entails; | ||
* The fact each MFE is fully independent means that it is harder to implement a consistent plugin interface between all of them. | ||
|
||
* Changes that affect multiple MFEs are costly | ||
|
||
* Development effort is multiplied by the number of existing MFEs, as each change needs to be duplicated; | ||
* Because no dependencies are shared, Webpack build time of any potentially shared library is multiplied by the number of existing MFEs. | ||
|
||
* Inefficient use of network bandwidth | ||
|
||
* Dependencies have to be downloaded multiple times by the browser. | ||
|
||
* Inconsistent documentation | ||
|
||
* The fact each MFE is fully independent contributes to inconsistencies in the quality of documentation of the features implemented. | ||
* This leads to confusion at release time: is a given MFE `good enough <https://openedx.atlassian.net/wiki/spaces/COMM/pages/3561521275/Requirements+for+an+MFE>`_ to ship? | ||
|
||
* Inconsistency in deprecation efforts | ||
|
||
* The gradual replacement of features goes contrary to the Principle of Least Surprise: why did a feature disappear between releases? | ||
|
||
Some of these are a natural consequence of abandoning server-side rendering; in particular, the authors do not suggest it will ever be possible for an operator to override *anything* on a page without forking the codebase, as was possible with Comprehensive Theming. However, it seems all of the listed problems can at least be ameliorated - if not completely resolved - by implementing a combination of industry best-practices that have risen to maturity in the past couple of years, all of which introduce foreseeable costs that are clearly outweighed by their advantages. | ||
|
||
It is thus a good time to consider these practices - specified below - weighing both the development cost of implementation and future recurring ones against their benefits. | ||
|
||
|
||
************* | ||
Specification | ||
************* | ||
|
||
This OEP proposes a middle-ground between a monolithic codebase and full MFE independence based on the existing industry-accepted concept of Domain Driven Development. The Open edX frontend will be split into formal top-level domains, including but not limited to the LMS and Studio, each of which will be implemented as a Container SPA that, in turn, will render multiple partly-independent MFEs effectively as components. The latter will be re-engineered to conform to the hosting domain's interfaces. | ||
|
||
This is to be a full re-platforming, to be undertaken as a single long-term project prior to release. It is in opposition to the currently in-progress gradual conversion of single pages to fully independent MFEs that can be linked to from the pre-existing monolithic framework; the opposite, injecting legacy pages into a domain SPA as components, would be unjustifiable. The difficulty of working with the legacy codebase is the main reason why it was decided to move to MFEs in the first place! | ||
|
||
On the other hand, the current gradual conversion to fully independent MFEs need not be interrupted; the domain-based re-platforming proposed here can be executed in parallel. Why? Converting an already fully independent MFE to a domain-hosted one is much less costly than the initial corresponding extraction from the monolith. And conversely, it is conceivable that a particular monolithic page, after extraction directly into a domain-hosted MFE, could then be cheaply backported *the other way*, into a fully-independent one for earlier release while the re-platforming project is incomplete. | ||
|
||
As this OEP is developed, we will further investigate: | ||
|
||
#. Integration strategy | ||
#. Domain SPAs and their interfaces | ||
#. Shared dependencies | ||
#. MFEs as components | ||
#. ... | ||
|
||
TODO: | ||
|
||
* What is the relationship of this project to the Modular Learning effort? They're both long-term projects, but is there anything else that could be coordinated between them? Maybe this project should only target the modular codebase, and ignore ``edx-platform`` entirely? (Are the APIs between the two even the same?) | ||
|
||
Integration strategy | ||
==================== | ||
|
||
At time of writing there appear to be three commonly recommended strategies for integration of MFEs into container apps: | ||
|
||
* `Run-time integration via JavaScript <https://martinfowler.com/articles/micro-frontends.html#Run-timeIntegrationViaJavascript>`_ | ||
* `Run-time integration via Web Components <https://martinfowler.com/articles/micro-frontends.html#Run-timeIntegrationViaWebComponents>`_ | ||
* `Webpack Module Federation <https://webpack.js.org/concepts/module-federation/>`_ | ||
|
||
TODO: | ||
|
||
* Which alternative is easier to understand and implement? | ||
* What are the drawbacks to each, in particular as compared to the other, but also with regards to existing MFE characteristics (which one is better suited for React)? Is there anything that would be much harder to do with one (or both) of them? | ||
* Is Webpack Module Federation mature enough, yet? | ||
* Choose between these, or suggest another, better alternative. | ||
|
||
Domain SPAs and their interfaces | ||
================================ | ||
|
||
TODO: | ||
|
||
* What does each initial domain SPA look like with no MFEs? What goes into the containing app (header? footer?), what goes into MFEs? | ||
* Define further container SPA and interface characteristics. | ||
|
||
Shared dependencies | ||
=================== | ||
|
||
TODO: | ||
|
||
* What dependencies should be shared between all MFEs? (React, Redux, ...?) | ||
* Should we use lazy loading, and if so, how? | ||
|
||
|
||
MFEs as components | ||
================== | ||
|
||
TODO: | ||
|
||
* Define how an MFE will connect to the containing SPA's interfaces. | ||
* Can an MFE be used across domains? | ||
|
||
|
||
************************ | ||
Reference Implementation | ||
************************ | ||
|
||
TODO | ||
|
||
|
||
********************* | ||
Rejected Alternatives | ||
********************* | ||
|
||
TODO | ||
|
||
|
||
************** | ||
Change History | ||
************** | ||
|
||
2022-11-09 | ||
========== | ||
|
||
* Document created | ||
* `Pull request #XXX <https://github.com/openedx/open-edx-proposals/pull/XXX>`_ |