Design Questions about static factory classes

T

Tom Anderson

It depends on the context.

For many internal systems then nightly downtime is still
acceptable.

But the world has become global. It is always work hours
somewhere on the planet.

Public internet systems like Google and FaceBook does
not close a couple of hours every day.

Huge multinational corporations with offices in almost
all timezones can not shutdown business critical system
a couple of hours every day.

Nightly downtime still exists but it is definitely
out of fashion today.

Many business system still have weekly/monthly
scheduled downtime though.

But Google/FaceBook types does not even have that.

We're no Google, and we will have downtime when we do need to update the
code. But pushing new content may well be happening on a daily basis, and
we don't want daily maintenance outages.

Mind you, if you have a cluster of app servers, you can update the code on
a machine-by-machine basis without ever taking the whole cluster down.
Provided you don't change the interface between machines, that is. I
anticipate that we'd be able to do this, althoug whether it'll be
considered worth setting up to avoid a few minutes of downtime, i don't
know.

tom
 
T

Tom Anderson

But when it is user input, then it is really not that exceptional
with format errors.

If it was reading a file that was generated by a system, then I
would consider a format error exceptional.

Even for unexceptional stuff an exception can be practical to
roll back the call stack, but if that is not the case either,
then I don't consider exception attractive.

A very good example is that .NET in 1.1->2.0 supplemented
the int.Parse method with a new int.TryParse method - today
the later is used in >90% of all cases.

Shocking.

tom
 
A

Arne Vajhøj

Arne said:
Bad user input is not really exceptional enough to justify an
exception.

Tom said:
I disagree. We've had arguments about the proper use of exceptions on
this newsgroup before, so i [sic] recognise that this is a matter where
opinions vary, but exceptions seem like a perfectly acceptable option
for dealing with bad user input to me. They might not be the right
solution in every situation, but they are an option that can be
considered.

And usually rejected.

Read /Effective Java/ (2nd ed.), "Item 57: Use exceptions only for
exceptional conditions", and the rest of section 9.

No.

It is always good to read opinions from qualified people even
if you disagree with them.
True. I wouldn't worry about that in input validation code of this kind
unless i had a profiler screaming at me that it was a problem.

Hmm. Do profilers track the amount of time the JVM spends handling
exceptions?

If it is interactive user input then the overhead of exceptions
will be unmeasurable due the ratio between CPU speed and human
typing speed.

I don't think performance is the best argument against exceptions
for bad user input.
I don't agree that bad input is not an exceptional condition; i wonder
if you are confusing 'exceptional' and 'unlikely' or 'unexpected'. I
agree that validating input must be done inline, but not that dealing
with invalid input must be. I'd say exactly the opposite, in fact.

You are free to have your opinion - just note that a lot
of people disagree today.

Arne
 
T

Tom Anderson

Arne Vajh?j wrote:
Bad user input is not really exceptional enough to justify an
exception.

Tom Anderson wrote:
I disagree. We've had arguments about the proper use of exceptions on
this newsgroup before, so i [sic] recognise that this is a matter where
opinions vary, but exceptions seem like a perfectly acceptable option
for dealing with bad user input to me. They might not be the right
solution in every situation, but they are an option that can be
considered.

And usually rejected.

Read /Effective Java/ (2nd ed.), "Item 57: Use exceptions only for
exceptional conditions", and the rest of section 9.

No.

It is always good to read opinions from qualified people even
if you disagree with them.

True. But i don't have that book, and i'm not about to rush out and buy it
because it contains advice i disagree with! If i come across a copy of it
(i might be able to borrow one from the tribe upstairs at some point), i
will certainly read this.
If it is interactive user input then the overhead of exceptions
will be unmeasurable due the ratio between CPU speed and human
typing speed.

I don't think performance is the best argument against exceptions
for bad user input.

Needless to say!
You are free to have your opinion - just note that a lot
of people disagree today.

I certainly recognise that. And am used to it :).

tom
 
R

Rhino

In most cases I don't think the exception text would
tell the end user anything.

Let us say that you have developed an accounting program and
the code throws an exception telling that it could not
load the JDBC driver.

No point in telling an accountant that. He don't know what
JDBC is.

You tell the accountant that there were a configuration error
and that he should contact his IT department.

You write in the log file what the problem is and when IT
support look at the log file, then they know what the
problem is.

Of course there are cases where the message text from the
exception can be used in the end user error text. Just don't
display class names, stack traces etc..
I completely agree with your argument in this scenario.

I was thinking more of cases where user input is faulty and could be
corrected by the user. For instance, I have a little GUI-based "color
converter" class: it has an input field where I type the hex
representation of a Color, e.g. FFCC00, and it gives me the RGB
representation, e.g. 25, 204, 0, in another field when I click on the
Convert button. Now, if the user mistypes the hex reprsentation of the
color, say FFCCZZ, the method that does the conversion detects that ZZ is
not a valid hex representation of the Blue component of a Color, throws
an IllegalArgumentExpection with text to that effect (the message is
retrieved from a ResourceBundle to allow for internationalization) and
then the try/catch block in the ColorConverter class displays that
message in a JOptionPane so that the user knows what to fix.

I don't log any of this and certainly don't show the user anything like a
stacktrace; just the message from the ResourceBundle.

That's a reasonable approach, isn't it?
 
R

Rhino

In the course of developing test cases for some of my classes,
particularly  the classes that are static factories, I've developed some
confusion about localization. Basically, I'm trying to figure out when I
want to have separate constructor and getInstance() methods

First, I hope we can all agree that, in an ideal world, every class which
can produce text output - even if no text is produced per se, most
classed would be capable of producing error messages for Exceptions -
should be written so that it can produce that output in the languages of
the users of those classes. So, if your utility classes are used in
French-speaking countries, text output and/or error messages will be in
French and so forth for other languages. Now, I know that many developers
will not worry about that - after all, the whole IT field seems to be
fairly English-centric - but I aspire to make all of _my_ classes locale-
sensitive.

Now, with the preamble out of the way, let's get down to brass tacks.

Let's say that I want to make a static factory class locale-sensitive but
I don't want to force the user to choose an explicit locale every time
they try to use the class. That suggests to me that I go one of two ways:

1. Provide two private constructors - one that takes a specified locale
and one that uses the default locale - and two corresponding public
getInstance() methods, one of which takes a specified locale and one that
uses the default locale. Then, if the user is comfortable with the
default locale, they use the constructor that doesn't have a locale
parameter, otherwise, they use the constructor that has a locale
parameter and specify the locale of their choice.

2. Provide a single private constructor that has no locale parameter and
a corresponding public getInstance() method. Also provide getLocale() and
setLocale() methods so that a user can instantiate with the single
getInstance() method and then use setLocale() to alter that locale if it
is not to his liking.

I thought I'd have a look at the Java API and see what happens there. I
got something of a mixed bag. A handful of classes have getInstance()
methods that take a Locale parameter, suggesting that they favour
Approach 1. A handful of classes have setLocale() methods, suggesting
that they favour Approach 2. However, the vast, vast majority of the
classes have neither suggesting that they are NOT locale-sensitive and
have no capability for changing the Locale at all.  

So I thought I'd ask the learned people on this group for their thoughts
on which approach they'd take when building classes that are meant to be
locale-sensitive. I'm sure there are variations on the two approaches
I've enumerated so I'm open to "none of the above" answers :)

Personally, I'm leaning towards Approach 2. Approach 1 requires doubling
up of constructors and getInstance() methods and makes you reinstantiate
the class if you want to change Locales. Approach 2 avoids those extra
constructors and getInstance() methods and lets you change Locale by
simply doing setLocale(). There may be negative aspects to that which
aren't occuring to me though so I hope you will point those out if you
see them.

I've learned a lot in this thread about different aspects of i18n/l10n
(internationalization/localization) and I still expect to learn a bit
more as people respond to my scenario about my little Color Converter
program.... I thank you all for supplying considerations I hadn't
thought of in the design decisions that go with i18n/l10n.

But I'd like to try to sum up a bit now. The conversation has gotten
sufficiently fragmented that I'm not sure what we would all agree on
with regards to the situation I am trying to resolve.

In a nutshell, I have some utility-type classes and I am trying to
figure out how they should best handle matters of Locale.

Notice that I said "utility-TYPE classes". I initially described these
as static factory classes but I'm no longer sure that they should be.

Until a few months ago, all of the methods in these classes were
static and there was no constructor for the class. I had some concerns
and asked about them on a thread here. I don't recall how to give a
URL for a Google Groups discussion so I apologize for not being able
to give you one but it was a discussion that started March 15 2010 and
was entitled "Design Question". In a nutshell, because I had a Locale
variable in the class, this was seen as an element of 'state" for the
class and therefore I was advised to change the class so that it had a
private constructor and a public static getInstance() method. I did
that and, in fact, had two of each: a constructor that took no
parameters and one that took Locale as the parameter, and
corresponding getInstance() methods. I understand why the 'state'
necessitated this kind of change now that I've reread that thread.

However, I find myself seriously doubting that Locale SHOULD be a
class variable after all. And if my reasoning is sound, which I hope
you will tell me, I may be able to go back to having all the methods
be static.

As I look at the classes in the Java API, only a tiny handful of them
have constructors that take a Locale as an argument and only a tiny
handful have setLocale methods. Assuming that the Java API is
considered well-designed by the Java community - and I have to hope it
is :) - that tells me that the remaining 99.9% of classes are
expecting to provide any locale-specific information in only ONE
Locale. Furthermore, no class invoking the API is typically going to
want to get the information in more than one language at a go.
Essentially, the classes operate on the basis of the Locale defined by
the user.country and user.language properties. Therefore, if my
properties are set to English and Canada, that is the locale that the
JVM is going to try to find - of course it will settle for other
flavours of English if there is no specific en_CA resource bundle -
and use for any other locale-specific text. (DateFormats,
NumberFormats, and their kin handle the localization needs of those
special kinds of data.)

Providing a way to set a specific Locale and even to change that
Locale on the fly so that classes could potentially invoke the class
repeatedly for different Locales is simply overbuilding and is almost
certainly not necessary at all! (I say 'almost' in deference to Lew's
observations about there being no hard and fast rules, which makes a
lot of sense to me.) So I think I can dispose of Locale in
constructors (and their associated getInstance() methods altogether.
Likewise, I can omit and setLocale() and/or getLocale() methods from
my utility classes too. Methods that seek to get ResourceBundles will
simply seek them for the default Locale, as determined via
Locale.getDefault().

Does this all make sense so far? I sure hope it does because I think
I've got myself convinced :)

The classes will still be fully locale-sensitive; I've proven that by
simply changing user.language and user.country to other values and
information comes out in the desired language just fine. (My
writeLocales() methods writes the display names of the Locales in the
language of the default locale so if my default Locale is en_CA, I get
them in English but if it is de_DE, I them in German, etc.)

As someone interested in the issue of supporting different languages
in a syste, I did some dabbling with the i18n stuff shortly after it
came out. I wrote simple apps that would display a list of locales and
let the user choose their favourite, then go back to the menu and
change them on so that information would be redisplayed in the
replacement Locale. I got in the habit of putting that kind of code in
many of my classes on the theory that I was making them more flexible
but I had never really given a lot of thought to how realistic this
was or how it conformed with the far better designed Java API. Now I
see that it is just unneeded frippery. If a class's methods really do
need to be able to change Locales on the fly, I think I'll be able to
write the code to enable that. But those needs should be few and far
between. For now, I think I should abandon any efforts to have
"dynamic locale switching" (for want of a better term) in my classes.

Am I on the right track here? Or am I throwing out the baby with the
bathwater?

Once we are agreed on that, I would like to follow up with a few
specific detailed questions but I'd like to get the fundamental
principle resolved first.
 
L

Lew

Rhino said:
I was thinking more of cases where user input is faulty and could be
corrected by the user. For instance, I have a little GUI-based "color
converter" class: it has an input field where I type the hex
representation of a Color, e.g. FFCC00, and it gives me the RGB
representation, e.g. 25, 204, 0, in another field when I click on the
Convert button. Now, if the user mistypes the hex reprsentation of the
color, say FFCCZZ, the method that does the conversion detects that ZZ is
not a valid hex representation of the Blue component of a Color, throws
an IllegalArgumentExpection with text to that effect (the message is
retrieved from a ResourceBundle to allow for internationalization) and
then the try/catch block in the ColorConverter class displays that
message in a JOptionPane so that the user knows what to fix.

I don't log any of this and certainly don't show the user anything like a
stacktrace; just the message from the ResourceBundle.

I recommend against popping a dialog or other window in a try/catch block.

Try/catch is for getting out of a mess. If there's a lot of code in there,
you risk getting in another mess.

You also don't separate concerns enough, in this case the "happy-path" logic
from the error-message logic.

Plus, your validation is likely, or should be likely to be off the Event
Dispatch Thread (EDT), since validation isn't really a graphic action but a
logical one. That involves thread coordination from inside a try/catch, not
so good.

Let the catch block cause a return from the validator, and let the caller of
the validator decide where to go next.
 
A

Arne Vajhøj

But I'd like to try to sum up a bit now. The conversation has gotten
sufficiently fragmented that I'm not sure what we would all agree on
with regards to the situation I am trying to resolve.
However, I find myself seriously doubting that Locale SHOULD be a
class variable after all. And if my reasoning is sound, which I hope
you will tell me, I may be able to go back to having all the methods
be static.

As I look at the classes in the Java API, only a tiny handful of them
have constructors that take a Locale as an argument and only a tiny
handful have setLocale methods. Assuming that the Java API is
considered well-designed by the Java community - and I have to hope it
is :) - that tells me that the remaining 99.9% of classes are
expecting to provide any locale-specific information in only ONE
Locale.

Note that the Java API is a low level API and localization is
most relevant for higher level business app code.

The huge majority of Java API classes does not have any
need for localization at all.

Furthermore, no class invoking the API is typically going to
want to get the information in more than one language at a go.
Essentially, the classes operate on the basis of the Locale defined by
the user.country and user.language properties. Therefore, if my
properties are set to English and Canada, that is the locale that the
JVM is going to try to find - of course it will settle for other
flavours of English if there is no specific en_CA resource bundle -
and use for any other locale-specific text. (DateFormats,
NumberFormats, and their kin handle the localization needs of those
special kinds of data.)

Providing a way to set a specific Locale and even to change that
Locale on the fly so that classes could potentially invoke the class
repeatedly for different Locales is simply overbuilding and is almost
certainly not necessary at all! (I say 'almost' in deference to Lew's
observations about there being no hard and fast rules, which makes a
lot of sense to me.) So I think I can dispose of Locale in
constructors (and their associated getInstance() methods altogether.
Likewise, I can omit and setLocale() and/or getLocale() methods from
my utility classes too. Methods that seek to get ResourceBundles will
simply seek them for the default Locale, as determined via
Locale.getDefault().

That strategy may work OK for fat client apps. It will not work
well for the server side code in web apps.

Arne
 
A

Arne Vajhøj

True. But i don't have that book, and i'm not about to rush out and buy
it because it contains advice i disagree with! If i come across a copy
of it (i might be able to borrow one from the tribe upstairs at some
point), i will certainly read this.

There are other good sections in the book as well.

Put it on your Christmas gift wish list!

Arne
 
A

Arne Vajhøj

Arne Vajhøj wrote:
...
...

Reading these two paragraphs, I think the difference between us is the
viewpoint we use in evaluating "exceptional". You seem to be using a
whole program viewpoint. I look at it much more locally.

Typically, in my code, a String conversion method has no idea whether
the String it is converting came from a GUI TextField, an input file
edited by a user, or a file that was generated automatically. Its design
cannot and should not depend on whether an inability to do the
conversion is due to an error in a user input or in a system generated
input.

Instead, I look at the issue from the point of view of the method I'm
defining. What is the primary function of this method? If its primary
job is conversion of a String to some other type of value, and it cannot
do it because of incorrect content in the String, it throws an exception.

Of course, somewhere in the call stack there is a method that does know
where the unconvertible String came from. If the condition is not
exceptional from its point of view, it should catch the exception and
take appropriate action.

That is a core problem of the domain logic exceptional criteria. If we
are in the low level API, then we don't have a clue about what is
exceptional.

I would say that from a purity perspective "unknown" would favor
return value over exception, because I like the "convert return
value to an exception at a higher level" a lot more than
the "convert exception to return value at a higher level".

But the practical perspective this situation would favor
exception, because the call stack is often deep and the
exception is simply an easy way to get out to where
it is needed.

Well - I guess there is a reason that programmers will not
be replaced by AI programs soon.

:)

Arne
 
A

Arne Vajhøj

I completely agree with your argument in this scenario.

I was thinking more of cases where user input is faulty and could be
corrected by the user. For instance, I have a little GUI-based "color
converter" class: it has an input field where I type the hex
representation of a Color, e.g. FFCC00, and it gives me the RGB
representation, e.g. 25, 204, 0, in another field when I click on the
Convert button. Now, if the user mistypes the hex reprsentation of the
color, say FFCCZZ, the method that does the conversion detects that ZZ is
not a valid hex representation of the Blue component of a Color, throws
an IllegalArgumentExpection with text to that effect (the message is
retrieved from a ResourceBundle to allow for internationalization) and
then the try/catch block in the ColorConverter class displays that
message in a JOptionPane so that the user knows what to fix.

I don't log any of this and certainly don't show the user anything like a
stacktrace; just the message from the ResourceBundle.

That's a reasonable approach, isn't it?

It is an OK approach.

A possible alternative could be to throw a custom exception
NotHexColorStringException and let the exception handling
code read the localized text.

Arne
 
R

Rhino

Lew said:
I recommend against popping a dialog or other window in a try/catch
block.

Try/catch is for getting out of a mess. If there's a lot of code in
there, you risk getting in another mess.

You also don't separate concerns enough, in this case the "happy-path"
logic from the error-message logic.

Plus, your validation is likely, or should be likely to be off the
Event Dispatch Thread (EDT), since validation isn't really a graphic
action but a logical one. That involves thread coordination from
inside a try/catch, not so good.

Let the catch block cause a return from the validator, and let the
caller of the validator decide where to go next.

Can you point me to any examples that show input error handling done
right? I'm not following your proposal very clearly with just the English
description; I need to see some code.

Even though my code:
a) works
b) is very simple

it is apparently not what the doctor ordered and I need to rethink yet
another major aspect of my code....
 
R

Rhino

It is an OK approach.

A possible alternative could be to throw a custom exception
NotHexColorStringException and let the exception handling
code read the localized text.
Okay, I'll give that some thought.

But it sounds like you are saying that this is not the routine or best
way to handle input errors so maybe I need to imitate the better
approaches. If someone could point me to examples of good input error
handling, maybe I could finally see how I'm supposed to be doing it....
 
T

Tom Anderson

That is a core problem of the domain logic exceptional criteria. If we
are in the low level API, then we don't have a clue about what is
exceptional.

I would say that from a purity perspective "unknown" would favor return
value over exception, because I like the "convert return value to an
exception at a higher level" a lot more than the "convert exception to
return value at a higher level".

Ah, whereas i'm just the opposite. It's easy to lose a return value. It's
hard to lose an exception.

tom
 
D

David Lamb

Also, is there much need for systems in which the user can switch
languages on the fly?

Yes, if only for testing. You don't want to have to exit the program,
change locale, and re-run it to verify that your other-language text
comes out OK.
 
R

Rhino

Note that the Java API is a low level API and localization is
most relevant for higher level business app code.

The huge majority of Java API classes does not have any
need for localization at all.
Good point.


That strategy may work OK for fat client apps. It will not work
well for the server side code in web apps.

So where does it leave me with my utility classes? Some of the methods in
these classes are just convenience methods and others do smallish tasks
like counting the number of occurrences of a given character in a string.
It's certainly possible that some will get bad input and that they will
correspondingly need to handle them some way. Should I be giving users of
these classes the ability to specify a non-default locale and/or switch to
a different locale on the fly?

If not, I'm inclined to just let them work with the default locale and
retrofit additional constructors and/or getLocale()/setLocale() later if
the need arises....
 
A

Arne Vajhøj

Okay, I'll give that some thought.

But it sounds like you are saying that this is not the routine or best
way to handle input errors so maybe I need to imitate the better
approaches. If someone could point me to examples of good input error
handling, maybe I could finally see how I'm supposed to be doing it....

I am just reluctant to rely too much on the message of an Exception.

I prefer to rely on the type of the Exception.

Arne
 
A

Arne Vajhøj

I'm particularly dubious about this in connection with
internationalization, because in some cases logging should be in the
developers' working language, but GUI display in a language chosen by
the end user. The same Exception might trigger either or both.


Also remember that you can add your own fields to an Exception subclass.

I don't know whether this makes sense, but for a String conversion
exception it might be helpful to include the index in the String of the
first error. I'm not sure whether it would ever make sense to add an
enum for more detailed classification - one could always subclass instead.

SQLException has a getErrorCode.

But then the original design of only having SQLException class
was a rather big mistake. Which they tried to fix in 1.6.

Arne
 
J

Jim Janney

Mike Schilling said:
Lew said:
Arne said:
And my guess is that Tom [sic] meant US English.

Tom said:
Certainly not! en_GB is the canonical form, and en_US is merely a
popular but subordinate deviation.

It has ever amazed me how well the Brits speak English. Awesome!

Some of them even write it well, though rarely as well as the Irish.

"The Gibbelins eat, as is well known, nothing less good than man...."
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,191
Latest member
BuyKetoBeez

Latest Threads

Top