Skip to content
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

Create the ConfigBuilder #196

Merged
merged 4 commits into from May 8, 2021
Merged

Create the ConfigBuilder #196

merged 4 commits into from May 8, 2021

Conversation

szarykott
Copy link
Contributor

This is a draft PR to show an idea of how could ConfigBuilder look like.

It does not bring a lot of new functionality. It just splits Config that was a mutable configuration combined with a builder into two separate structs. It brings certain benefits:

  • Config is no longer refreshed when a new source is added
  • More from the clean code perspective, it lifts concepts of "mutable" and "frozen" config to type level, thus mitigating runtime errors. It is a clean code issue, as Config could not be frozen before as it was a dead private API.

Immutability is considered good programming practice, but not everyone might like it. I'd like to hear the opinions of users of the library - do you mutate config often after application initial bootstrap, do you consider such a mutability a needed feature?

I do not intend to push it in its current form, it is just to showcase an idea. To consider it mergeable discussion has to take place regarding few subjects:

  • is it the correct way to go
  • should old ways be deprecated as it is done now or should they be removed

In the current state there is a lot of deprecation warnings, so please do not mind them now and focus on more high-level aspects of this PR.

I attach a graph of the intended workflow so that it is easier to see the big picture.
image

src/builder.rs Outdated Show resolved Hide resolved
src/builder.rs Outdated Show resolved Hide resolved
src/builder.rs Outdated Show resolved Hide resolved
src/builder.rs Outdated Show resolved Hide resolved
src/config.rs Outdated Show resolved Hide resolved
src/config.rs Outdated Show resolved Hide resolved
src/config.rs Show resolved Hide resolved
src/builder.rs Outdated Show resolved Hide resolved
src/builder.rs Outdated Show resolved Hide resolved
@matthiasbeyer
Copy link
Collaborator

Hi. So how do we move forward here? I guess this and #180 overlaps too much to keep both open, right? I'd close #180 therefore and continue with this PR here (not only, but also because I want to encourage you to contribute! 😆 ).

If you don't mind, feel free to take patches from git.beyermatthias.de/config - branch 'szarykott-builder-patches' (git fetch https://git.beyermatthi.as/config szarykott-builder-patches && git merge --ff-only FETCH_HEAD) were I did some minor cleanup for this PR for a few things I think are appropriate. The change to calling Expression::from_str is controversial, I guess 😄 but I'd rather be a bit more explicit in the code here.

@szarykott
Copy link
Contributor Author

Thank you for the heads up @matthiasbeyer !

Correct, those two PRs follow the same principle with minor differences. Thank you for willingness to merge my PR then. I'll see what are the changes you propose and push them here. I will handle it, but it might take me few days.

@matthiasbeyer
Copy link
Collaborator

No worries, we are not in a hurry! 😆

@matthiasbeyer matthiasbeyer added this to the 0.12.0 milestone Apr 20, 2021
@szarykott
Copy link
Contributor Author

I merged your patches and pushed them. Could you please resolve all pull request discussions you consider solved for better visibility of what is there to do?

If you are ok with the way it is, I am also going to refactor tests to use builder pattern, due to a large number of deprecation warnings in tests.

@szarykott
Copy link
Contributor Author

I tried to squash commits, something weird happened, please be patient ;)

@matthiasbeyer
Copy link
Collaborator

I resolved everything and I will do a new review once you're ready! 😄

@szarykott
Copy link
Contributor Author

Hello again!

I think this is more-less the final version of this pull request.

There are a lot of files changed, but most of them are tests.

Here's a brief description of the changes.

  1. builder.rs contains a builder struct that is the essence of this pull request.
  2. Old implementation is deprecated, but not removed.
  3. To avoid deprecation warnings, I added allow(deprecated) on appropriate lines in the crate.
  4. To have new features tested I changed all the tests to use ConfigBuilder.
  5. To have old features still tested I duplicated appropriate tests and put in tests/legacy folder (hoping they will be removed after 0.12 release). Tests in this folder have allow(deprecated) attribute. The entry point for them is the legacy_tests.rs file in the tests folder.
  6. I added a new implementation of Source (for [Box<...>]) as Clippy issued a warning regarding the build_internal method. Another way to fix it would be to disable this lint on this method, but it seems a bit hacky, while it was relatively easy to add a new implementation of Source.

@szarykott szarykott marked this pull request as ready for review April 25, 2021 09:48
Copy link
Collaborator

@matthiasbeyer matthiasbeyer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome.

One comment, but that wouldn't block merging. I rather merge now and do some more changes later 😃

One more rebase please:

  1. reword the first commit to just "Add ConfigBuilder for builder-pattern style Config initialization"
  2. squash into first commit: b2e50ff
  3. squash 43973fe and fc0b227 into 6d2dada, rewording to "Use builder-pattern in tests, keep old interface tests in legacy" (or something like that)
  4. drop de097d3

You can keep the other commits, especially 2f8aca7 (but, if possible, with some more appropriate wording) - because it can easily be reverted later.

Sorry for another round of rebasing, I hope you don't mind. Otherwise, this is ready for merging IMO.

src/builder.rs Outdated
/// # Errors
///
/// Fails if `Expression::from_str(key)` fails.
pub fn set_default<S, T>(&mut self, key: S, value: T) -> error::Result<&mut ConfigBuilder>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking about why we're using the &mut self builder-pattern style here. Maybe mut self would be more appropriate (moving and returning Self), so we can chain the build() function properly?

Nothing that blocks this PR from landing though!

That would also make the impl Source for [Box<dyn Source + Send + Sync>] unnecessary I guess.

Copy link
Contributor Author

@szarykott szarykott Apr 27, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I've used &mut self, because this is how it was used in Config.

But the point is valid, the consuming version would allow chaining things properly, I am going to change this PR. After all, if it turns out in the future that the &mut self version is required by users, it is "less breaking" to lessen required ownership (self -> &self, etc.) than the other way around.

It would not make this implementation you mention unnecessary as it is needed because there is a build_cloned function that takes &self. It makes sense to have a cloned version, especially when speaking about the configuration that can change over time (etcd, consul, even files in rare circumstances) that you might want to refresh periodically in your application.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

files in rare circumstances

not even in rare ones: Think of a server software which should be able to pick up config changes without restarting!

I am going to change this PR

Awesome!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am happy you agree about the two flavors of the build method. I did not want to sound too pushy on this as I remember your opposition to the idea in some earlier comments, but maybe I just recall wrongly.

Code is changed, ConfigBuilder's methods are not consuming, except for one of two build methods. Feel free to merge as soon as you want!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not change commit messages exactly as you wanted, but I hope it is fine the way it is.

@szarykott szarykott force-pushed the builder branch 2 times, most recently from 597dbfb to da0b047 Compare April 27, 2021 20:56
@szarykott szarykott changed the title Draft: Create the ConfigBuilder Create the ConfigBuilder Apr 29, 2021
Copy link
Collaborator

@matthiasbeyer matthiasbeyer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So as far as I am concerned, this looks good.

Would you like me to merge?

@szarykott
Copy link
Contributor Author

Yes @matthiasbeyer I'd like you to merge, I only need to resolve conficts.

@szarykott
Copy link
Contributor Author

@matthiasbeyer merge when you want. I rebased my code on master and added one commit which modifies env.rs file in similar way that previous code did to other tests files (use builder in main tests and keep old tests in legacy_tests).

@matthiasbeyer matthiasbeyer merged commit 266f504 into mehcode:master May 8, 2021
@matthiasbeyer
Copy link
Collaborator

Awesome. I really love the progress in this crate lately and the many people contributing! Thank you!

@szarykott szarykott deleted the builder branch July 31, 2021 20:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants