method signature design question

M

madworld

I have a method that I want to write to verify if a credit card's details
are correct. I want to return an error message if there is a problem with
them (such as 'missing digit'). The implementation is not a problem, but I
cannot decide the best way to set out my interface.

I have decided there are 3 ways to do the method signature.


1) public boolean verify(Card card) throws SomeException
I would return true if the card was verified or throw an exception with an
error message otherwise.

2) public String verify(Card card)
Return null if the card was ok, otherwise return a string of the error
message.

3) public void verify(Card card) throws SomeException
Just do nothing if the card was ok, otherwise throw an exception with an
error message.


Which way would you choose to do this ?
 
R

Ryan Stewart

madworld said:
I have a method that I want to write to verify if a credit card's details
are correct. I want to return an error message if there is a problem with
them (such as 'missing digit'). The implementation is not a problem, but I
cannot decide the best way to set out my interface.

I have decided there are 3 ways to do the method signature.


1) public boolean verify(Card card) throws SomeException
I would return true if the card was verified or throw an exception with an
error message otherwise.

2) public String verify(Card card)
Return null if the card was ok, otherwise return a string of the error
message.

3) public void verify(Card card) throws SomeException
Just do nothing if the card was ok, otherwise throw an exception with an
error message.


Which way would you choose to do this ?

How about 4) public boolean verify(Card card, StringBuffer message) --
Returns true if the card is valid or false and modifies the StringBuffer to
hold the error message. Not saying that's a better alternative, but an
alternative.
 
M

Marco Schmidt

madworld:

[...]
Which way would you choose to do this ?

I'd go for variant #2. Exceptions should be used only when
exceptional things happen in the method. With a credit card
verification method, an invalid number is a normal (= to be expected)
outcome.

For proper i18n an error code (e.g. of type int) would be nice. That
way, the error message could be picked with regard to the current
language of the program instead of hard-coding it into the verify
method.

Regards,
Marco
 
S

Sudsy

madworld wrote:
1) public boolean verify(Card card) throws SomeException
I would return true if the card was verified or throw an exception with an
error message otherwise.

2) public String verify(Card card)
Return null if the card was ok, otherwise return a string of the error
message.

3) public void verify(Card card) throws SomeException
Just do nothing if the card was ok, otherwise throw an exception with an
error message.

Which way would you choose to do this ?

#1 and #3 are effectively the same. Why bother returning a boolean when
an exception will be thrown if verification fails anyway?
So I'd go for #3. The strength of this approach is that the exception
can incorporate additional information. Did the MOD-10 check fail? Did
the prefix check fail? Was the card number length incorrect for the
card issuer? Was the security code required but not supplied?
Your verify method could be applicable to any number of situations if
the exception class is well defined, implemented and documented.
That's my approach, FWIW.
 
A

Alexey Dmitriev

#1 and #3 are effectively the same. Why bother returning a boolean when
an exception will be thrown if verification fails anyway?
So I'd go for #3. The strength of this approach is that the exception
can incorporate additional information. Did the MOD-10 check fail? Did
the prefix check fail? Was the card number length incorrect for the
card issuer? Was the security code required but not supplied?
Your verify method could be applicable to any number of situations if
the exception class is well defined, implemented and documented.
That's my approach, FWIW.

There is no doubt, that this approach is more convenient :)
 
F

Filip Larsen

I have a method that I want to write to verify if a credit card's details
are correct.
[...]
I have decided there are 3 ways to do the method signature.

You might also want to consider a 4th "business modelling" variant:

public VerificationResult verify(Card card);

where the return type can be either a simple class or a whole class
tree. The return type should probably have at least an isApproved()
method (somewhat corresponding to your boolean return value) so that it
is easy to branch. I would also recommend always returning a non-null
result with this signature.

If you have blocks of code where the pre-condition for the block is that
the card is approved, you can alwyas use a convenience method like

public void verifyApproved(Card card) throws VerificationException;

that will throw an exception (with a link to a VerificationResult) if
the card is not approved.

My main point here, I guess, is that the verify method verifies credit
card and nothing else. Whether or not some verification result is
exceptional is up to the context in which verify is called.


Regards,
 
S

Sudsy

Filip Larsen wrote:
My main point here, I guess, is that the verify method verifies credit
card and nothing else. Whether or not some verification result is
exceptional is up to the context in which verify is called.

Having real-world experience implementing credit card systems, I can
assure you that this is one of the more complex issues. In addition
to some of the other validation failures I mentioned earlier you can
also run into "system not available" and even "take card" situations.
That last one is where the merchant is actually supposed to keep the
card, not return it to the customer.
So how do you do that in an e-commerce scenario? You can't, of course.
But how much information do you return to the customer? Do you let
them know that they're over their credit limit? Do you really want
to return the results of AVS (Address Validation System)? Certainly
not! scammers seek out such "open" systems to test card numbers and
addresses.
Besides which, the requirements are different for the on-line trans-
action and the customer service situations. In the latter case you
might want the operator to see the failure message and tactfully
deal with the customer on the line. The on-line transaction should
fail, the failure reason should be logged, and the customer told,
politely, that the transaction could not be completed. They should
also be provided with the customer service telephone number.
Hence my suggestion. It handles both situations as well as others
which might be encountered in the future. As always, YMMV.
 
M

madworld

Sudsy said:
Filip Larsen wrote:


Having real-world experience implementing credit card systems, I can
assure you that this is one of the more complex issues. In addition
to some of the other validation failures I mentioned earlier you can
also run into "system not available" and even "take card" situations.
That last one is where the merchant is actually supposed to keep the
card, not return it to the customer.
So how do you do that in an e-commerce scenario? You can't, of course.
But how much information do you return to the customer? Do you let
them know that they're over their credit limit? Do you really want
to return the results of AVS (Address Validation System)? Certainly
not! scammers seek out such "open" systems to test card numbers and
addresses.
Besides which, the requirements are different for the on-line trans-
action and the customer service situations. In the latter case you
might want the operator to see the failure message and tactfully
deal with the customer on the line. The on-line transaction should
fail, the failure reason should be logged, and the customer told,
politely, that the transaction could not be completed. They should
also be provided with the customer service telephone number.
Hence my suggestion. It handles both situations as well as others
which might be encountered in the future. As always, YMMV.

My verify method works by charging the customer the minimum amount the
processor allows via a pre-auth and then immediately voiding it.

It's more effective and simplier than trying to code in a set of validation
rules myself. And it also picks up on cancelled cards, and cards with
blocks.
 
S

Sudsy

madworld wrote:
My verify method works by charging the customer the minimum amount the
processor allows via a pre-auth and then immediately voiding it.

Ah, the old $1.01 pre-auth hold!
It's more effective and simplier than trying to code in a set of validation
rules myself. And it also picks up on cancelled cards, and cards with
blocks.

Think carefully about the costs involved with doing things that way.
How much does your credit card processor charge you per transaction?
Check this out:
- pre-auth hold fails: 1 transaction
- pre-auth hold, void, charge: 3 transaction
Depending on your monthly volume, these charges can add up to a lot
of money. Even if it's only a couple of quarters per transaction,
you're still ringing up some serious coin.

Remember the M$ ad about saving a nickel on every transaction?...
 
M

madworld

Sudsy said:
madworld wrote:


Ah, the old $1.01 pre-auth hold!

£0.10 here actually.
Think carefully about the costs involved with doing things that way.
How much does your credit card processor charge you per transaction?
Check this out:
- pre-auth hold fails: 1 transaction
- pre-auth hold, void, charge: 3 transaction
Depending on your monthly volume, these charges can add up to a lot
of money. Even if it's only a couple of quarters per transaction,
you're still ringing up some serious coin.

Remember the M$ ad about saving a nickel on every transaction?...

I have already checked this out, and the processor here does not charge per
transaction. It only charges per settled transaction.

So this is free.
 
F

Filip Larsen

Sudsy said:
Having real-world experience implementing credit card systems, I can
assure you that this is one of the more complex issues.

I fully agree with most of your post.

When I worked with implementing prepaid services for GSM, the system
design of prepaid and credit card validation were often more complex and
time-consuming than the "pure" technical stuff, mainly because there
were so many colliding interests: response-time, through-put,
availability, security, local law, provider policies, etc.
In addition
to some of the other validation failures I mentioned earlier you can
also run into "system not available" and even "take card" situations.

Yes, that is also why I would model the API to support the business
process of credit card validation in general. I consider the verify
method the original poster mentions to be a validation engine or
service, doing all the distributed computing to validate a card, and
then some higher level code then adapt the results to fit the correct
business context (like your example with an ATM/POS versus on-line
internet transaction).
But how much information do you return to the customer? Do you let
them know that they're over their credit limit? Do you really want
to return the results of AVS (Address Validation System)? Certainly
not! scammers seek out such "open" systems to test card numbers and
addresses.

If you are worried that "client code" unintentionally might use a
validation service in a way that breaks the business process, then it
could be done following the usual Java service pattern where you
configure a factory and then get from it a validation instance on which
you then call verify. This way a number business process variations can
be configured into one service. For instance, the detail of information
passed back could be reduced appropriately to validation services called
in a "on-line" or "self-service" configuration so that caller code do
not have to do any filtering in that regard.
Besides which, the requirements are different for the on-line trans-
action and the customer service situations. In the latter case you
might want the operator to see the failure message and tactfully
deal with the customer on the line. The on-line transaction should
fail, the failure reason should be logged, and the customer told,
politely, that the transaction could not be completed. They should
also be provided with the customer service telephone number.
Hence my suggestion. It handles both situations as well as others
which might be encountered in the future. As always, YMMV.

Assuming you refer to signature #3 in the original post I must say that
I do not agree in the following sense: an implementation of a business
process should only use exceptions for variations that are truely
exceptional, preferably for scenarios not specified in the process at
all.

If, for instance, the validation process is modelled as a simple
"atomic" test with a yes/no answer, then the business result is boolean
and the implementation would then have to use exceptions to signal any
of the "normal" exceptions that occur in distributed systems. Throwing
an exception, however, carries no meaning for the business process, so a
caller cannot in general conclude yes or no on an exception.


Oh well, I can see I am heading out into an age old discussion :)

Regards,
 
J

Jezuch

U¿ytkownik Ryan Stewart napisa³:
How about 4) public boolean verify(Card card, StringBuffer message) --
Returns true if the card is valid or false and modifies the StringBuffer to
hold the error message. Not saying that's a better alternative, but an
alternative.

Smells like C...
 
S

Sudsy

Filip Larsen wrote:
If, for instance, the validation process is modelled as a simple
"atomic" test with a yes/no answer, then the business result is boolean
and the implementation would then have to use exceptions to signal any
of the "normal" exceptions that occur in distributed systems. Throwing
an exception, however, carries no meaning for the business process, so a
caller cannot in general conclude yes or no on an exception.


Oh well, I can see I am heading out into an age old discussion :)

Regards,

Not to belabor the point (too late!) but how often do you expect to
get a card rejection? Every 100? Every 1,000? To my mind that calls
for an exception. Of course it's not the only way...
I actually do processing in three stages:
1. I invoke a static method called getCardIssuer. If it returns null
then the card failed basic sanity checks. I do this since not
every client will be able/willing to accept all card brands. If
they only accept MasterCard and Visa then this check helps.
2. Run the number through the "hot list".
3. Try to apply the charge.
I generate an exception only at the third stage, if the card will
not accept the charge.
It could also be implemented as a method returning an object which
contains the results of the attempt or a boolean, as you suggested.
Different strokes for different folks. That's why I add the YMMV
disclaimer.
 
F

Filip Larsen

Sudsy wrote
Not to belabor the point (too late!) but how often do you expect to
get a card rejection? Every 100? Every 1,000? To my mind that calls
for an exception. Of course it's not the only way...

Point taken. If you model rejection as an exceptional case in your
business process, then it might make perfect sense to use checked
exceptions to implement it. Heck, I use option #3 myself on occation :)
Different strokes for different folks. That's why I add the YMMV
disclaimer.

I agree.


Regards,
 

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,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top