Interface design considerations

S

sasuke

Hi all.

I've been recently trying to design a small command line translator
application. I can come up with three possibilities as to the way in
which the interface which hides the translation magic behind the
scenes can be designed:

// The stateless verbose contract [SLVC]
public interface ITranslator {
String translate(String text, Locale fromLocale, Locale toLocale);
}

// The stateful minimalistic contract [SFMC]
public interface ITranslator {
String translate(String text);
}

// The stateful verbose contract [SFVC]
public interface ITranslator {
String translate(String text);

void setFromLocale(Locale fromLocale);

void setToLocale(Locale toLocale);
}

Here is my interpretation of the three:
- The SLVC places the responsibility of handling the locale
information on the calling class. The implementation class can be very
well implemented using the Singleton design pattern since no
additional information is required when translating text.
- The SFMC places the responsibility of handling locale information on
the implementation class. One of the ways in which this can be done is
make the implementation class provide setter or hook methods for
setting the locale information though any other approach for
retrieving the locale information can be used.
- The SFVC is a verbose version of SFMC which mandates the
implementation class provide hooks for setting the Locale information
i.e. mandates the implementation class be Stateful.

I'm personally leaning towards the first approach but would very much
like to hear what is the general thought process which goes behind
when designing interfaces in general. Comments and suggestions
appreciated.

../sasuke

P.S.: Pardon the silly categorization; I came up with those on a
whim. ;-)
 
M

markspace

sasuke said:
// The stateful minimalistic contract [SFMC]
public interface ITranslator {
String translate(String text);
}
- The SFMC places the responsibility of handling locale information on
the implementation class. One of the ways in which this can be done is
make the implementation class provide setter or hook methods for
setting the locale information though any other approach for
retrieving the locale information can be used.


This one also allows you to pass this object as a Strategy to other
objects, and those other objects don't know or care what the locales
are, or even that you use Locale or some other object. I'd kinda favor
it, unless your design seems to indicate one of the others would be
better. Being ignorant of implementation is often considered good design.
 
J

Joshua Cranmer

sasuke said:
- The SLVC places the responsibility of handling the locale
information on the calling class. The implementation class can be very
well implemented using the Singleton design pattern since no
additional information is required when translating text.

The contract will be burdensome if translation is very complex (e.g.,
the semantics for French->English translation are very different from
those of Japanese->English). It will also be burdensome if several
translation requests will be performed in sequence in the same locale.
- The SFMC places the responsibility of handling locale information on
the implementation class. One of the ways in which this can be done is
make the implementation class provide setter or hook methods for
setting the locale information though any other approach for
retrieving the locale information can be used.

I envision implementations of this methodology to either be able to
translate only one locale to another, or to have the class user to
manually supply the information at construction.
- The SFVC is a verbose version of SFMC which mandates the
implementation class provide hooks for setting the Locale information
i.e. mandates the implementation class be Stateful.

This is like the first one, except it has more shorthand, since it would
expect translation to be in "bursts" (i.e., translate would be called
with the same locales repeatedly).
I'm personally leaning towards the first approach but would very much
like to hear what is the general thought process which goes behind
when designing interfaces in general. Comments and suggestions
appreciated.

It depends. My gut reaction, in lieu of any other context, would be to
go more towards the second one (since I expect that translation would
mostly be between the same two locales and that it would be rather
specialized). The third one would be my second choice, and the first my
third.

The decision ultimately comes down to usage patterns and implementation
difficulty.
 
A

Arved Sandstrom

G

Giovanni Azua

Hi sasuke,

Please find my comments below:

sasuke said:
// The stateless verbose contract [SLVC]
public interface ITranslator {
String translate(String text, Locale fromLocale, Locale toLocale);
}
I would not prefer this alternative because of these reasons:

- I would say it is more usable for clients to set the "from" and "to" once
and call "translate" many times passing only the text e.g. Google Translate,
you set the from and to language once and then keep translating texts away
this is what I always do anyway German => English. Eventually you go back
and "swap" English => German maybe also to check the soundness of the
translation, a nice addition to your Stateful version maybe would be the
"swap" method. Therefore handing to clients an interface that has a method
"translate(String)" would be easier from the usability prospective e.g.
would cover nicely the use-case of configure once upon startup the from and
to and call many times the translate while also supporting the use-case of
changing the from and to continuously.

- In several papers I have read about SE and if I recall correctly most
metrics regarding number of input parameters for a method in average expect
this to be 1 or less meaning one parameter, though Item 40 [1] sustains "Aim
for four parameters or fewer"

- Another factor to look at is the convariant ordering or the interface,
meaning if it is more general (generic) or more specific [2]. This interface
SLVC is more specific than SFMC. More general interfaces like SFMC tend to
be easier to implement as they impose less requirement on implementors i.e.
they don't force implementors to depend on or having to specifically deal
with Locale. Furthermore, having more specific interfaces with more
dependencies increases the values of the OO metrics "AC" Afferent Couplings
and "CBO" Coupling Between Objects [3] [4]. A higher number in "AC" or "CBO"
means more instability and less abstract.
// The stateful minimalistic contract [SFMC]
public interface ITranslator {
String translate(String text);
}
This is a more abstract, less instable choice for an interface, thus you
could hand this ITranslator to layers of your app safely assuming that they
will not be impacted should the implementors decide to change depending away
from Locale or should Locale public interface change.

For all explained before, I think a very good alternative would be:

//
// leave it free for more specific variants to be created and easier, more
stable reuse
//
public interface ITranslator {
String translate(String text);
};

//
// more specific subclass that could be more useful in the configuration
layer of an application
//
public interface ILocaleTranslator extends ITranslator {
void setFromLocale(Locale fromLocale);

void setToLocale(Locale toLocale);

void swap();
};

Best regards,
Giovanni

[1] Effective Java 2nd Edition 2008
http://www.amazon.com/Effective-Jav...=sr_1_1?ie=UTF8&s=books&qid=1245585338&sr=1-1
[2]
http://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)
[3]
http://satc.gsfc.nasa.gov/support/O...nts_of_Orthogonal_Object_Oriented_Metrics.pdf
[4]
http://www.parlezuml.com/metrics/OO Design Principles & Metrics.pdf
 
G

Giovanni Azua

Or maybe a better more fine grained design:

public interface ITranslator {
String translate(String text);
};

public interface ILocaleAware {
void setFromLocale(Locale fromLocale);

void setToLocale(Locale toLocale);
}

public interface ILocaleAwareTranslator extends ITranslator, ILocaleAware {
void swap();
}

Best regards,
Giovanni
 
G

Giovanni Azua

Giovanni Azua said:
Or maybe a better more fine grained design:
This design just remainded me of one relevant excerpt from a book [1] I read
many many years ago. I retained forever the helicopter metaphor of this
excerpt:

"... which is more reusable: a single interface that represents the behavior
of a helicopter, including flying, floating, hovering, lifting, rolling,
vibrating, shaking and falling, or multiple interfaces representing each of
these behaviors individually? An interface that represents flying is much
more reusable than an interface that represents a helicopter. Hardly
anything but a helicopter behaves like a helicopter. Hoewever, lots of
things fly." [1]

I think this is just another way to say the same thing i.e. favor splitting
and fine grained interface designs.

btw Another excerpt from that book I retained forever but rather as a funny
thing was:

"While COM interfaces use only a subset of IDL, they do require several
nonstandard extensions that Microsoft added to support COM. At Microsoft, we
always feel we can improve on a standard."

therefore breaking them lol :)

--
Giovanni


[1] Inside COM 1997
http://www.amazon.com/gp/product/15...&pf_rd_t=101&pf_rd_p=470938131&pf_rd_i=507846
 
M

markspace

Giovanni said:
Giovanni Azua said:
Or maybe a better more fine grained design:
This design just remainded me of one relevant excerpt from a book [1] I read
many many years ago. I retained forever the helicopter metaphor of this
excerpt:

"... which is more reusable: a single interface that represents the behavior
of a helicopter, including flying, floating, hovering, lifting, rolling,
vibrating, shaking and falling, or multiple interfaces representing each of
these behaviors individually? An interface that represents flying is much
more reusable than an interface that represents a helicopter. Hardly
anything but a helicopter behaves like a helicopter. Hoewever, lots of
things fly." [1]

I think this is just another way to say the same thing i.e. favor splitting
and fine grained interface designs.


This seems to me to be reversed: "fly" is a coarse interface, whereas
"flying", "lifting", "rolling", "vibrating", "shaking", etc. seem like
finer, and therefore less useful, behaviors.

Design books I have read recently emphasize coarse interfaces, because
the coarse interface is easy to deal with and can represent lots of
behavior. Fine interfaces require lots of "if this property but not
this property" checking in the controlling code. These coarse
interfaces also emphasize dependency injection, testability and
data-driven design.

("Data-driven" design here means you read class names from a config file
and instantiate the classes reflectively. It's useful for configuring
frameworks.)
 
A

Arne Vajhøj

sasuke said:
I've been recently trying to design a small command line translator
application. I can come up with three possibilities as to the way in
which the interface which hides the translation magic behind the
scenes can be designed:

// The stateless verbose contract [SLVC]
public interface ITranslator {
String translate(String text, Locale fromLocale, Locale toLocale);
}

// The stateful minimalistic contract [SFMC]
public interface ITranslator {
String translate(String text);
}

// The stateful verbose contract [SFVC]
public interface ITranslator {
String translate(String text);

void setFromLocale(Locale fromLocale);

void setToLocale(Locale toLocale);
}

Here is my interpretation of the three:
- The SLVC places the responsibility of handling the locale
information on the calling class. The implementation class can be very
well implemented using the Singleton design pattern since no
additional information is required when translating text.
- The SFMC places the responsibility of handling locale information on
the implementation class. One of the ways in which this can be done is
make the implementation class provide setter or hook methods for
setting the locale information though any other approach for
retrieving the locale information can be used.
- The SFVC is a verbose version of SFMC which mandates the
implementation class provide hooks for setting the Locale information
i.e. mandates the implementation class be Stateful.

I'm personally leaning towards the first approach but would very much
like to hear what is the general thought process which goes behind
when designing interfaces in general. Comments and suggestions
appreciated.

I would also prefer the SLVC approach.

Stateless is usually good.

You can use the same translator object in a multithreaded
environment.

Arne
 
A

Arne Vajhøj

Arne said:
sasuke said:
I've been recently trying to design a small command line translator
application. I can come up with three possibilities as to the way in
which the interface which hides the translation magic behind the
scenes can be designed:

// The stateless verbose contract [SLVC]
public interface ITranslator {
String translate(String text, Locale fromLocale, Locale toLocale);
}

// The stateful minimalistic contract [SFMC]
public interface ITranslator {
String translate(String text);
}

// The stateful verbose contract [SFVC]
public interface ITranslator {
String translate(String text);

void setFromLocale(Locale fromLocale);

void setToLocale(Locale toLocale);
}

Here is my interpretation of the three:
- The SLVC places the responsibility of handling the locale
information on the calling class. The implementation class can be very
well implemented using the Singleton design pattern since no
additional information is required when translating text.
- The SFMC places the responsibility of handling locale information on
the implementation class. One of the ways in which this can be done is
make the implementation class provide setter or hook methods for
setting the locale information though any other approach for
retrieving the locale information can be used.
- The SFVC is a verbose version of SFMC which mandates the
implementation class provide hooks for setting the Locale information
i.e. mandates the implementation class be Stateful.

I'm personally leaning towards the first approach but would very much
like to hear what is the general thought process which goes behind
when designing interfaces in general. Comments and suggestions
appreciated.

I would also prefer the SLVC approach.

Stateless is usually good.

You can use the same translator object in a multithreaded
environment.

At least it is both possible and easy to code it that way.

Arne
 
S

sasuke

Hi all,

Thanks to all the suggestions provided, I was able to come with a
basic implementation of my translation library. The interfaces I ended
up creating are:

public interface ITranslator {
String translate(String text);
}

// This is implemented by classes like GoogleTranslatorImpl
public interface ILocaleTranslator extends ITranslator {
void setFromLocale(Locale fromLocale);
void setFromLocale(Locale fromLocale);
Locale getToLocale();
Locale getFromLocale();
}

// This is implemented by classes like PropertiesFileTranslatorImpl
public interface ITextFileTranslator {
void setTranslator(ITranslator translator);
void translateFile(File inFile, File outFile) throws
TranslationException;
}

Having reached this far, I still have a couple of queries:

= Let's suppose I've a very simple Socket server for dealing with
translations. For translating each piece of text I:
- Connect to the server socket
- Send the request
- Receive the translated response
- Close the resources

What would be a good way of introducing the concept of session in my
library implementation wherein the user can take advantage of using
the same connection [if supported] for all its translations during a
session instead of creating and destroying the socket connection for
each piece of text? I was thinking along the lines of having a `init
()' and `destroy()' methods which would be invoked by the client to
initiate or destroy a translation session respectively.

= What would be a good way of handling exceptions when creating such
general purpose libraries? Right now I have a single exception class,
TranslationException which extends RuntimeException for this. It
encapsulates all the checked exceptions thrown by the application by
catching all the checked exceptions and wrapping them like:
try {
// any piece of code
} catch(Exception e) {
throw new TranslationException(e.getMessage(), e);
}

= How would I go about writing test cases for translation
implementations which require external resources like a socket
connection to the translation service and so on? Let's assume my
implementation class looks something along the lines of:

class XXXTranslator implements ILocaleTranslator {

// implement all interface getters and setters

public String translate(String translate) {
// some complicated preprocessing
// connection to the translation service
// some complicated post processing
}
}

Please let me know in case further clarifications are required.
Comments and suggestions would be greatly appreciated.

../sasuke
 

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

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,040
Latest member
papereejit

Latest Threads

Top