"Best practices" of ERMA

First off, I *hate* the term "best practices." That implies that I know what is best usage of this API, which isn't the case. What I'd rather say is, "here is the usage pattern I was imagining." If you feel that I'm wrong on some point, let's debate it and decide what seems right. For now, here are how I envision developers using ERMA.

ERMA mostly replaces logging code

A lot of our code has logging statements that are spread through out the system. Often these log entries have useful info that could (and should) be aggregated and reported on. Therefore, you will often find places where you want to log something in specific and report in aggregate. This is a case where using ERMA exclusively will lead to nice code improvements.

The following code is redundant. We're logging an caught exception and capturing that Exception for reporting purposes.

TransactionMonitoring m = new TransactionMonitor(getClass(), "method");
try {
    // Do work
    m.succeeded();
} catch (Exception e) {
    m.failedDueTo(e);
    log.error("Exception caught", e);
} finally {
    m.done();
}

Rather than have redundant code, let's drop the log4j specific line and use a MonitorProcessor to recreate it's work. By doing this, we are reducing our code base while keeping the same functionality.

TransactionMonitor m = new TransactionMonitor(getClass(), "method");
try {
    // Do work
    m.succeeded();
} catch (Exception e) {
    m.failedDueTo(e);  // ERMA will recreate the logged stack trace
} finally {
    m.done();
}

There are many places where there is only logging occuring. I encourage you to look at these spots and determine if that idea isn't better expressed with a Monitor. The benefit is that creating reports on ERMA instrumentation will be possible (without a code change). Therefore, in the future you may find that you are able to gain valuable insight into a production problem, for example, by writing a last minute analysis app that is powered by your ERMA instrumentation.

Don't be scared of the cancer pattern

ERMA was specifically designed to play nice with the cancer pattern: a pattern of repeating code throughout an application. How does ERMA do it?

  1. The API will be reved slowly
  2. The cancer code is only used for collecting the data
  3. The code does little harm if left in and not processed
  4. The API is kept general enough that spreading it throughout our depots should pose no problems

Now, there are definitely ways we can reduce the *amount* of boiler plate code. Annotations are one way. For example, often developers will want to instrument a method call to get basic success/failure monitoring. The way to implement that today is do to the following:

public void foo() {
    TransactionMonitor m = new TransactionMonitor(getClass(), "foo");
    try {
        // Do foo stuff
        m.succeeded();
    } finally {
        m.done();
    }
}

Thanks to Ray Krueger, we also have the option to mark methods and classes as monitored and use AOP to add instrumentation.
@Monitored
public void foo() {
    // Do foo stuff
}

Don't code to the instrumentation

By this I mean, don't treat instrumentation as a deliverable artifact of the application. Developers have enough to worry about without attempting to interlace monitoring requirements with their business requirement code. Instead, capture as much information as is necessary in as little code as possible, and save the tranformation logic for a MonitorProcessor or custom monitor.

To put a concrete example behind this idea, let's say you needed to support a report that sums all the promotional dollars we spent. You could write code like this.

EventMonitor m = new EventMonitor("event");
m.set("promotionAmount", ps.getTotalPromotions().getAmount());
m.fire();

This code will work, except if getTotalPromotions() returns null, perhaps because there were no promotions applied to that pricing solution. In this case, we get a NullPointerException and an angry developer because their monitoring code caused their application to fail. Therefore, this approach would need to morph to this.
EventMonitor m = new EventMonitor("event");
m.set("promotionAmount", ps.getTotalPromotions() != null ? ps.getTotalPromotions().getAmount() : null);
m.fire();

This idea is starting to smell. Instead, if you have a pricing solution, set the pricing solution on the monitor itself, like so.
EventMonitor m = new EventMonitor("event");
m.set("pricingSolution", ps);
m.fire();

The MonitorProcessor will have complete access to all JavaBean properties on the pricing solution, in a neat clean way. This code will even work across VMs.
public void process(Monitor m) {
    if (m.get("pricingSolution.totalPromotions") != null) {
        Amount promotionAmount = (Amount) m.get("pricingSolution.totalPromotions.amount");
    }
}
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License