-
Notifications
You must be signed in to change notification settings - Fork 33
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
[Core] Improve dependency injection for submodules #810
Comments
It seems like as the code evolved organically, we create factory functions starting with Q1: Wdyt about the point above?
Q2: What if we simply treat all submodules the same as modules and have no differentiation between the two? Would this simplify things
Q3: What if we just panic if you try to access an uninitialized submodule instead? Alternatively, since they all have In general, I'm very open to refactoring anything as long as we have time, capacity and sanity to do it. Follow up questions: Q4: What you be able to pick this up? If so, which iteration do you think it fits in and do you think it'll be a Medium or Large effort (once we iron out the details)? |
I have to think on it a bit more to figure out if I have an opinion on
I think we can for the most part with the exception of having submodules conform to the
Sounds interesting but I think I would need to see a snippet to understand what you mean. To add context to the code comment, the scenario where the peerstore is retrieved from the bus is when the CLI starts up its P2P module. Before it does so, it creates and adds an
Happy to pick it up! I would estimate it as a Medium which I would distribute between making a change to the All that being said, I don't see this as particularly urgent and I'm not sure that there's a place in the sprint(s) where it naturally fits but I would personally prefer to resolve this before adding any new code which injects and/or retrieves submodules from the module registry. Wdyt about making it a stretch goal for next sprint or something like that? |
Adding some diagrams that I don't think make sense to include in the PR description but may make sense to include as documentation at some point: Example
|
@bryanchriswhite I reviewed the diagrams you provided above very carefully and am 100% aligned with the approach. As we discussed offline, I think we should
Do you have any other questions or feedback or anything? From my perspective, the above is a pretty clear and well-formed solution. |
## Description 1. Simplify `PeerstoreProvider` interface 2. Extend it to support retrieval of the unstaked actor peerstore 3. Implement the extended interface in `persistencePeerstoreProvider` ### Before ```mermaid classDiagram class InterruptableModule { <<interface>> Start() error Stop() error } class IntegratableModule { <<interface>> +SetBus(bus Bus) +GetBus() Bus } class InitializableModule { <<interface>> +GetModuleName() string +Create(bus Bus, opts ...Option) (Module, error) } class Module { <<interface>> } Module --|> InitializableModule Module --|> IntegratableModule Module --|> InterruptableModule class PeerstoreProvider { <<interface>> +GetStakedPeerstoreAtHeight(height int) (Peerstore, error) +GetP2PConfig() *P2PConfig } class persistencePeerstoreProvider class rpcPeerstoreProvider persistencePeerstoreProvider --|> PeerstoreProvider rpcPeerstoreProvider --|> PeerstoreProvider PeerstoreProvider --|> Module ``` ### After ```mermaid classDiagram class IntegratableModule { <<interface>> +GetBus() Bus +SetBus(bus Bus) } class PeerstoreProvider { <<interface>> +GetStakedPeerstoreAtHeight(height int) (Peerstore, error) +GetUnstakedPeerstore() (Peerstore, error) } class persistencePeerstoreProvider class rpcPeerstoreProvider class p2pModule class unstakedPeerstoreProvider { <<interface>> +GetUnstakedPeerstore() (Peerstore, error) } persistencePeerstoreProvider --|> PeerstoreProvider persistencePeerstoreProvider --> p2pModule : from Bus rpcPeerstoreProvider --> p2pModule : from Bus p2pModule --|> unstakedPeerstoreProvider rpcPeerstoreProvider --|> PeerstoreProvider rpcPeerstoreProvider --|> Module PeerstoreProvider --|> IntegratableModule class Module { <<interface>> } Module --|> InitializableModule Module --|> IntegratableModule Module --|> InterruptableModule ``` ## Issue Realted: - #810 Dependants: - #505 - #806 ## Type of change Please mark the relevant option(s): - [ ] New feature, functionality or library - [ ] Bug fix - [ ] Code health or cleanup - [ ] Major breaking change - [ ] Documentation - [ ] Other <!-- add details here if it a different type of change --> ## List of changes - Replaced embedded `modules.Module` with simpler `modules.IntegratableModule` in `PeerstoreProvider` interface - Removed unused `PeerstoreProvider#GetP2PConfig()` method - Added `PeerstoreProvider#GetUnstakedPeerstore()` method - Added `p2pPeerstoreProvider` implementation of `PeerstoreProvider` interface - Added `Factory` generic type ## Testing - [ ] `make develop_test`; if any code changes were made - [x] `make test_e2e` on [k8s LocalNet](https://github.com/pokt-network/pocket/blob/main/build/localnet/README.md); if any code changes were made - [ ] `e2e-devnet-test` passes tests on [DevNet](https://pocketnetwork.notion.site/How-to-DevNet-ff1598f27efe44c09f34e2aa0051f0dd); if any code was changed - [x] [Docker Compose LocalNet](https://github.com/pokt-network/pocket/blob/main/docs/development/README.md); if any major functionality was changed or introduced - [x] [k8s LocalNet](https://github.com/pokt-network/pocket/blob/main/build/localnet/README.md); if any infrastructure or configuration changes were made <!-- REMOVE this comment block after following the instructions If you added additional tests or infrastructure, describe it here. Bonus points for images and videos or gifs. --> ## Required Checklist - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have added, or updated, [`godoc` format comments](https://go.dev/blog/godoc) on touched members (see: [tip.golang.org/doc/comment](https://tip.golang.org/doc/comment)) - [ ] I have tested my changes using the available tooling - [ ] I have updated the corresponding CHANGELOG ### If Applicable Checklist - [ ] I have updated the corresponding README(s); local and/or global - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] I have added, or updated, [mermaid.js](https://mermaid-js.github.io) diagrams in the corresponding README(s) - [ ] I have added, or updated, documentation and [mermaid.js](https://mermaid-js.github.io) diagrams in `shared/docs/*` if I updated `shared/*`README(s)
## Description Introduces the `Submodule` interface and applies it to the P2P module's peerstore provider. ## Issue Deliverables 1, 2, 3, & 5: - #810 ## Type of change Please mark the relevant option(s): - [ ] New feature, functionality or library - [ ] Bug fix - [x] Code health or cleanup - [ ] Major breaking change - [x] Documentation - [ ] Other <!-- add details here if it a different type of change --> ## List of changes * fixed typo; renamee `IntegratableModule` to `IntegrableModule` * renamed `InitializableModule` to `InjectableModule` * removed `InjectableModule#Create()` as `Moudle` also embeds `ModuleFactoryWithConfig` * added `Submodule` interface type * refactored peerstore providers as submodules * updated module README ## Testing - [x] `make develop_test`; if any code changes were made - [x] `make test_e2e` on [k8s LocalNet](https://github.com/pokt-network/pocket/blob/main/build/localnet/README.md); if any code changes were made - [x] `e2e-devnet-test` passes tests on [DevNet](https://pocketnetwork.notion.site/How-to-DevNet-ff1598f27efe44c09f34e2aa0051f0dd); if any code was changed - [ ] [Docker Compose LocalNet](https://github.com/pokt-network/pocket/blob/main/docs/development/README.md); if any major functionality was changed or introduced - [x] [k8s LocalNet](https://github.com/pokt-network/pocket/blob/main/build/localnet/README.md); if any infrastructure or configuration changes were made ## Required Checklist - [x] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have added, or updated, [`godoc` format comments](https://go.dev/blog/godoc) on touched members (see: [tip.golang.org/doc/comment](https://tip.golang.org/doc/comment)) - [ ] I have tested my changes using the available tooling - [ ] I have updated the corresponding CHANGELOG ### If Applicable Checklist - [x] I have updated the corresponding README(s); local and/or global - [ ] I have added tests that prove my fix is effective or that my feature works - [x] I have added, or updated, [mermaid.js](https://mermaid-js.github.io) diagrams in the corresponding README(s) - [ ] I have added, or updated, documentation and [mermaid.js](https://mermaid-js.github.io) diagrams in `shared/docs/*` if I updated `shared/*`README(s) --------- Co-authored-by: d7t <[email protected]> Co-authored-by: @olshansky <[email protected]> Co-authored-by: Daniel Olshansky <[email protected]> Co-authored-by: Daniel Olshansky <[email protected]>
Objective
Improve the dependency injection experience for submodules (e.g. P2P's
PeerstoreProvider
, telemetry'sTimeSeriesAgent
, etc.). I think this may generally apply to submodules which need to embed thebase_modules.InterruptableModule
.Origin Document
Observation made while working on #732. In order to complete the peerstore provider refactor (#804).
When retrieving modules from the bus (via the module registry), they are asserted to the correct interface type by their respective
Bus#Get_X_Module()
method. In contrast, retrieving submodules from the registry must be done directly (at the time of writing) which requires additional type assertions and boilerplate in each place any submodule is retrieved from the bus.Goals
Module
unless appropriate).Concrete Example
Below,
rpcPeerstoreProvider
MUST implementModule
so that it can traverse theModuleRegistry
dependency injection system that we currently have, as it's used outside of the P2P module in the CLI. This results in it embedding the noop implementations ofInterruptableModule
and being additionally over-constrained by theInitializableModule#Create()
interface method:Requiring
rpcPeerstoreProvider
(the injectee) to implementInitializableModule
fosters boilerplate around the respective constructor function and everywhere it's injected. Here is an excerpt fromp2p/providers/peerstore_provider/rpc/provider.go
:The
Create()
function isn't currently used anywhere in the codebase, same goes for therpcPeerstoreProvider#Create()
method, which only serves to satisfy theInitializableModule
interface requirement. This increases complexity and reduces readability and maintainability on both the injectee and injector side in my opinion.Here is an excerpt from
p2pModule
which illustrates the complexity this design introduces on the injector side (which will present everywhere a submodule is retrieved from theModuleRegistry
):I would prefer to be able to do something like this:
Deliverable
Submodule
interface definitionInitializableModule#Create()
(unnecessary as ofModuleFactoryWithOptions
embedding)InitializableModule
toInjectableModule
Bus
inteface (like each module has)ModuleRegistry
module names toInjectableModule
s (instead ofModule
s)Non-goals / Non-deliverables
General issue deliverables
Testing Methodology
make test_all
LocalNet
is still functioning correctly by following the instructions at docs/development/README.mdk8s LocalNet
is still functioning correctly by following the instructions hereCreator: @bryanchriswhite
The text was updated successfully, but these errors were encountered: