Spike - Identify opportunities to split mega applications into smaller pieces
- 1 Spike Overview
- 2 The application descriptor we are analyzing and attempting to split is:
- 3 Representing dependencies using a graph approach:
- 4 Evaluation
- 5 The tools used to build the graph and visualize dependencies are outlined below.
- 6 Implementation
- 7 Catalog of applications with modules, structured according to business operations and dependencies.
- 8 A dependency graph of applications divided by business operations.
- 9 The teams assigned to manage the maintenance of the newly split applications.
- 10 Decision record
- 11 Conclusion
Spike Overview
JIRA ID: EUREKA-305
Objective:
We have several large applications, often referred to as "mega applications." Our goal is to break these down into smaller, more granular applications to enable more frequent releases and deploy only the necessary components to the cluster for customer needs. The first step is to achieve this at the module level without refactoring the code or modifying dependencies. Next, we will align this approach with subject matter experts, who will independently define applications from a FOLIO perspective. We will then collaborate to find a balanced solution between both approaches.
Scope:
Identify suitable candidates for breaking modules out of the mega applications into smaller, standalone applications.
Focus on modules that many others depend on but that have fewer dependencies themselves, such as inventory or potentially finance.
Consider team responsibilities when splitting applications, especially in cases where applications span multiple team boundaries. For example, mod-inventory and ui-inventory are owned by Folijiet, while mod-inventory-storage is managed by Spitfire.
The application descriptor we are analyzing and attempting to split is:
app-platform-complete - GitHub link
It includes 53 backend modules and 54 UI modules.
Representing dependencies using a graph approach:
To illustrate the dependencies between modules, I decided to use a graph representation, where each module is a node, and the dependencies are represented as edges between them.
In the screenshot below, you can see all backend modules in the system, along with their dependencies, arranged in a hierarchical layout.
Evaluation
To group or aggregate nodes into larger nodes (or applications) based on dependencies—where nodes within a group only have dependencies on each other (i.e., they are internally connected but not externally)—the following steps can be followed:
Steps to Aggregate Nodes Based on Dependencies:
Identify Subgraphs:
Connected Components: Begin by identifying connected components (subgraphs) within the graph. These represent groups of nodes that are all directly or indirectly connected. If dependencies are confined within a connected component, the nodes in that group can be aggregated.
Dependency Analysis:
For each node, evaluate its dependencies. If all dependencies are confined to a specific subset of nodes, that subset can potentially be grouped into a larger node.
Cycle Detection:
Strongly Connected Components (SCC): In directed graphs, look for SCCs, where each node is reachable from every other node in the group. Nodes within the same SCC can be grouped together.
Community Detection Algorithms:
Utilize clustering algorithms, such as modularity-based or hierarchical clustering, to group nodes that are more interconnected internally than with nodes outside the group. This method allows for more flexible groupings beyond SCCs or connected components.
Check External Dependencies:
After identifying potential groups, ensure no nodes within the group have dependencies outside of it. If external dependencies exist, the group may need further refinement.
Merge Nodes:
Once valid groups are identified, where dependencies are self-contained, aggregate them into larger nodes. This process reduces the graph by replacing smaller nodes with single, larger nodes.
The tools used to build the graph and visualize dependencies are outlined below.
TBD link on GitHub after clearing the code
Implementation
The following modules have no dependencies and can be easily divided into separate applications:
mod-grpahql | mod-licenses | mod-service-interaction | mod-gobi | mod-rtac |
|
|
| folio_gobi-settings |
|
Candidates for Splitting with Minimal Changes:
The following modules can be divided into smaller applications if certain dependencies are resolved or eliminated.
The primary candidate is the Notification application, which consists of five modules.
Please refer to the screenshot below:
Catalog of applications with modules, structured according to business operations and dependencies.
Below is a preliminary catalog of modules grouped by backend and UI within the application, based on the technical analysis. This catalog highlights applications that can be separated without requiring code changes.
{
"applications": [
{
"id": "app-notification",
"modules": [
"mod-notify-3.2.1-SNAPSHOT.133",
"mod-event-config-2.7.2-SNAPSHOT.67",
"mod-sender-1.12.1-SNAPSHOT.50",
"mod-batch-print-1.2.0-SNAPSHOT.11",
"mod-email-1.17.1-SNAPSHOT.86",
"mod-template-engine-1.20.1-SNAPSHOT.97"
]
},
{
"id": "app-graphql",
"modules": [
"mod-graphql-1.12.1000355"
]
},
{
"id": "app-license",
"modules": [
"mod-licenses-6.1.0-SNAPSHOT.258",
"folio_licenses-11.1.10990000000022",
"folio_plugin-find-license-11.1.10990000000014"
]
},
{
"id": "app-interaction",
"modules": [
"mod-service-interaction-4.1.0-SNAPSHOT.118",
"folio_plugin-find-interface-5.1.100000167",
"folio_service-interaction-3.1.10990000000026",
"folio_dashboard-6.1.10990000000044"
]
},
{
"id": "app-gobi",
"modules": [
"mod-gobi-2.9.0-SNAPSHOT.240",
"folio_gobi-settings-3.1.109000000424"
]
},
{
"id": "app-rtac",
"modules": [
"mod-rtac-3.8.0-SNAPSHOT.98"
]
},
{
"id": "app-list",
"modules": [
"folio_lists-3.0.209900000000432",
"mod-fqm-manager-2.1.0-SNAPSHOT.354",
"mod-lists-2.1.0-SNAPSHOT.97",
"folio_plugin-query-builder-1.1.40990000000053"
]
},
{
"id": "app-bulk-edit",
"modules": [
"folio_bulk-edit-4.1.4090000003083",
"mod-bulk-operations-2.1.0-SNAPSHOT.268"
]
},
{
"id": "app-bulk-edit",
"modules": [
"folio_bulk-edit-4.1.4090000003083",
"mod-bulk-operations-2.1.0-SNAPSHOT.268"
]
},
{
"id": "app-inventory",
"modules": [
"folio_inventory-12.0.1090000007895",
"mod-inventory-storage-27.2.0-SNAPSHOT.1031",
"mod-inventory-20.3.0-SNAPSHOT.794",
"folio_plugin-find-instance-8.0.109000000741",
"folio_plugin-find-package-title-6.1.100000316",
"mod-inventory-update-3.4.2-SNAPSHOT.133",
"folio_plugin-create-inventory-records-4.1.100000535"
]
},
{
"id": "app-organization",
"modules": [
"folio_organizations-5.1.100000787",
"mod-organizations-2.0.0-SNAPSHOT.62",
"mod-organizations-storage-4.8.0-SNAPSHOT.106",
"folio_plugin-find-contact-5.1.100000172",
"folio_plugin-find-interface-5.1.100000167",
"folio_plugin-find-organization-5.1.109000000259"
]
},
{
"id": "app-orders",
"modules": [
"folio_orders-6.0.4090000001749",
"mod-orders-12.9.0-SNAPSHOT.947",
"mod-orders-storage-13.8.0-SNAPSHOT.384",
"folio_plugin-find-po-line-5.1.100000285",
"folio_acquisition-units-5.1.100000246",
"mod-ebsconet-2.3.0-SNAPSHOT.78"
]
},
{
"id": "app-data-export",
"modules": [
"folio_export-manager-3.1.109000000587",
"folio_data-export-6.1.1090000001023",
"mod-data-export-worker-3.3.0-SNAPSHOT.514",
"mod-data-export-spring-3.3.1-SNAPSHOT.276",
"mod-data-export-5.1.0-SNAPSHOT.435",
"folio_plugin-bursar-export-4.0.20990000000096"
]
},
{
"id": "app-data-import",
"modules": [
"folio_data-import-7.1.8090000002696",
"mod-data-import-3.2.0-SNAPSHOT.304",
"mod-di-converter-storage:2.3.0-SNAPSHOT.61",
"folio_plugin-find-import-profile-7.1.100000232",
"mod-source-record-manager-3.9.0-SNAPSHOT.967",
"folio_plugin-find-import-profile-7.1.100000232",
"mod-source-record-storage-5.9.0-SNAPSHOT.634",
"mod-di-converter-storage-2.3.0-SNAPSHOT.61"
]
},
{
"id": "app-agreement",
"modules": [
"folio_agreements-11.1.109900000000173",
"mod-agreements-7.1.0-SNAPSHOT.718",
"folio_plugin-find-eresource-7.1.1099000000008",
"folio_plugin-find-agreement-11.1.10990000000011",
"folio_local-kb-admin-8.1.10990000000011"
]
},
{
"id": "app-search",
"modules": [
"mod-search-3.3.0-SNAPSHOT.597"
]
},
{
"id": "app-authority",
"modules": [
"folio_marc-authorities-5.1.1090000007641",
"mod-entities-links-3.1.0-SNAPSHOT.281",
"folio_stripes-authority-components-4.1.109000000959",
"folio_stripes-marc-components-1.0.10000093"
]
},
{
"id": "app-serials",
"modules": [
"mod-serials-management-1.1.0-SNAPSHOT.108",
"folio_serials-management-1.1.10990000000070"
]
},
{
"id": "app-oai",
"modules": [
"folio_oai-pmh-5.1.109000000422",
"mod-oai-pmh-3.14.0-SNAPSHOT.354"
]
},
{
"id": "app-courses",
"modules": [
"folio_courses-6.1.109000000458",
"mod-courses-1.4.11-SNAPSHOT.161"
]
},
{
"id": "app-circulation",
"modules": [
"mod-audit-2.9.1-SNAPSHOT.168",
"mod-circulation-storage-17.3.0-SNAPSHOT.417",
"mod-circulation-24.3.0-SNAPSHOT.1253",
"mod-calendar-3.2.0-SNAPSHOT.169",
"folio_circulation-9.2.1090000002242",
"folio_calendar-11.0.2099000000006",
"folio_remote-storage-5.1.109000000315",
"mod-remote-storage-3.2.1-SNAPSHOT.206",
"folio_circulation-log-4.1.109000000440",
"mod-ncip-1.15.2-SNAPSHOT.88",
"folio_receiving-5.0.5090000001301",
"folio_requests-9.2.1090000002996",
"folio_checkin-9.2.109000000876",
"folio_checkout-11.0.1090000001088",
"mod-patron-blocks-1.11.0-SNAPSHOT.100",
"mod-feesfines-19.2.0-SNAPSHOT.230"
]
},
{
"id": "app-users",
"modules": [
"folio_users-11.0.1090000005958",
"mod-patron-6.2.0-SNAPSHOT.136",
"mod-user-import-3.9.0-SNAPSHOT.100"
]
},
{
"id": "app-finances",
"modules": [
"folio_finance-6.0.109000000868",
"mod-finance-5.0.0-SNAPSHOT.257",
"mod-finance-storage-8.7.0-SNAPSHOT.364",
"folio_plugin-find-fund-3.1.100000171"
]
},
{
"id": "app-invoice",
"modules": [
"folio_invoice-6.0.4090000001067",
"mod-invoice-5.9.0-SNAPSHOT.445",
"mod-invoice-storage-5.9.0-SNAPSHOT.161"
]
},
{
"id": "app-quick-marc",
"modules": [
"folio_quick-marc-9.0.1090000002742",
"mod-quick-marc-5.2.0-SNAPSHOT.294",
"mod-invoice-storage-5.9.0-SNAPSHOT.161"
]
}
]
}
A dependency graph of applications divided by business operations.
The diagram below shows a graph representing all dependencies between the applications listed in the catalog. The graph includes applications without circular dependencies, which can be split independently; however, some applications have circular dependencies that must be resolved before further separation into smaller components.
The teams assigned to manage the maintenance of the newly split applications.
Application | Team |
---|---|
app-graphql | Thor |
app-license-1.0.0 | Bienenvolk |
app-interaction | Bienenvolk |
app-gobi-1.0.0 | Thunderjet |
app-rtac-1.0.0 | Dreamliner |
app-oai | Firebird |
app-serials | K-Int |
Decision record
Based on our discussion, we have agreed not to add additional functionality in EUREKA to manage circular dependencies. Instead, we’ll ask the team to resolve these dependencies first, allowing us to split them into smaller applications further once ready. Simultaneously, we have agreed to split approximately seven smaller applications during the Sunflower release and assign the appropriate team for future maintenance. Additionally, we identified one candidate application, app-organization, which can be split if the Sunflower team can do so during the release.
Conclusion
To continue applying the algorithm, we can attempt to group certain modules within the applications and create stories for the team, outlining the required changes and how to implement them. However, this process must still be aligned with subject matter experts, who will also work on splitting modules into applications, and then negotiate an approach that strikes a balance.
Spike Status: In Progress