|
Hi Eddy Vluggen,
thanks a lot for the clarification.
There is just one thing that I maybe missexplained:
Eddy Vluggen wrote: They don't need to know. Windows knows what culture the user is using, and both
can "ask" Windows.
This is totally correct, but I was actually referring to the language the customer wants the application to run with.
I do not know wether they want a dutch, german, english or whatever language, neither does the plugin developer know, so it has to be possible to adjust it after deployment.
Anyway, this doen't make an actual difference
Eddy Vluggen wrote: You could opt to put the shared resources in an external library, and share that
among the projects. That way you'd need to localize the resources only once.
I like this idea and honestly I already use such an approach for sharing image resources over multiple projects.
Thanks Eddy for sharing your ideas/knowledge, I appreciate this very much!!!
Have a great day and best regards
Andy
|
|
|
|
|
You're welcome
Bastard Programmer from Hell
|
|
|
|
|
I did the localization for our applications some 2 years ago. Texts shown on forms/lables/buttons were the minor point. We do have far more messages shown in MessageBoxes (or other strings changed at runtime), and it was a long work to find them all in the source code.
I created my own tools for reading the source code line by line, looking for literal strings, display them, manually decide whether the string has to be localized or not (e.g. our logging is not localized - that would be too much extra work), and replace it with an appropriate call to the ResourceManager and adding the string to the appropriate resource file.
And yes, the OK button's text shows up perhaps a hundred times in the resource files...
If I remember correctly, with (non-managed) C++ it was possible to use Windows resources for such common texts like "OK" "Cancel" "File" "Edit" etc. But I do not know how to do that with .Net.
By the way, I added an entry to the app.config file such that the user can decide to use a different locale than Windows. Here in Germany, some of our customers use an English Windows on their servers, and with that little trick our applications can be set to German.
And another point to consider: a new thread inherits the language from Windows, not from the process which started the thread. The language must be set here again.
The .Net resource files can be used by specialized translation offices. Their tools discover such multiple entries like the "OK". Their prices here in Germany are typically about 1 Euro per entry for most Western languages.
|
|
|
|
|
Hi Bernhard,
thanks a lot for sharing your experiences., it was very helpful.
Good you mentioned the threadding issue, that completely fell under the table
In my application the language is set when logging in by selecting the required language. The language is then stored as readonly in a static class, pretty much the same as using a config file.
I also haven't heared about the translation offices you have mentioned. While I am pretty sure our management will use internal resources for translating this is still a good thing to know
Thanks a lot and have a great day,
Viele Grüße aus München
Andy
|
|
|
|
|
Lately I have begun to question how far an application should go to allow users to address possible errors? This may be answering my own question but it dawned on me while writing that it comes down to, at what point does the error checking and correction begin to affect application build costs and performance.
What do others think?
|
|
|
|
|
Troy.compdr wrote: how far an application should go to allow users to address possible errors?
Depends on what the application does.
Troy.compdr wrote: at what point does the error checking and correction begin to affect
application build costs and performance.
I have never seen a user (human) application where validation impacted performance. At least not where it wasn't traced to some basic misuse of something (perhaps overuse and incorrect use of regexes.)
Presumably by "build costs" you mean development cost. Since most places don't rigorously track costs I doubt there is an objective answer to that. However I have seen complex error scenarios be deferred because they would take too much development time. Not sure that the extreme cases matter anyways because they often reflect possible rather than likely user errors.
|
|
|
|
|
In my experience input validation and logging reduce development time and cost, and maintenance time and cost. Error correction, retries, best guesses, and the like, are tricky ones; when provided, make sure you have an easy way to disable them, otherwise your basic (or unit) testing may become very cumbersome.
|
|
|
|
|
See my thoughts regarding the issue here[^]
"You get that on the big jobs."
|
|
|
|
|
|
What is your way of dealing with a composition in a class?
Will you force the user to pass the required values to the contained objects?
Or you'll let the user set the contained object anytime later and check for it's validity everywhere?
For example,
class Rocket
{
Booster b1;
Rocket(Boostertype bt, BoosterPower bp)
{
b1 = new Booster(bt,bp);
}
Launch()
{
b1.fire();
}
}
Or it could be done this way
class Rocket
{
Booster b1;
Rocket()
{
}
initBooster(Boostertype bt, BoosterPower bp)
{
b1 = new Booster(bt,bp);
}
Launch()
{
if(null!=b1)
{
if(b1.bp >100)
{
}
}
}
}
My preferred way is to enforce Rocket's constructor with params required for booster as well.
Unless we pass a sensible value for the booster, rocket creation will fail.
But my mate here seem to differ with my opinion. He doesn't want Rocket's creation to be disturbed by booster constructors parameters.
Instead, when a Launch() is called , it should throw an exception saying Booster is not initialized/configured.
Which one would you prefer?
Starting to think people post kid pics in their profiles because that was the last time they were cute - Jeremy.
|
|
|
|
|
It depends on how you want to interact with the composite member.
I will often use an interface for the composite member that forces certain behavior on the parent.
To continue with your example. Can a rocket exist without the booster? Yes, then it does not belong in the constructor; no, then it must be initialised.
I would have:
interface BoosterInterface {
Booster getBooster();
Boostertype getBoosterType();
Boostertype getBoosterPower();
void initBooster(Boostertype bt, BoosterPower bp);
void setBooster(Booster bl);
void setBoosterType(Boostertype bt);
void setBoosterPower(BoosterPower bp);
}
class Rocket
impliments BoosterInterface {
}
Having the interface means that you can of course force behaviour to the containing class.
My two pennies worth.
Panic, Chaos, Destruction. My work here is done.
Drink. Get drunk. Fall over - P O'H
OK, I will win to day or my name isn't Ethel Crudacre! - DD Ethel Crudacre
I cannot live by bread alone. Bacon and ketchup are needed as well. - Trollslayer
Have a bit more patience with newbies. Of course some of them act dumb - they're often *students*, for heaven's sake - Terry Pratchett
|
|
|
|
|
Makes sense.
Starting to think people post kid pics in their profiles because that was the last time they were cute - Jeremy.
|
|
|
|
|
It's an interesting one to say the least. One of the principals of OO development is that you shouldn't return an object out of a constructor that requires further configuration to be useful*. In other words, you shouldn't need to set additional properties before the class is useful. In this particular case, the fact that you can get to the Launch code without setting it, and the first point that you notice that there's a failure is at this point would indicate that the Booster should have been applied earlier on.
*Now, looking at your sample, it would seem that what you are looking at here is an object that would typically be composed using Dependency Injection, so it would be reasonable to assume that the DI code would actually compose your object for you. This would mean that you would be exposing a dependency that your code was reliant on - and this is where it gets slightly murkier. If you favour the wide constructor approach to composition, then every time you need to add an extra dependency to your class, you have to add it to your constructor, and add a backing field for that type. You may prefer the dependency property (I'm not using this in the WPF way here) approach, which means that you would expose a property for it - and this could be an auto property so you wouldn't need to add the field yourself as the compiler takes care of this for you behind the scenes.
|
|
|
|
|
Using the analogy of the rocket, you can still perform a lot of actions - giro tests, etc - without a booster. The booster is an added item, not necessarily an intrinsic part. If the rocket must have a booster, then I agree it must be a part of the constructor to ensure its presence.
Panic, Chaos, Destruction. My work here is done.
Drink. Get drunk. Fall over - P O'H
OK, I will win to day or my name isn't Ethel Crudacre! - DD Ethel Crudacre
I cannot live by bread alone. Bacon and ketchup are needed as well. - Trollslayer
Have a bit more patience with newbies. Of course some of them act dumb - they're often *students*, for heaven's sake - Terry Pratchett
|
|
|
|
|
Nagy Vilmos wrote: If the rocket must have a booster, then I agree it must be a part of the
constructor to ensure its presence.
And that's the rub. What constitues a valid instance of the class? In the admittedly contrived example given, the only operation that could be performed was a Launch, so the booster is an intrinsic part of this particular example.
Now, if this class were one I was designing, I would take a slightly different approach if this was a full lifecycle of a rocket. This particular rocket implementation is tightly coupled to a single booster. What happens if I want a rocket with more than one booster? Or I want to use one that's based on the ACME Fusion Drive 3000 elastic band? To that end, I'd consider that a design like this might be better:
public class Rocket
{
public Rocket()
{
}
public void PreLaunchTests()
{
OnPreLaunchTests();
}
public void Launch()
{
}
protected virtual void OnPreLaunchTests()
{
}
protected virtual void OnLaunch()
{
}
}
public class SingleBoosterRocket : Rocket
{
public List<IBooster> Boosters { get; private set; }
public SingleBoosterRocket()
{
Boosters = new List<IBooster>();
}
public void AddBooster(IBooster booster)
{
Boosters.Add(booster);
}
protected override void OnPreLaunchTests()
{
}
protected override void OnLaunch()
{
if (Boosters.Count == 0)
throw new NotEnoughBoostersException();
}
}
public class DualBoosterRocket : SingleBoosterRocket
{
public DualBoosterRocket() : base()
{
}
protected override void OnPreLaunchTests()
{
}
protected override void OnLaunch()
{
if (Boosters.Count < 2)
throw new NotEnoughBoostersException();
}
} Again, this is a completely fabricated design, but this has the advantage of being more flexible. Ultimately, the design should be based on the real requirements, which is why I have steered well clear of saying that one approach is better than another in all cases. BTW - in case you're wondering, the actual composition in this sample has been moved to the containing object, rather than the actual rocket implementation, as that piece of code would be the one that decided what the composition entailed. The rules for the rocket have been encapsulated in a simple classes that have a single responsibility.
|
|
|
|
|
Thanks for the example Pete
Starting to think people post kid pics in their profiles because that was the last time they were cute - Jeremy.
|
|
|
|
|
|
As Pete says, a constructor should always return a valid object, that is, you should be able to use it in normal situations. So the answer to the question depends on whether a Rocket can be useful without a Booster. In your simplistic example, where it has one method and that method throws an exception if it isn't set, it clearly can't, and therefore the Booster should be assigned in the constructor (and, if applicable, a null check applied there).
|
|
|
|
|
Neither. Rocket should be able to call a factory method "Boosters.GetBooster()", or some other suitable mechanism to acquire what it needs, when it needs it.
Marc
|
|
|
|
|
Funnily enough, that was the gist of the answer that I've just added above.
|
|
|
|
|
Pete O'Hanlon wrote: Funnily enough, that was the gist of the answer that I've just added above.
I read it, but your response was too wordy for me to figure out what you were saying! But none-the-less, two great minds, a single thought between them, eh?
Dependency Injection, hmmm... it's really weird to me how we have these (what I consider to be) massive frameworks to support DI when all it really needs is a simple instantiation engine.
Anyways, I'm getting distracted by the lure of an unoccupied soapbox.
Marc
|
|
|
|
|
We internally have a DI engine that is only 60 lines or so of code, and it's good enough for our purposes when all we need is basic DI.
|
|
|
|
|
Pete O'Hanlon wrote: We internally have a DI engine that is only 60 lines or so of code
Sweet!
Marc
|
|
|
|
|
I think we can think about two scenarios:
1. First, On the ground, we "build" the rocket with boosters and make a launch.
2. We don't build or assemble a rocket, but when a launch is called, it acquires a booster and executes a launch.
The second one is loosely tied.
The Boosters.GetBooster() can be applied for both the scenarios?
Starting to think people post kid pics in their profiles because that was the last time they were cute - Jeremy.
|
|
|
|
|
VuNic wrote: The Boosters.GetBooster() can be applied for both the scenarios?
I think so. In the first scenario, the constructor can call GetBooster to get a concrete instance, though I think it would be much more preferable for Rocket to have a Build() method.
In the second scenario, and this may be over the top, consider that we know that a rocket, among other things, has some form of propulsion mechanism, otherwise it wouldn't be a rocket. Now, a rocket might have a main engine, boosters, stages, ion engines, so forth, a whole slew of combinations of things. So if rocket is to have a "has a" relationship to booster, the concept of booster needs to be abstracted to "propulsion systems", ideally a collection of this abstraction type. The GetBooster factory might return a collection specific to the rocket's requirements. You can define specific collections as a concrete type (there's most likely a limited, well defined set of configurations). Each type (the configuration of propulsion systems) probably has specific launch behaviors. Therefore, the type itself contains all the logic for how to proceed with a launch, going from main engine firing, booster firing, stages, and final orbit maneuverings with ion engines. So, why should the rocket itself know how to do this? The rocket is just a container for a particular configuration. Maybe the rocket performs some coordination with other systems, but the execution of the launch should be delegated to the configuration type.
Which is where functional programming can be used, not only for "computing" the launch, but also for ensuring that configurations, using discriminated unions, are permitted.
Marc
|
|
|
|
|