Rebalance the dependency tree by moving & tossing the modules #765
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
TL;DR: Rebalance the dependency tree by moving & tossing the modules.
There are no changes in the behaviour of the framework or the public interfaces. Some preparatory changes were made as separate PRs (for semantic grouping and easier investigations in the future; in some PRs, there were minor changes of public interfaces (e.g. for daemon stopping flags)):
The time is right: after it is feature-complete and most likely will no be expanding in complexity, but before it might get widely adopted and contributions will flow (we can dream, [slowly] we… can… dream…).
Problem
Background: In the beginning, several decisions were made to structure the framework to two primary packages —
reactor
andstructs
— and keep them layered inside. Eventually, this decision forced all data structures to be placed instructs
even if they belonged to some modules/aspects/functionality ofreactor
— to not violate layering. As a result, this broke cohesion and made almost allreactor
aspects "mirrored" instructs
with no particular reason except for dependencies, while bothreactor
&structs
themselves were exploding in complexity.Goal: The goal is to rebalance the dependency tree: specifically, to increase cohesion and reduce the complexity of layers.
Solution
AS IS: Before the change, there were these essential layers:
kopf.toolkits
,kopf.on
,kopf
-- user-facing API.kopf.reactor
.kopf.engines
.kopf.structs
.kopf.storage
.kopf.aiokits
(only since recently).kopf.clients
-- low-level K8s API communication.kopf.utilities
-- system- & language-level helpers and adapters.TO BE: After the change, the layered layout is this:
kopf
,kopf.on
,kopf.testing
— public interfaces (can be imported & accessed).kopf._kits
— the user-facing helpers (not used in the framework itself).kopf._core
— the high-level essentials of the framework:kopf._core.reactor
— the central unit that runs and reacts to resource changes.kopf._core.engines
— specialised aspects/features of the framework.kopf._core.intents
— operator- & reaction-defining structures (causes & effects).kopf._core.actions
— functions & handler invocation with dynamic kwargs.kopf._cogs
— the low-level helpers & glue-code of the framework:kopf._cogs.clients
— the Kubernetes API communication.kopf._cogs.configs
— the settings & persistence storage classes.kopf._cogs.structs
— reusable simple(!) data structures and types.kopf._cogs.aiokits
— asynchronous primitives and patterns.kopf._cogs.helpers
— system- & language-level helpers and adapters.The specific modules are moved across these packages for better balance and cohesion.
A rough criterion of a good balance is ~7 modules per package; the imports should be one-liners again.
Side-goals
Besides, a few side-goal were achieved:
Hidden packages: While moving the modules, those considered internal are now hidden behind underscore-named packages, so that any attempt to import them would raise concerns that they are not part of the public API and can change at any time. Previously, modules like
kopf.clients.patching.patch_obj()
could be mistakenly perceived as public too.Import linter: Automated import linter is added, which ensures that the modules are layered accordingly and no violation (e.g. reversed imports of upper layers to lower levels) is going to happen in the future.