Wednesday, December 1, 2010

What's wrong with profile attributes?

As a general rule, we shouldn't allow developers to use profile attributes. Looking back, I've probably used about 1 profile attribute a year, to accomplish some pretty edgy (read: hacky) things. People normally use them to pass data around like from a business component to an applet or a from the server to the browser. Here's why they're a bad choice...

Profile attributes have no scope, and no namespace. Profile attributes are set at the session level so changes made in one piece of code can inadvertently affect code in other areas. The fact that there are no namespaces makes the problem worse, because your chances of accidentally using a name someone else used are greater (although you could come up with some namespace scheme).

Profile attributes screw your ability to debug. Because you can't find all the places your profile attribute might be set or unset, debugging becomes much tougher.

Profile attributes screw your ability to refactor. For the same reasons that your ability to debug is screwed, so is your ability to refactor. One of the basic things you need to be able to do when refactoring is finding all the places you used variable x. Well if variable x is a profile attribute, good luck!

Getting a profile attribute from the client is costly. Not everyone understands this. Your profile attributes do not exist in the client. So when you try to read them from browser script, Siebel needs to do a round-trip to the server to get it. That's a round-trip for each profile attribute you get or set.

In short, if you think you need to use a profile attribute to accomplish something, think again! If you still think you need a profile attribute, hit yourself on the head and think again!*

* The same advice pretty much applies for shared globals as well.

Wednesday, July 21, 2010

Java Data Bean Performance

I'm not supposed to be working on Siebel anymore, but something keeps pulling me back to do odd jobs.

One of my coworkers was complaining about the slow performance when integrating with Siebel using the Siebel Java Data Bean. He was just creating some buscomp records and setting a bunch of field values along the way.

I'm not very familiar with the Siebel Java Data Bean, but my theory is that each buscomp operation (NewRecord, SetFieldValue, SetFieldValue, SetFieldValue, etc) was triggering a round trip to post changes to the server. There aren't a lot of hard rules in my book for improving performance, but avoiding the network is one of them (avoiding the database is another). [Can anyone confirm my theory that the Java Data Bean is heavy on posting changes?]

So how can we avoid the network in this case? Two ideas immediately come to mind. Without giving it away, one of them still uses the Siebel Java Data Bean, the other uses a different solution altogether. Either of them would allow you to create a bunch of new records all in a single round-trip.

Can you guess what I'm thinking of? Any additional ideas that may help here?

[We did a quick POC and were able to get a 90% reduction in execution time with one of these approaches]

Friday, April 30, 2010

Could not open/read file: C:\sea77\client\local\sse_data.dbf

Do you get a popup error when you start up your computer that says "Could not open/read file: C:\sea77\client\local\sse_data.dbf"? If you do, I bet it takes a heck of a long time to start up your computer too. I haven't run into this problem for quite sometime, but I just got a new machine and a clean install of Siebel 7.7.6.2 (client). I run into this problem every time I make a clean install but for some reason I can't seem to remember how to fix it right away. It bothers me enough that I thought I'd post a solution to it here. It's easy.
  • In Windows, go to Start > Run, and type "services.msc" in the Run window to open your services console.
  • Find the service named "Adaptive Server Anywhere - siebel_local"
  • Right click the service and select Properties from the context-menu
  • In the Properties window, change the startup type to "Manual"
  • Do the same for the service named "Siebel QuickStart Service"
  • Click Apply, then OK
This disables the auto-startup of the SQLAnywhere server that looks for your local database. Another fix is probably to re-point your Local data source to an existing DBF file, or to drop a DBF file into the expected directory, but I don't really need this feature on startup, so I just like to disable it.
There you go. Enjoy your two minutes back at every startup.

Thursday, April 23, 2009

Workflow vs. Server Script

There's a lot of advice out there that says to use declarative solutions whenever possible and turn to scripting as a last resort only.  Hell, it's the basis of Siebel's technical document "Declarative Alternatives to Siebel Scripting".  I believe in using straight Tools configuration as much as possible, but there's one thing I'm not yet sold on: Using workflow processes in lieu of scripted business services for complex actions.

I used to believe what I heard, that workflow processes were superior to scripted business services - but then I decided to evaluate it for myself.  There are advantages and disadvantages to each approach, and I'll get to those later.

What originally sold me was the argument that workflow processes performed more strongly than server script because they did not have the overhead of a script interpreter.  The argument usually goes something like this, "Workflow processes run the compiled C++ code directly, so are faster than scripted processes that must be interpreted."  Well newsflash: Workflow processes also need to be interpreted.  Siebel did not build your workflow into their product, did they?  You described it using a tool, and that description must be interpreted at runtime.  Yes, compiled C++ is used to interpret your workflow processes.  And compiled C++ is also used to interpret your scripts.

Which interpreter is faster?  Which engine loads faster?  I ran some tests to find out.  The results show that the two were very comparible when performing the exact same operations.  If there were any differences, they were negligible.  My test updated the amount of a single revenue record.  Each process (scripted and workflow) did one query and one update.  After warming up the OM, each process completed in 57 milliseconds on average (which included the time to invoke each via a driver script).

What I did notice was that because workflow processes were not as descriptive as script, and you sometimes needed to do more work to accomplish the same task.  For instance, when I extended the test to update multiple revenue records, it took the scripted version 1 query and 21 writes to update 21 records, while the workflow processes needed 22 queries and 21 writes.  How did that affect the results?  The scripted process averaged a reasonable 500 milliseconds while the workflow process chugged along at 865 milliseconds on average.

So the results seem to say that workflows are just as fast as scripts when the performing the same operations, but the inflexibility of workflow processes can lead to algorithms that are less than ideal performance-wise.

Other reasons to like business services are that the development times are faster for various reasons.  The script debugging tools are more sophisticated, and starting your script debugger is typically faster than starting the workflow simulator - particularly if you need to deploy and activate a workflow subprocess before simulating.  And I don't think anyone would disagree when I say that scripts are far more flexible and powerful than workflow processes.

So what reasons are there to like workflow processes?  For one, they can be deployed without an SRF.  I'm guessing that benefit has not nor will ever be realized by a large portion of Siebel customers.  One reason that I like is that their level of instrumentation is far superior to script.  The workflow monitor and logging events are far more useful in a production environment than any script built-in instrumentation for script (there is almost none).  That can be invaluable in getting a production issue resolved quickly, for a problem that would normally be hard to reproduce and research.

In the end, I'm somewhere in the middle - but I'd have to say a bit closer to the script (read: dark) side.  What do you all think?

Thursday, March 12, 2009

Extending eScript Objects

There seemed to be a lot of interest in the post on Siebel Unleashed about the ABS (ATI) Framework for eScript (unrelated to Siebel's Appointment Booking System), which is some company's proprietary tool set used to perform repetitive tasks in eScript - some simple and some complex. A few examples given were: searching for the existence of a particular value in an array; accessing TheApplication() object; getting the field values of a record for which we know the Id. And doing those things in a consistent manner and using fewer keystrokes. What struck me is how well they integrated their framework with Siebel and core eScript objects.

I really believe in tool sets, and I'd like to see some Siebel hackers out there expand on the idea. How this tool set was built is not really obvious, so I'd thought I'd take a stab at it. Respecting the fact that the ATI Framework is proprietary, I won't give a whole lot of detail reverse-engineering the complex API calls I saw in the posts. However, I will show some basic techniques you can use to build your own framework using some simple examples. It would help to know a bit about objects and properties in JavaScript.

To keep the post relatively short, I'm not going to give any examples to validate that this stuff actually works. I'll leave that to you, because it's best to figure some things out yourself. If you're having problems, just know that I have successfully tested these concepts.

Is this value in the array?

Sometimes you have to search an array to see if a particular value exists. Nothing a little "for" loop can't take care of. But if you need to do this with any kind of frequency, why rewrite it every time? Also, what if a developer introduces a bug while trying to reimplement it? Write it once, make it work, and reuse it. Not only will you reduce your exposure to programming errors, but it will make your programs more succinct, and much easier to comprehend.

You can always add an application method that takes a reference to the array and the value you're searching for and returns a true or false, but I always wondered why this method wasn't part of the Array object to begin with. Let's go ahead and make it part of the Array object by modifying the prototype property to include a custom function. I put this in the "(declarations)" section of my application server script (which I chose because it's the first script I know of that's executed when the application starts):

Array.prototype.Exists = function (value)
{
  for (var i = this.length - 1; i >= 0; i--)
    if (this[i] == value) return true;
  return false;
}

Once this sets up you'll be able to see if the value "5 of spades" exists in your aCardDeck array: aCardDeck.Exists("5 of spades");

Accessing the Application Object

Ever get tired of typing TheApplication() every time you need to access an application method? Well those on the ATI Framework don't. It looks like they've reduced the application reference to some sort of global variable "TheApp", accessible from any object.

If I had a business component and wanted to make "TheApp" available from anywhere within that object, I could add a line like "var TheApp = TheApplication();" to the "(declarations)" section of the business component. But that means I'd have to add that line to every business component, which makes me angry. You won't like me when I'm angry. So how can we avoid the maintenance hassle, and me turning into a big green monster?

What if we update the prototype of the business component object to include "TheApp"? That sounds like a good idea. Well unfortunately I haven't been able to figure out what the business component object/constructor is actually called. I'll do the next best thing, which is to add "TheApp" to all custom objects. The business component object must be derived from the Object class. So here's another addition to the application "(declarations)":

Object.prototype.TheApp = this;

Remember, that "this" is the application object, since we're doing this from the application "(declarations)". This approach has the added benefit of enabling "TheApp" reference from all Siebel objects including business services, applets, and, yes, the application object itself. It surprised me that the application object was able to access "TheApp", since the prototype was modified after the application was already instantiated.

Adding a Custom Business Component Method

Let's say, for some reason, you constantly find the need to get business component field values in uppercase characters only. Well here's what I added to the application "(declarations)" this time:

Object.prototype.GetFieldValueUpperCase = function (sFieldName)
{
  return this.GetFieldValue (sFieldName).toUpperCase ();
}

Now if you have some bc "bcFoo", you can get the value for field "Bar" in uppercase characters by doing something like, "bcFoo.GetFieldValueUpperCase("Bar");" When this is called from a business component object, then all the references to "this" refer to that business component.

The unwanted side-effect here is that this method is enabled on all custom objects because we updated the prototype of the Object class. Since GetFieldValue() is only supported on business components, this will fail on any other object. So, if anyone finds the object/constructor names for any Siebel objects, please let that cat out of the bag. In any case,

I think you guys have had enough. Don't forget to let us all know if you find the object/constructor names for any Siebel objects. And if they're any new discoveries or breakthroughs out there, please comment about it. But for now, happy hacking!

Friday, February 13, 2009

Siebel 8.1.1.0 on Windows Vista

So I decided to see what this Siebel 8 hype was all about. I downloaded all the necessary files from Oracle eDelivery, unzipped them, used the ImageCreator to build the network installation image (whatever that means), then proceeded to install Siebel Tools and Web Client.

All of this on Windows Vista, mind you. I had to run the installs as Administrator in Windows XP SP2 compatibility mode, otherwise, Oracle's Universal Install just disappeared as soon as files started copying.

Well, the Tools installation completed, but failed to start. The Web Client just plain didn't install. The Web Client installation failed just after checking the system prerequisites, before choosing language packs. When I attempted to continue, ignoring the error, no language packs appeared for selection.

A little searching around brought me to this Oracle doc: "Siebel System Requirement and Supported Platforms, Version 8.1 Rev. A, January 2009"

"Table 7. Software Requirements for the Siebel Developer Web Client" lists Microsoft Windows XP Professional SP2+ as required software. Does this mean that Siebel's latest release cannot run on Windows Vista? I hope not.

I hope that it's just something I did wrong, because it would be disappointing to learn that the Windows 7 Beta has already been released, and Siebel still hasn't found a way to get their Tools and Mobile Client to run on Windows Vista.

If anyone knows how to get Siebel 8.1.1.0 running on Windows Vista, drop me a line, and I'll update this posting. Meanwhile, I'll be playing with 8.1.1.0 on my other machine which is running Windows XP SP2. And FYI, it's running just fine on that.

Thursday, February 5, 2009

eScript Date Parser Bug

The Siebel eScript date parser does not correctly recognize dates in the 12AM hour in the format HH:MM:SS AM. This is a bug in some versions of the eScript engine, affecting server scripts, but not browser scripts - since browser scripts use the web browser's javascript engine. Check out the example below.

Siebel eScript (7.7.2.6 SIA [18372]):
// incorrectly evaluates to noon
// "Sat Oct 18 12:00:00 2008"
new Date ('10/18/2008 12:00:00 AM").toString ();
JavaScript engine from IE 6.0.2900.2180.xpsp_sp2_gdr.070227-2254:
// correctly evaluates to midnight
// "Sat Oct 18 00:00:00 PDT 2008 12:00:00 AM"
new Date ('10/18/2008 12:00:00 AM").toString ();
We just got a quickfix from Oracle for this nasty little bug we found, but the fix is on our private branch. So if this is affecting you, you might want to request it too. It took a few months between logging the SR and getting the patch delivered, so we had to work around the problem manually. We created a function to turn a string into a date object. In case you need it, here it is:
function StringToDate (sDateString)
{ // takes a date string, parses it using the
  // escript date parser, and returns it as a
  // date object. also works around a known
  // defect with the escript date parser
  // (siebel sr 3-765130491)

  var dt = new Date (sDateString);

  // address siebel product defect where
  // 12:XX AM dates get translated to 12:XX PM
  // in the date constructor
  if (/^[^:]*12(:\d{1,2}){0,2}\s*[Aa][Mm]/.test (sDateString))
  {
    // the time appears to be 12:XX AM,
    // so verify it
    if (dt.getHours () == 12)
    {
      // the hours are off, so fix it
      dt.setHours (0);
    }
  }

  return (dt);
}
I wonder if this problem occurs with date formats from other locales... In case you didn't know, I'm in the US.