views:

160

answers:

2

In case management and workflow systems this seems to come up a lot. The need to provide a comprehensive list of each business message in the 'system' and provide its possible cause(s) and corrective action(s).

A vendor example is Oracle: All their errors have a naming convention (e.g. ORA-00237) and they have documented every possible ORA-XXXXX error).

How do you 'mandate' this in your development process without creating an undue burden on the team? Example problem domains would be software like a loan application, Corporate Tax Preparation application, Determining Eligibility for an entitlement program etc..

A: 

Is this a reasonale summary of reqirements?

  1. All messages emmitted are labelled with some uniquifier.
  2. The uniquifier is independent of internatioliasation of the text message.
  3. Those uniquifier are stable over time, a new release of the app should use the same uniquifier for a message that was emmited in the previous release. This tends to help folklore build: oh yes, error ZZ-27B, that's caused by ...
  4. That stability is not affected by minor syntactic fixes to the text, spelling corrections and message elaborations.
  5. We need to help programmers get it right. So we want to make it as easy as possible for the programmer, and readily validated by the code reviewer.

In an ideal world I'd like to use some kind of annotation and/or injection technique to manage the whole thing. However I can't think of a way to ensure that uniquifiers are stable over time without the developer needing to be involved. When a developer refactors some code, changing its position, and fixes some typos in text it's not trivial to spot it's the "same" error message.

So I'd revert to my (very) old practice:

1). Devise a suitable granularity for the uniquifiers CCC-MM-nnn. CCC being an application identifier, MM some "module" probably at a higher level than the leaves of the Java package hierarchy. nnn being a sequence number. For each MM have a Class containing static constants for each message.

// conceptually like this, but perhaps done with enums or annotations
static final MessageUniquifier  CCC_MM_123 = new MessageUniquifier("CCC_MM_123);

2). Have a logging api

Logger {
  public void logError(MessageUniquifier id, String message) ...

The effects of this approach are

  • Developers must supply a unquifier for every message, compilation error if not
  • The effort to create a new uniquifier is to edit the appropriate uniquifier class, we have several so that there's not too much contention for those edits.
  • It's relatively trivial to come up with a tool that checks that no two message production points use the same uniquifier.
  • The documentation for each error can be added as java doc to the uniquifier classes or readily matched against them, so completeness is reasonably easy to check.
djna
+2  A: 

For errors raised by your own application, a common solution it to have a table of error messages like this:

create table errors
    ( error_no integer primary key
    , error_text varchar2(200)
    , error_cause varchar2(4000)
    , error_action varchar2(4000)
    );

A typical entry might be:

insert into errors (error_no, error_text, error_cause, error_action)
values (479, 'End date cannot be earlier than start date',
        'A start date and an end date were entered where the end date was before the start date, which is not allowed.',
        'Correct the start and end dates and retry.'
       );

Then in your code handle exceptions something like this:

if p_start_date > p_end_date then
    error_pkg.raise_error (479);
end if;

The package would do something like:

procedure raise_error (p_error_no integer)
is
    l_text errors.error_text%type;
begin
    select error_text into l_text
    from   errors
    where  error_no = p_error_no;
    raise_application_error(-20001, l_text);
end;

The end user would see something like:

ERROR 479: End date cannot be earlier than start date

This could then be looked up to get the cause and action details.

A more advanced version would allow for data values to be displayed in the messages, using placeholders in the error text like this:

insert into errors (error_no, error_text, error_cause, error_action)
values (456, 'Invalid action code: [1]',
        'An invalid action was specified', 'Correct the action code and retry.'
       );

error_pkg.raise_error (456, p_act_code);
Tony Andrews
Brian
Yes, it's by no means infallible. What I have found is that eventually some developer finds a reason to set up a generic error like (999, '[1]') where [1] is a placeholder, and then the actual message is supplied in the call. This then gets used all over the application for different reasons - thus defeating the object of having the table in the first place!
Tony Andrews