-
Notifications
You must be signed in to change notification settings - Fork 352
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
Simplify bootstrap function arguments with default-able options #2078
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The argument structs are good, but the other changes look like a revert to an earlier system with 5-argument functions.
impl<'config> Builder<'config> { | ||
/// Initializes the builder with two [`FullNode`] values representing two different | ||
/// running full nodes, to bootstrap chain A and chain B respectively. | ||
pub fn with_node_pair( | ||
test_config: &'config TestConfig, | ||
node_a: FullNode, | ||
node_b: FullNode, | ||
) -> Self { | ||
Self { | ||
test_config, | ||
node_a, | ||
node_b, | ||
client_options_a_to_b: Default::default(), | ||
client_options_b_to_a: Default::default(), | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why remove the builder for a less convenient function API? This has the same purpose: make the test code more convenient to write in the simplest cases, while making customization possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the builder pattern is fine as long as it does not force the user to always use the pattern. There is a trade off between readability and writability. When I tried to use the new builder pattern, I found it much more difficult to understand, as I now have to jump between dozens of lines of code with mutation, side effects, and could potentially be executed non-linearly. In comparison, function argument passing have linear semantics, so I just need to read the few lines to immediately understand the semantics of the code.
Anyway, I re-introduce the builder pattern in aa336c7 with the pattern applied to the BootstrapClientOptions
type instead. The builder methods are opt-in, with the Default
trait or explicit field accessors available in case users want to opt out. This helps make it clear that there are only syntactic sugar methods and users only need to worry about side effects in the other functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The mandatory config_modifier
closure argument is also annoying. In the builder, I tried to simplify this by having two finalization methods: bootstrap
as the basic case without the modifier closure, and bootstrap_with_config
to provide the modifier. Passing the closure to the final build method also hints the user that the closure is invoked during the bootstrap process, not as part of the option setup.
Readability is subjective here. To me, it's much more intuitive to read the builder method chain where most of the parameters are supplied to a clearly named method, if they need to be customized at all, rather than trying to remember the meaning or the "dunno, use default" value of each of the anonymous arguments in a function call site. This is the rationale behind the clippy lint and the related API guideline. In this case it's not that bad, three to five parameters with distinct types, so let's go with this. These utilities are used by the test framework, not the tests themselves, so readability and convenience is less important here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah the main point is that these are internal functions that are not meant to be called frequently. They act more as code fragments not as reusable modules. The higher level constructs like BinaryChainTest
are the real abstraction that hides the complexity, so we only need to focus on providing clean interfaces there.
…rmalsystems#2078) * Refactor bootstrap chain and foreign client code * Introduce BootstrapChannel/ConnectionOptions * Use builder pattern for bootstrap option types
Crate:
ibc-test-framwork
Description
Simplifies the interface for bootstrapping chain/client/connection/channel in integration tests. The optional arguments are now grouped into an option type like
BootstrapChannelOptions
with aDefault
instance. So callers who only want to provide the required arguments can pass inDefault::default()
for the optional arguments.This will also allow the bootstrap functions to evolve more easily in the future as more overrides are added, which can be added to the options types.
PR author checklist:
unclog
.docs/
).Reviewer checklist:
Files changed
in the GitHub PR explorer.