Without running it, what does the following chunk of code print?
Long a = new Long(4); Long b = new Long(4); System.out.println(a == b); System.out.println(a.longValue() == b); System.out.println(a.longValue() == b.longValue());
Why?
Without running it, what does the following chunk of code print?
Long a = new Long(4); Long b = new Long(4); System.out.println(a == b); System.out.println(a.longValue() == b); System.out.println(a.longValue() == b.longValue());
Why?
2 commentsThe kid developed a pretty nasty rash of unknown origin after dinner today, so we called the on-call advice nurse. After a few not-so-fruitful rounds of questions about what the rash looked like, I grabbed a couple of digital pictures, posted them to Flickr, and gave the nurse the URL over the phone. (I took the pictures down after the call was over.) A cool bath followed by some hydrocortisone, and peace returned to our household. No Bendryl for the kid if we can avoid it, as it seems to function as a strong stimulant in her case; the one time we gave it to her at 10PM, she literally ran laps around her room for four hours...
This brings to mind an idea for a software business — branded, private, secure photosharing portals for physician's offices and hospitals that provide advice over the phone. The portal would provide secure, permanent storage for the images and integration with the medical record system.
0 commentsWS-BPEL is finally in public review. John Evdemon has links and additional information on his blog.
Every time I talked with Maciej about what was happening and created a mental estimate of when the WS-BPEL spec would finally be out, I added a twelve-month buffer, just in case. Even then, my guesses were always early. Nonetheless, as an educated observer, I think that the process took about the right amount of time.
0 commentsEngineers have a variety of perspectives on ready-for-production, from "It works on my desktop" to "The functional and integration suites all pass" to "The theorem prover and state space traversal heuristics assert that it's perfect". Ultimately, "Are we ready to go to production?" is the wrong question. The right questions are more business-oriented:
The first question is for the business owner to answer outside of the context of what the development team has to say about the state of the system. Failure is a fact, and managing the probability of a failure requires time and investment. It's the business owner's prerogative to choose the points on the curves of magnitude of customer impact and ongoing investment in development — independent of asserted outcome of the development effort. It's a bit like cooking a steak à point in that you want the software to be just barely done.
The second question is for development leads and architects to answer, both at design time and during implementation. Recovery options need to be matched to failure modes and possible inconsistencies, and failures need to be detectable other than via confused or angry customers. The design-time imperative is to pick the right design patterns — stateless when possible, idempotent always, and minimal horizontal co-footprint per unit of traffic come to mind. (I'm saying "co-footprint" because "footprint" isn't quite the right term. A customer spread across a couple of tables is no big deal, but needing to have all of the customers in a single database is constraining.) The development solution is to engineer-in instrumentation and plug-points where data or operations can be cleanly injected into the system, ideally to the point that an operator can use the system in the same ways that the system uses itself. (The body of thought on recovery-oriented computing is a good read on the subject of designing systems so that failures are just bumps in the road.)
In all practical terms, the developers are the only capable and knowledgeable operators for the system, and refining and documenting the system to the point that first-tier and second-tier support can exist is an organic process that needs to happen in response to observed issues, not a phase on a project plan. To extend the steak analogy, this would be bien cuit, which is only suitable as a chew toy for a dog or for the manufacture of footwear. In my mind, intimacy with the system is the bond that links development to operations, but just handing out pagers to software engineers without the proper groundwork is both illegitimate and destructive.
In a maxim, system failures are to be expected, but business failures are unacceptable.
1 commentWhen the Sprial Frog relationship with Universal was announced, I was tentatively intrigued and waited for the catch to come out. This is in spite of the fact that I can't think of any artists on major labels that I give a hoot about. Once the first sketchy details were out about having to watch ads, it sounded like a job for Mechanical Turk — I can have a remote human watch the ads on my behalf for a nominal fee. The idea had a certain impish appeal in that I'm certain that the advertisers wouldn't want their demographic to be people somewhere in the world who'd sit through an ad for a nickel, but it was all mooted when it the details of Spiral Frog's plans for regressive DRM came out. I'm going to have to think about other opportunities where MechTurk could provide an acceptable-cost route around other on-line annoyances.
Now, as for the obsession with DRM,...
Consumer: (in raspy falsetto) I'd like to download some music, but I don't like DRM.
Waiter: (earnestly) Well, we've got some Same-Old-Same-Old; that's got DRM, ads, music, and DRM. That's not much DRM.
Consumer: (angrily) I don't like DRM!
Chorus of Record Labels: DRM DRM DRM, D-R-M D-R-M...
0 commentsTesting is great, but instrumentation is both critically important and often ignored. After all, failures always come from untested scenarios.
Basic instrumentation (like heap data) is good, but basic instrumentation is also a bit like taking a picture of a race car. Other than from context, it's impossible to know whether it's going 200MPH or just parked in the middle of the racetrack. For example, the average velocity of a response time parameter indicates whether response times are getting longer or shorter or staying about the same, and the average rate of change of the average rate of change indicates whether a linear extrapolation is likely to miss high or low.
Here's a simple approach to get thumbnail rates of change for a
stream of values; I'll explain how to integrate it with JMX a little
later. The first ingredient is a useful little utility class that
computes the moving average of a stream of long values.
(Clearly the values can't be that large, ideally no larger than
MAX_LONG/2*size.)
public class CircularWindow {
private long sum;
private long last;
private long[] x;
private int ptr;
private int size;
private boolean full;
public CircularWindow(int size) {
x = new long[size];
this.size = size;
}
public void add(long y) {
sum += (last = y) - x[ptr];
x[ptr] = y;
if (++ptr == size) {
ptr = 0;
full = true;
}
}
public long average() {
return full?(sum/size):((ptr!=0)?(sum/ptr):sum);
}
public long last() {
return last;
}
}
It is built with the assumption that the average will be requested frequently but not necessarily every time a value is added. (If the average was requested infrequently versus the size of the buffer, it would make more sense to compute the sum only when the average was requested.)
To get at rates of change, chain up two of the windows and add values like so:
D_s.add(value - s.last()); s.add(value);
Now, what does this do? For a hint, try this:
CircularWindow x = new CircularWindow(100);
CircularWindow y = new CircularWindow(100);
CircularWindow z = new CircularWindow(100);
for (long i=0; i < 50000; ++i) {
long value = i*i;
z.add(value - y.last() - x.last());
y.add(value- x.last());
x.add(value);
if (i > 49990) {
System.out.println("x av = " + x.average());
System.out.println("y av = " + y.average());
System.out.println("z av = " + z.average());
}
}
The series y ticks up two every time, and the z series is constant 2. It looks like the cleverly-named D_s series from above approximates the first derivative of the s series, and presuming that the values in the series come from a suitable well-behaved differentiable function, that's obvious if you write it out:
D_s(n+1) ~ (s(n+1) - s(n))/((n+1) - n) = s(n+1) - s(n)
The main window and the second window for tracking the rate of change can be encapsulated conveniently:
public class VelocityWindow {
private CircularWindow s;
private CircularWindow D_s;
public VelocityWindow(int size) {
s = new CircularWindow(size);
D_s = new CircularWindow(size);
}
public void add(long x) {
D_s.add(x - s.last());
s.add(x);
}
public long average() {
return s.average();
}
public long velocity() {
return D_s.average();
}
public long ticksToClear() {
if (D_s.average >= 0) return -1;
return s.last() / D_s.average();
}
}
The fully reusable path for integration into an application's JMX
instrumentation is via a MonitorMBean
implementation. A MonitorMBean typically uses a timer
(e.g., a TimerTask)
to sample an attribute and then either exposes attributes or fires
notifications. (The GaugeMonitor
is similar in flavor but not really the same thing.)
I haven't ever gotten around to taking the
MonitorMBean approach, since the quick and dirty path is
simply to embed the VelocityWindow directly in the MBean
and expose average and velocity as
attributes. Another derived metric that is useful when tracking
backlogs is ticks to clear, which would either be infinite if
D_s.average() is non-negative or
-1*s.last()/D_s.average() otherwise.
1 comment
I got a SPAM this weekend for "Blogger and Podcaster Magazine". In all likelihood, this is just a case of someone identifying a demographic where the advertising revenues from a magazine could exceed the cost of printing and mailing a bunch of free copies, but this strikes me as a case of unclear on the concept. A hard copy, snail-mailed magazine targeted at people who are deeply involved in blogging, podcasting, and other purely on-line activities? That's just the kind of content that you can't find on-line... [sic.]
I don't get it, but maybe that's just me.
0 comments