-
Notifications
You must be signed in to change notification settings - Fork 967
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
Discuss: Global Config design #508
Comments
I vote for a global config file. I think more flexibility is good thing. |
Maybe this goes completely against the design of Humanizer, but I'd vote for neither one: don't use static, or configuration, but keep the flexibility with overloads, or constructors when instantiating types. Why? Although there are other NuGet packages that use static methods, and properties to configure it (like AutoMapper), for me it feels like an old-school approach of providing an API for you as a developer: since they can be accessed from anywhere, they also behave as globals (you never know when, and how things are configured). My experience with that is that it gives a lot of headaches. These days, dependency injection is becoming the defacto standard, and there are good ways of making things global in that, if you need that when you want to set something global. The same applies to configuration, that doesn't belong in something like a class library like Humanizer. |
The current design of the API is based upon extension methods, those are static. IMHO we should drop the current support for configuration. We in generally already take this route, let's take it to the end. |
I agree with @mexx. As I understand actions needed to be performed are:
|
👍 |
The reason I added the static configurator was to allow global configuration without enforcing devs to have to pass the config in every single method. Optional defaults work as long as you want the default value otherwise you will have to pass your override to all method calls. I am also not a big fan of methods with long argument lists which typically happens with a lot of optional params (Perhaps we could pass configurator options/hashes to methods to avoid an ever-growing API surface). All that said, I agree with the pain of shared static state. |
I also not a fan of methods with lots of parameters or overloads.
With this in place, we can now write
or the currently present method would look like that
Thoughts? |
The configurator in |
I really like the idea of separate configuration classes that contain the configuration options. Although @MehdiK's suggestion looks not that bad, I think introducing a lambda to configure an instance is not the most user-friendly way to go. |
In both cases there is a need for an instance to hold the configuration options. In @MehdiK's suggestion this object is created inside the method and passed out to allow customization, in my case the object is created outside. I would go even further and say, the parameter should be an interface. That way we can decouple the implementation even more, as a potential user could provide a complete own implementation of the configuration options, which delivers different results in dependency of a context. Thoughts? |
An interface would provide decoupling, but at the expense of users not being able to discover easily which class to create that implements that interface. |
Right, maybe a good naming convention can help? |
That certainly would help. But when would you imagine someone creating their own configuration options class? |
As I said, when the configuration should depend on some state. I could implement the needed interfaces to hide the access to this state in the implementation. Currently to support this scenario you would have to provide a factory for the configuration to the methods that call Humanizer. Further I have one more point why interfaces are a better fit. Some code example:
The casts aren't necessary, I've included them for clarification of my intent. |
That is true. I understand what you're going for now. Looks fine. |
We can hide this under the system interface IFormatProvider, probably
|
@hazzik Could you elaborate more on how |
@mexx forget, we can not. I was thinking that we can implement custom |
Global-only configuration is a huge pain point for me. I didn't see this explicitly mentioned, but the way I see this could work is that locally provided config takes precedence over global. That way one can set global defaults and override those where necessary. Pseduo-code: Configurator.DateTimeConfiguration = ...;
var now = DateTime.Now;
var useGlobal = now.Humanize();
var useLocal = now.Humanize(new DateTimeConfiguration(...)); The actual API could expose the one method with a default: public static string Humanize(this DateTime @this, DateTimeConfiguration configuration = null)
{
configuration = configuration ?? Configurator.DateTimeConfiguration;
} |
@kentcb Thanks for this input, also the overloads with the additional parameters can utilize this technique. We wouldn't even break the current state of the configuration, at least it's my hope. What is beneficial to projects those are happy with the global configuration approach. |
Today Humanizer uses a few static configuration options to control formatting/output behavior of some of its methods.
Aside from this design making it harder to run unit tests in parallel, it does place certain restrictions on the library usage - namely that you couldn't have different options depending on the context as they're static.
This may or may not be a real issue but I wanted to start a discussion around it here.
Thoughts?
The text was updated successfully, but these errors were encountered: