Helidon Config
io.helidon.common.config -> "Config API" io.helidon.config -> "Config"
Helidon 1.x -> 3.x There is a single "Config" module, that contains both APIs, SPIs, and implementation
Helidon 4.x, current main
For the purpose of minimizing size of dependencies for Pico, and to remove dependencies "into" config module from Pico and common,
we have created a "Config API" module
- there is a full duplication of all of the APIs in "Config" to have backward compatibility as much as possible
This approach brings in a "dirty" state, where we duplicate APIs, we want to use the "Config API", but need "Config" in some places in Helidon
We could use this with a single backward incompatible change (method asNodeList
), not sure how big impact this single method
would have on implementation and Helidon in general
Revert back to a single "Config" module, that would be used by Pico and all other Helidon modules as we have in 3.x.
We should remove dependency on helidon-logging-jul
and jakarta-annotation
as a runtime dependency of Config
This is fully backward compatible with Helidon 3, would introduce the full config as a dependency of Pico (and helidon-common-configurable
)
This would not allow us to depend on Pico in Config, so if we wanted to create a Pico service for config, we would need to have a new module such as helidon-config-pico
Separate API fully from "Config" into "Config API".
This would require a change of all usages of Config, to work with the API rather than with the implementation, and to create config instances using the chosen
approach (API or runtime).
This approach would create a clean dependency tree, where Config runtime could actually use Pico as a dependency.
Also module helidon-common-configurable
would only depend on API
We would need to decide about naming - current (helidon-common-config; helidon-config) - possible (helidon-config-api; helidon-config-runtime) - this is practically worse than the choice above, as it requires pico and common to have a dependency into config. I would choose this option only if we decide to move all APIs and SPIs to API (including builder etc.)
This option has additional sub-options:
a) Move all APIs and SPIs to Config API b) Move Config.Builder API to Config API - requires a) c) Move only APIs, and leave SPIs as implementation specific (ConfigSource, Parser etc.) - mutually exclusive with b
This has a few impacts on the use of Config:
- Usages can be refactored to
Config API
, as that is the right way to access configuration data - Creating a new config instance
a) We can have
Config.create()
in "Config API" and use service loader to get the default config instance b) We can refactor currentio.helidon.config.Config
toHelidonConfig
and add all thecreate()
methods andbuilder()
methods there e.g. we could have: (config API).Config config = (config API).Config.create(); (config API).Config config = (Config).HelidonConfig.create(myConfigSource); c) We can move all the create and builder methods to "Config API" and use service loader to discover a builder implementation (requires sub-options a, and b)
It should be noted that currently
common-config
is a sparse set of interfaces/contracts and methods from the config impl module. Option 2 assumes that we will always want a "full" config API definition instead of the minimal definition for what config is at its pure essence (Config and ConfigValue at the core of common). Whether common-config is sparse or full seems orthogonal to this discussion for the API signature, and a "clean" API design.From the guiding principle perspective, I believe the following:
asNodeList()
as in this case) then we should fix it and make a clean API during a major version change.What we are mainly debating here is the tradeoffs between principle #1 and principle #3: Noting that the current
asNodeList
method will be 100% backward compatible if we leave it alone, but it will not be "clean".Now more concretely for this case - here is my opinion/suggestion:
asNodeList
as deprecated. This is a nod to option 0 but with a caveat to allow for backward compatibility per our principles.asNodeList
method that is following the right signature for the generics declaration, thereby fixing the API. This ultimately adheres to all of the principles that I shared above.