Minor tweaks to allow to programmatically configure providers. - #170
Conversation
Basically, made one method public instead of internal plus protection against null ref in a couple of places.
|
2 different way to solve the same problem. I picked that way. Why does it matter? |
|
Just an easier way. And less code. And more readable (if you care about readers) :) |
|
Logically, the configuration may have children and may not to. So from that perspective I find it cleaner to specify "I don't have children" via null value vs. empty array. There is also an issue of efficiency - redundant memory allocation. We had that discussion in the past: #18. And of course it is an internal implementation detail (the field is private) so the efficiency may be more important than a more intuitive API. |
|
But how does it affect efficiency? It's done only once on startup and then discarded. It's a throw-away object. We're not talking about something like GrainReference.
Indeed. Empty list means there no children. Iteration will stop at that point since there nothing to iterate.
Nope. You're doing an OSS, and you want ppl to contribute, so you should care about them reading your code. The code is written once but read many times. Anyone can write programs for computer but writing them for ppl is something that need to be mastered. P.S. Not for this case, but the general observation is: API has always more priority than anything else. You create it for other developers to consume. The success of your project depends on whether they will be satisfied with API and documentation/samples or not. It's something I learnt the hard way. P.P.S. Null checks all over the place are considered a code smell. Switch to eager initialization where possible and myriad of this ugly checks will go away. Abuse of lazy initialization is a plague of current Orleans' codebase. |
|
I think this is a good point. There are a handful of hot paths in the code where not allocating objects matters for performance. In most other places empty lists/dictionaries can be cleaner and easier to read. |
|
I understand that this is minor issue and we can forget about any good programming practices, for sure. So you can forget about that, I'm too tired today to fight around such a crumb. It's still doesn't fix the big picture around programmatic configuration of Boostrappers, anyway :) Maybe, I'll find some time to make an API close to: config.Global.RegisterBoostrapper<ServiceLocatorBootstrapper>();If I won't sink in a sea of |
|
Sorry, guys, If I offended in you some way. It's 3AM here and that last whiskey glass was extra :) |
I actually think it does. |
|
@yevhen No, you did not offend anybody. You brought a valid and important point. Thank you for that! |
…ation Minor tweaks to allow to programmatically configure providers.
|
@gabikliot I didn't say it doesn't work. It does. But it's still cumbersome. With your change, I can now skip part related to setting What's still left is this: void RegisterBootstrapProviders(params[] Type bootstrapProviders)
{
var category = Configuration.Globals.ProviderConfigurations.Find("Bootstrap");
if (category == null)
{
category = new ProviderCategoryConfiguration
{
Name = "Bootstrap",
Providers = new Dictionary<string, IProviderConfiguration>()
};
Configuration.Globals.ProviderConfigurations.Add("Bootstrap", category);
}
foreach (var bootstrapProvider in bootstrapProviders)
Register(bootstrapProvider, category);
}
public void Register(Type bootstrapProvider, ProviderCategoryConfiguration category)
{
var fullName = bootstrapProvider.FullName;
var config = new ProviderConfiguration(properties, fullName, fullName);
category.Providers.Add(config.Name, config);
}So, how on Earth, should an end-user (developer) know, without diving into Orelans sources, that in order to register bootstrap provider, he need to:
I can continue with this list, believe me (I started my carrier 15 years ago as QA engineer :), but I hope you get the point. There is too much (magic) code involved for such a casual task as registering bootstrap provider, which in my opinion is a crucial element of the framework. Would you put all of these steps into documentation of the The fact that you've generalized all kinds of providers is an inner detail. It should not be visible to clients. You used a code compression technique, which has it's cost, such as clarity. It's ok to use such generalizations but when its visible in public API it looks really weird :) That's why I wrote, that such an important element as config.Global.RegisterBoostrapper<ServiceLocatorBootstrapper>();All of that burden could be hidden behind that simple Facade method. |
|
Such a façade could indeed be a useful enhancement. It will make a programmatic configuration of bootstrap providers easier. It would be great to see your PR in that area. |
|
I realise I'm late, perhaps this adds something to the conversation:
There's a thread in SO that has more discussion around this. I suspect many of the seasoned .NET developers expect most of the guidelines should be followed and these issues weigh considerably when tools are chosen, at least in the projects I've been involded in (sometimes, oftentimes, nobody seems to care, but that tend to show in results too). Nevertheless, this was a good discussion on the pros and cons in this situation. I wonder if we should add some notes to contributor guidelines? |
|
Thank you @veikkoeeva for the useful links! |
|
@gabikliot Yep. I didn't see contributor policies written, but one possible formulation I see is that on public surface following the Framework Design Guidelines is preferred. I would put it so that it's preferred internally too, but it's OK to do otherwise too when reasons arise. What comes to me, I'd be OK someone just commenting to the code "we'll use null to optimize storage, performance etc. and this code isn't expected to change and these shouldn't leak outside", or something similar. As I would see it, it would lower the barrier for random people to do actual refactoring, however small the improvements would be, and be assured even small contributions could make it to the codebase (work won't go in vain, all work is good work and worth doing). Good for cleaning up code rot and technical debt, I think. Perhaps, when there's a chat and wider discussion with random people (like me), it'd provide a starting point to argument for and against with stable basis. |
|
Yes, I agree. |
Basically, made one method public instead of internal plus protection against null ref in a couple of places.