Monday, September 6, 2010

writing jobs


Also writing ad-hoc jobs to correct data or straighten faulty situations? These one-time jobs that will be used for weeks, months or even years? Put a stop to these jobs: refuse to write them!
Instead make decent and expandable user-proof solutions based on runBaseBatch for example. Put a little dialog on, make it configurable, useable by non-technical-skilled users, ....

Why going to all that trouble? We all know it is not just a one-time job ... it will start a life after you created it. Give  your coding an honourable life, even the lousy jobs!

If you do stick to writing a job, at least make it a respectable one:
- don't put hardcoded variables in there, use a dialog (which is as simple as in the code example below),
- add an info to inform what's been done (how many records, how much time, ...)
- use try-catch when appropriate
- give your variables meaningfull names,
- some comment never hurts,
- ...

static void LAX_Job_Dialog(Args _args)
    Dialog          dialog;
    DialogField     dlgCustName;
    CustName        custName;
    CustTable       custTable;
    Counter         cnt;
    dialog = new Dialog('find customer named ...');
    dlgCustName = dialog.addField(typeId(CustName));

    if (
        custName = dlgCustName.value();
        if (custName)
            // search for any customer with the entered value in the name
            custName = '*' + custName + '*';
            while select accountNum, Name
                from custTable
                where custTable.Name like custName
                info(strFmt('%1 - %2', custTable.AccountNum, custTable.Name));
        info(strFmt('%1 customers found', cnt));

P.S. Jobs are executed on the client-side. Drag your job into a menu-item, set the 'runon' property to 'server' and its speed will most likely boost. Especially jobs with while select loops in them.

Wednesday, September 1, 2010

debugging tip


With some errors in Ax, I somethimes just don't know where to start debugging.
In those situations I use the call stack as a starting point to give me an idea on where to place breakpoints.

Here's what I do:

1 - create a new static method LAXGetCallStack in the Global class:
// this method returns the X++ call stack, the _offset is to skip entries at the top of the stack

client server static str LAXGetCallStack(int _offset = 0)
    container   callStack =    xsession::xppCallStack();
    int         k;
    int         lineNumber;
    str         entry;
    str         path;

    for (k = 1 + _offset ; k <= conlen(callSTack) ; k = k + 2)
        path = conpeek(callStack,k);
        lineNumber = conpeek(callStack,k+1);
        entry += (entry ? #newline :'') + strfmt('-> %1 Line - %2', path, lineNumber);
    return entry;

2 - modify the infolog.add method 
a - add this to the declaration section
    boolean     stackTraceActive;
    str         strInfoTxtToDebug;

b - add this at the beginning of the method (before switch(loglevel))
    stackTraceActive = true;
    strInfoTxtToDebug = 'debug';
    strInfoTxtToDebug = '*' + strInfoTxtToDebug + '*';

    if (stackTraceActive)
        if (_txt like strInfoTxtToDebug)
            _txt += #newLine + 'STACKTRACE for debugging:';
            _txt += #newLine + LAXGetCallStack(4);

If I get to investigate situations where the only clue is some strange info/warning/error, I use (a specific part of) the text of the infolog as a condition to in the infolog.add method to get the stacktrace an thus the calling objects.

This can be improved by making the stackTraceActive variable a user settable parameter. 
The same goes for the strInfoTxtToDebug variable.

list table properties


Ever got the question to list all tables that have a certain property set (caching, tableGroup, configurationKey, securityKey, ...), but don't feel like browsing throug the AOT manually? I do. This script enables you to export the table properties you want to study into an xls (well, a tab-delimited) file. The result then looks like this.

The same concept can be used to list properties of other objects.