abm (14) amp (18) ascape (6) biomed (6) business (22) butterflyzer (9) dharma (12) eclipse (62) emf (7) graphics (10) ip (8) java (35) life (5) osx (13) science (13) web (6) xpand (5)

Tuesday, November 3, 2009

Zest with a Twist

I found this googling a bit on the history of Zest soap, a product of Proctor & Gamble, while committing a bunch of stuff to sourceforge's god-awful slow SVN servers. You were perhaps thinking that this was a post on that Eclipse GEF project also referred to as Zest? Time to broaden our horizons a bit and explore the bleeding edge of consumer culture. Which brings to my mind Gillette, in the process subjecting me (and now you) to that little wince that we associate with razors and blood. But Gillette's products hardly ever leave you bleeding. I wouldn't make a very good add copy-writer, I guess. Though, I mean, yeah, fully disposable razors really make me wince but is a keeper razor with disposable blades truly the best a man can get? A bit of a dystopic message, huh?


But here's a much more uplifting one. I think. Well maybe not, but at least it does kind of make you think:


Any guesses what that's about? But first, back to the soap. (Actually, it's not really soap, it's detergent, but that doesn't sound like something we would want to put on our bodies, so it's better to call it soap.) I'm currently kind of a Dr. Bronner's guy, so perhaps I'm not qualified to make a judgement about the merits of this particular branding, but I do have a few thoughts here..

  • Was there something that P&G felt people were missing from the whole Zest experience?

  • If so, is it likely that it was the experience of smelling like a Mango and a Tangerine?

  • Is that say second best to the experience of using a Gillette razor?

  • What are these stimulating effects they speak of? I mean, that one actually sounds like a real selling point to me. They should hype that one even more, because personally the scent thing isn't drawing me in. Maybe I'm more of a AXE guy. On second thought, yech, maybe not.

  • If I were a marketing genius could I figure out a way to do the whole give away the razor and sell the blades thing only with soap? Because I can't figure out how to do that with Open Source software.

  • That bit about Open Source was just an attempt to keep folks who think there might be a tech component buried in here reading. I'll give you a hint about that.. The latest behavioral economics research suggests that contrary to the assumptions of classical economics, people vastly over-estimate the value of sunk costs. (Truthfully, I'm not aware of any actual research on that, but my guess is that it exists.)

  • I wonder if the P&G guys ever do pro bono work? As I intimated in my last blog post, academic conferences and societies could sure use a lot of help in that regard. It's all about branding folks!

  • Perhaps I am a marketing genius, and this whole Eclipse thing was just a way of ingratiating myself into a group of soap use opinion leaders so that I can put the viral marketing wammy on them. (If you trust folks like us to recommend a new computer to you, perhaps you'd trust us to recommend other consumer products. Recent consumer market segmentation reveals that those old stereotypes of the computer guy -- with the doritos droppings flecking his week old beard stubble, slightly smelly armpits, and a vaguely hostile or at minimum subtly patronizing attitude -- have gone by the way side, to be replaced by the image of that nice young man on the Mac ads. Oh how grateful I am to Apple marketing in so many ways. True story: one of the first things my wife asked me when we first met on a buddhist internet dating site (I kid you not) was wether I was a Mac guy or PC guy. She's a lawyer, not a techy, but I just had the realization that what she was really asking me was wether I was like that nice guy or more like John Hodgman. In fact, if you added Hodgman's caustic wit to Mac guy's lovable and so approachable mien you'd have me to a tee. Or at least that was what I was advertising...


And, yep as most of you probably guessed, the profound message above comes from the mangos and razor blades folks. Making fun of advertising is like shooting fish in a barrel, but it does make me think about how we construct our views about reality. I mean, this stuff works, and our perceptions about the world around us are pretty much constructed by our own preconceptions even when they aren't so coarsely engineered. The thoughts we carry around with us and give so much importance to aren't really that much more sophisticated then the message above, but we still end up giving them much more credibility than we do our own direct experience. Weird..

Anyway, here's the part about GEF Zest. You folks that stuck it out must be feeling pretty good about your choice now, eh? That's the thing. Any heuristic -- say the one about sunk costs -- ends up being wrong eventually.

Zest has been both a source of joy and sorrow for me as I've worked with it over the last year or two. I'm thinking that that experience is pretty common among those of us who are spending a lot of time with relatively bleeding edge software. We're sucked in by tremendous potential for offering functionality that we wouldn't have been able to do otherwise. We make a ton of progress really rapidly. Then we run into some limitations, and spend weeks hacking around trying to get rather simple things working. It never fails to amaze me how quickly I can get complicated and powerful things working and then how long it takes to refine those things down to something that I actually feel good about presenting to end-users. The question for me always comes down to wether the enormous productivity and feature gains are worth the (seemingly inevitable to me at the moment) pain. Why, it's just like when I was making the decision wether to switch from Mach II to Mach IV. And should I get the kind where you can put a battery in it? No, it's actually nothing like that.

Zest is a particularly interesting case in point, because of a design philosophy that favors encapsulation of functionality and ease of use for common issues over flexibility and integration with other components. For example, the first versions made it really impossible to use one's own GEF figures without extensive hacking -- essentially copying a significant part of the source tree. That has since been changed -- thanks Ian! -- and there is now a nice feature provider capability. But it seems like the default API decisions always err toward the side of marking things as not accessible, to the point of deliberately locking down some functionality that could be exposed. There are really good arguments for doing things this way. Some of this graph stuff is inherently complicated and difficult to grok, and often it doesn't make sense to expose a bunch of stuff that people won't be able to override properly anyway. But it can get really frustrating especially when doing implementations that are extending the framework.

One thing I've really been struggling with since I started using Zest is the issue of layout sizing. Zest's approach is to try to fit the graph into the space allotted, which makes sense for the majority of cases. But I want the layout to grab the amount of space that it would ideally need. What I've ended up doing is writing my own layout progress monitor that dynamically adjusts the size of the underlying scroll pane as a result of the outcome of the zest layout. If the graph nodes are too scrunched together, then I increase the size in increments that are my best guess of how much more space the layout needs.

So this ends up being a sort of weird approach as I've basically got two layouts playing off of each other. I've spent quite a bit of time mucking with it, and it's still not doing exactly what I want, but it's getting closer. I've been trying to also get the layout to shrink when the layout is too big, but that hasn't been working so well. I've been ending up with the two algorithms fighting each other so that the graph layout ends up yo-yoing back and forth between two sizes. Pretty funny the first time it happened, but it's getting a bit old now. Anyway, for those of you who want to try this out, the core code is below.

            Graph graph = this.visualEditor.getBehaviorViewer().getGraphControl();
List<Rectangle> figures = new ArrayList<Rectangle>();
for (Object node : graph.getNodes()) {
GraphNode graphNode = (GraphNode) node;
Rectangle newRectangle = new Rectangle(graphNode.getLocation(), graphNode.getSize());
figures.add(newRectangle.expand(insets));
}
List<Rectangle> remaning = new ArrayList<Rectangle>(figures);
Map<Integer, Collection<Integer>> columnIntersects = new HashMap<Integer, Collection<Integer>>();
Map<Integer, Collection<Integer>> rowIntersects = new HashMap<Integer, Collection<Integer>>();
for (Rectangle rectangle1 : figures) {
remaning.remove(rectangle1);
for (Rectangle rectangle2 : remaning) {
Rectangle r1 = new Rectangle(rectangle1);
Rectangle r2 = new Rectangle(rectangle2);
Rectangle intersect = r1.intersect(r2);

if (rectangle1.y != rectangle2.y) {
if (intersect.height > 0) {
Collection<Integer> column = columnIntersects.get(intersect.x);
if (column == null) {
column = new ArrayList<Integer>();
columnIntersects.put(intersect.x, column);
}
column.add(intersect.height);
}
}
if (rectangle1.x != rectangle2.x && intersect.width > 0) {
Collection<Integer> row = rowIntersects.get(intersect.y);
if (row == null) {
row = new ArrayList<Integer>();
rowIntersects.put(intersect.y, row);
}
row.add(intersect.width);
}
}
}
int uniqueColumns = columnIntersects.keySet().size();
int uniqueRows = rowIntersects.keySet().size();
int maxOverlapWidth = 0;
int maxOverlapHeight = 0;
for (Entry<Integer, Collection<Integer>> entry : columnIntersects.entrySet()) {
int overlapHeight = 0;
for (Integer columnIntersect : entry.getValue()) {
if (columnIntersect > overlapHeight) {
overlapHeight = columnIntersect;
}
}
overlapHeight = overlapHeight * uniqueRows;
if (overlapHeight > maxOverlapHeight) {
maxOverlapHeight = overlapHeight;
}
}
for (Entry<Integer, Collection<Integer>> entry : rowIntersects.entrySet()) {
int overlapWidth = 0;
for (Integer rowIntersect : entry.getValue()) {
if (rowIntersect > overlapWidth) {
overlapWidth = rowIntersect;
}
}
overlapWidth = overlapWidth * uniqueColumns;
if (overlapWidth > maxOverlapWidth) {
maxOverlapWidth = overlapWidth;
}
}
if (maxOverlapWidth != 0 || maxOverlapHeight != 0) {
nextSize.setSize(new Dimension(nextSize.width + maxOverlapWidth, nextSize.height + maxOverlapHeight));
visualEditor.getBehaviorViewer().applyLayout();
} else {
resizing = false;
}


While it sounds like I'm mostly complaining, in fact on balance Zest has been an enormously cool component and one that I've relied really heavily on. That reliance does bring an extra level of frustration when the development and support level isn't ideal. But the benefits still far outweigh the cots.

What did any of that have to do with soap? Nothing.

4 comments:

  1. Thanks for the post on Zest :-).

    A few points.
    1. Regarding API lockdown -- when I first started with Zest (@ eclipse) the only thing I knew was that Eclipse was very careful about API. Not knowing any better, I locked a lot of things down. Part of this years work on Zest is to open it up a bit and define some more API. Actually, we are almost entirely binary compatible and I'm looking at the few places we're not. (Let's make sure your use-case still works)

    2. This summer we had some excellent work done though Summer of Code, especially on our layouts. They are much better now and much easier to maintain.

    3. Your specific case is something I've always wanted to do. Maybe we could make this a general solution and bring it to Zest.

    Thanks so much! Zest has been such an interesting learning experience for me.

    I think it's time for a blog post :-).

    ReplyDelete
  2. On reflection, lockdown is a pretty hefty word to be throwing around. :) It is simply very hard to make a judgement about how much to hide and how much to reveal, and you make a really interesting point. There is some kind of interesting co-adaption between the cultural expectations of a platform / community and the level of hiding we want to do. Like, when to mark something as internal, and then should we actually not export the package? I've been trying to come to term with this stuff myself as I build out the AMP API. In my case, I have it easy..because AMP is essentially defining a platform, I don't really have to worry about the implementation; everything is private except for the interface providers. With Zest there are many more decisions to make. And it has been really nice to see things open up. The feature stuff allowed me to do some really (I think) neat stuff that I'll try to put a demo together for real soon.

    I'm not sure that the code is really that general -- it's designed to work with the tree layouts and so makes some assumptions about how things are oriented vertically -- but I'd sure like to help make this more general. I had thought that this was a really simple thing to do within the tree algorithm itself, but after mucking around with it I'm not so sure.

    I'm just working with the current galileo release so it sounds like I should be switching to the development version to try some of the new features out.

    ReplyDelete
  3. I'm going through the CQs process to get the SoC work in, however, we will likely make both versions available with Helios. I'm thinking of having both a Zest 1.2 and Zest 2.0.

    ReplyDelete
  4. Hi Ian,

    Sounds like you guys have made a lot of progress! I'm anxious to see it and I don't actually have an EPL requirement for this experimental stuff. Is the code available at googlecode?

    Specifically, are the any changes to tree layouts in either 1.2 or 2.0? I'd like a version that I can use to favor depth over width..the current tree layout provides a pretty binary flavor, where node close to the root seem to be layed out equidistant even when some don't have child nodes. I have an example I posted to the GEF newsgroup. (http://www.eclipse.org/forums/index.php?t=msg&th=155853&start=0&S=40a7e4ba93fd93df81bb1e24a5256b68) Ironically, I think I have a simpler case then the general tree layout problem so it might make sense for me to try to roll my own implementation for this..

    cheers,

    Miles

    ReplyDelete

Popular Posts

Recent Tweets

    follow me on Twitter