Hibernate Session Management 4

Posted by wsargent Fri, 30 Dec 2005 08:28:00 GMT

I’m having trouble with Hibernate now. In particular, I’m having trouble with Spring and Hibernate’s idea of managing transactions. Hibernate doesn’t use the JTA for transaction management: instead, it uses a Session object that looks a lot like a UserTransaction, and is defined as that period when the objects that you get are actually connected to the database. So you call

session.beginTransaction();
Post post = getPost();
// calling post.getComments() will get real comment objects from Hibernate here... session.commit();

// You can’t call getComments() here because there’s no active session. // You’ll die with a LazyInitializationException. post.getComments();

You might think that Hibernate would open a new connection or session if it has to lazy load associations. This is a bad idea, because you can get a ton of open connections.

You might think that Hibernate would keep a session open on a thread, so you can do many operations in a single transaction. Well, it can. If you can get hold of a sessionFactory, you can call sessionFactory.getCurrentSession() and it will return you the ThreadLocal session back.

Except that I’m using a JTA transaction model in a J2EE web application. Oops.

EDIT: ARGH. I misread the error message. JTA works fine, but Hibernate needs a current JTA transaction and I didn’t have that.

You might think that Hibernate would have a servlet filter that would open up a single transaction at the beginning of a page render and close it when the page finished rendering. And, well, Spring does. Hibernate is a persistence solution, so from what I can tell, they’ve essentially washed their hands of Spring. But Spring has OpenSessionInViewFilter.

However, I can’t get OpenSessionInView to work. Here’s my code:

public String execute() throws Exception {
  // this is a Post object extracted by another action and set on this one
  Post post = getPost();
  String parsedPost = parsePost(post);
  setParsedPost(parsedPost);
}

// Get various lazy loaded objects if they exist (we only want to pull them in if we are // displaying posts) public String parsePost(Post pPost) { ... Map<String, Media> media = pPost.getMedia(); ... List comments = pPost.getComments(); }

and here’s what happens when I try it:

2005-12-29 23:38:27,515 DEBUG [com.tersesystems.blog.dao.hibernate.HibernatePostDAO] - <findPublishedPage: pPage = 0, pPageSize = 5>
2005-12-29 23:38:27,531 DEBUG [org.springframework.orm.hibernate3.SessionFactoryUtils] - <Opening Hibernate Session>
2005-12-29 23:38:27,625 DEBUG [org.springframework.orm.hibernate3.HibernateTemplate] - <Eagerly flushing Hibernate session>
2005-12-29 23:38:27,640 DEBUG [org.springframework.orm.hibernate3.SessionFactoryUtils] - <Closing Hibernate Session>
2005-12-29 23:38:27,640 DEBUG [com.tersesystems.blog.dao.hibernate.HibernatePostDAO] - <findPublishedPage: posts = [[...]>
2005-12-29 23:38:27,765 DEBUG [org.springframework.orm.hibernate3.SessionFactoryUtils] - <Opening Hibernate Session>
2005-12-29 23:38:27,765 DEBUG [org.springframework.orm.hibernate3.HibernateTemplate] - <Eagerly flushing Hibernate session>
2005-12-29 23:38:27,765 DEBUG [org.springframework.orm.hibernate3.SessionFactoryUtils] - <Closing Hibernate Session>
2005-12-29 23:38:27,765 ERROR [org.hibernate.LazyInitializationException] - <could not initialize proxy - the owning Session was closed>
org.hibernate.LazyInitializationException: could not initialize proxy - the owning Session was closed

    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:53)
    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:84)
    at org.hibernate.proxy.CGLIBLazyInitializer.intercept(CGLIBLazyInitializer.java:134)
    at com.tersesystems.blog.dao.hibernate.PostImpl$$EnhancerByCGLIB$$9066ad74.toString(&lt;generated&gt;)
    at java.lang.String.valueOf(String.java:2577)
    at java.lang.StringBuilder.append(StringBuilder.java:116)
    at com.tersesystems.blog.action.ParsePostAction.parse(ParsePostAction.java:108)
    at com.tersesystems.blog.action.ParsePostAction.execute(ParsePostAction.java:137)
    at com.opensymphony.xwork.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:283) </pre></div>

What this seems to say is that OpenSessionInView will only keep a session open in an object that extends from HibernateDaoSupport, and uses a HibernateTemplate. I tried overriding getHibernateTemplate() so I could add better logging to it, but someone’s declared it final and private. Which is unfriendly.

Theoretically the way to do this is to use the HibernateCommentDAO and have it take in a postId, but that seems silly to me. I don’t want to have to define a transaction explicitly around every action. I just want to be able to call post.getComments() anywhere in the page that I’m rendering, which I should be able to do.

I’d write my own filter, but I don’t want to mess with the existing Session support that exists. I started writing a filter behind the OpenSessionInView one and found out that I had two different instances of sessionFactory. I don’t know how the heck I managed that one.

Webwork Actions in a Nutshell 8

Posted by wsargent Fri, 23 Dec 2005 06:38:00 GMT

Today, I talk about webwork actions.

There are two parts to webwork actions. There’s the JSP, and there is the Java class. The JSP looks like this:

<ww:action id="myActionObj" name="'myActionType'"/>

For the sake of clarity, I haven’t shown how the name attribute wires through XWork to Spring: there’s a diagram in an earlier post. I don’t know why you need single quotes around it.

The Java class looks like this:

import com.opensymphony.xwork.ActionSupport;

public class MyAction extends ActionSupport {

public String execute() 
{
return SUCCESS;
}

}

A webwork action is roughly equivalent to a droplet, only instead of calling service(), it calls execute(). However, there is an important difference between droplets and actions. An ATG droplet is typically stateless and global: you define a single component in Nucleus, set up all the global references in the properties file, and pull all the session scoped and request scoped objects through request.resolveName(“myComponent”).

As best as I can tell, Webwork actions are request scoped. That is, there’s a new instance of the class created on every request. This is because instead of setting output parameters on DynamoHttpServletRequest, the properties of the action itself are used as output parameters.

This means that where you would normally do:

public void service(DynamoHttpServletRequest pRequest, DynamoHttpServletResponse pResponse)

  throws IOException, ServletException 

{

pRequest.setParameter("value", "I am an output parameter");
pRequest.serviceParameter("output", pRequest, pResponse);

}

you would do:

public String execute()
{
   setValue("I am an output parameter");
   return SUCCESS;
}

and then in the JSP page you would do:

<ww:action id="myActionObj" name="'myActionType'"/>
<ww:property value="#myActionObj.value"/>

Note that the action object hangs around at least for the lifetime of the page render. If you are using the same action multiple times in the same page, you should use different ids.

So that takes care of output parameters. How do you get input into a Webwork action?

You use the ActionContext class. This class uses ThreadLocal behind the scenes to give you access to your request and session state.

import com.opensymphony.webwork.ServletActionContext;
import com.opensymphony.xwork.ActionContext;
import com.opensymphony.xwork.ActionSupport;
import javax.servlet.http.;
import java.util.;

public class MyAction extends ActionSupport {

public String execute()
{
    // if you want raw access to the request...
    HttpServletRequest request = ServletActionContext.getRequest();
    Map httpParameters = request.getParameters();

    // ... or if you want to remove any dependency on servlets...
    ActionContext context = ActionContext.getContext();
    Map parameters = context.getParameters();

return SUCCESS;
}

}

Now, the following section I can’t speak to. Sebastiano defined the following interceptors here in xwork.xml, so I have no idea what they do or why he defined it:

   <interceptors>

  […]

  &lt;!-- a small stack used for the actions in ww:action tags --&gt;
  &lt;interceptor-stack name="simpleStack"&gt;
    &lt;interceptor-ref name="prepare" /&gt;
    &lt;interceptor-ref name="servlet-config" /&gt;
    &lt;interceptor-ref name="params" /&gt;
  &lt;/interceptor-stack&gt;
&lt;/interceptors&gt;

&lt;!--
   Anything you would normally use for display is defined with the simple stack. 
   Here, we count an array.
--&gt;    
&lt;action name="countArrayAction" class="countArrayAction"&gt;
  &lt;interceptor-ref name="simpleStack"&gt;&lt;/interceptor-ref&gt;
&lt;/action&gt;

We can then get down to counting how many items are in an array. Using this pattern, parameters can be defined explicitly:

<ww:action id="countArrayObj" name="'countArrayAction'">
   <ww:param name="'array'" value="#someArray"/>
</ww:action>

The code for this goes:

public String execute()
{

ActionContext context = ActionContext.getContext();
Map parameters = context.getParameters();

// Note that while this is a contrived example, Webwork does like to return 
// string parameters as String[], even if there's only one of them passed in.
Object[] randomParamArray = (Object[]) parameters.get("array");

int count = (randomArray == null) 0 ? randomArray.length;
setCount(count);

return SUCCESS;

}

And that’s Webwork actions in a nutshell.

Webwork and OGNL 6

Posted by wsargent Wed, 21 Dec 2005 06:38:00 GMT

I understand Webwork now. For a while I was completely blocked. The documentation on the wiki just didn’t give me enough information to really understand what was going.

Finally, I wrote to Sebastiano Pilla and asked for help. He sent me some source code that showed me how to use Webwork in practice, and I was able to use that as a model. I still don’t understand some areas of Webwork, but I understand it well enough.

What I was meaning to do was:

<dsp:droplet name="DisplayPosts">
  <dsp:oparam name="output">

 &lt;dsp:droplet name="ForEach"&gt;
   &lt;dsp:param name="array" param="posts"/&gt;
   &lt;dsp:param name="elementName" value="item"/&gt;
   &lt;dsp:oparam name="output"&gt;
       &lt;dsp:valueof param="item.title"/&gt; &lt;br /&gt;
       &lt;dsp:valueof param="item.body"/&gt;
   &lt;/dsp:oparam&gt;
 &lt;/dsp:droplet&gt;

</dsp:oparam> </dsp:droplet>

or using JSTL:

<dsp:droplet name="DisplayPosts">
  <dsp:oparam name="output">

 &lt;!-- convert between DSP and JSTL --&gt;
 &lt;dspel:getvalueof var="postz" param="posts"&gt;
 &lt;c:forEach var="item" items="${postz}"&gt;
   &lt;c:out value="${item.title}"/&gt; &lt;br /&gt;    
   &lt;c:out value="${item.body}"/&gt; 
  &lt;/c:forEach&gt;
 &lt;/dspel:getvalueof&gt;

</dsp:oparam> </dsp:droplet>

Webwork does not expose objects to JSTL by default. It says it can, but nothing happened when I tried:

<ww:action name="'displayPosts'" id="displayPostsObj"/>
<ww:set name="postz" value="#displayPostsObj.posts" scope="page"/>
<c:forEach var="item" items="${postz}">

&lt;c:out value="${item.title}"/&gt; &lt;br /&gt;    
&lt;c:out value="${item.body}"/&gt;

</c:forEach>

Webwork uses OGNL to expose data. Which means it has almost nothing in common with either JSTL objects or DSP droplets. So the correct way of doing this in Webwork is:

<ww:action name="'displayPosts'" id="displayPostsObj" />
<ww:set name="postz" value="#displayPostsObj.posts" scope="page"/>
<ww:iterator value="#postz">
  <ww:property value="title"/> <br />
  <ww:property value="body"/>
</ww:iterator>

This works. But it’s not using the same model that you would see in JSTL. Whereas DSP is scope based (params only exist in oparam tags) and JSTL is mostly flat, OGNL is stack based. So when you iterate over a collection, it takes the element and puts it onto the value stack. When you access properties without the # syntax, it assumes you’re talking about the first element on the stack. So <ww:property value=”title”/> gets item.title, and so on. If anything, it’s like $_ in Perl. It’s a little bit of syntax magic.

But what if you want to get the item itself? Well, then you have to understand OGNL. Webwork itself doesn’t document OGNL: you have to go to the OGNL web site to do that.

<ww:iterator value="#postz">
   <ww:set name="post" value="[0]"/>
   Post: <ww:property value="#post"/>
</ww:iterator>

In OGNL, [0] returns the item itself. I don’t know why.

The # syntax can again be understood by reference to Perl: any time you try to get something that isn’t on the default stack, you have to specify it with # beforehand to indicate it’s a variable. There are a number of variables that are defined in Webwork; #parameters, #application, and so on. If you have http://example.org/myapp/index.jsp?foo=bar and you call <ww:property value=”#parameters.foo”/>, you can get “bar”. Instead of <%= request.getContextPath %>, you can do <ww:property value=”#request.contextPath”/>.

The date formatting support in Webwork is threadbare. They suggest that you use the <ww:text> tag, but that requires that you parameterize it into a ResourceBundle. There’s nothing like a DSP tag converter as far as I can tell. The most effective way of formatting a date I’ve found is:

<%@ taglib uri="webwork" prefix="ww" %>
<%@ page import="com.opensymphony.xwork.util.OgnlValueStack" %>
<%@ page import="java.util." %>
<%@ page import="com.tersesystems.blog.util." %>
Assume the code's inside an iterator and timestamp is a property of the element...
<%
  OgnlValueStack stack = (OgnlValueStack)request.getAttribute("webwork.valueStack");
  Date date = (Date) stack.findValue("timestamp");
  String formattedDate = DateUtils.format("M/d/yy h:mm aa", date);
%>

(If you do something like this yourself, make sure you get the synchronization right. DateFormat isn’t thread-safe.)

If you want to do something more complex in OGNL, you need to know the internal model down cold. Say that you want to dereference an element inside a map using a specific key in Webwork. You’d think that using the [0] syntax described earlier would work:

<ww:iterator value="#myObject.keyList">

&lt;ww:set name="element" value="#myObject.map[[0]]"/&gt;

</ww:iterator>

But this doesn’t work. (Nope, still not sure why.) The way to do this is:

<ww:iterator value="#myObject.keyList">
  <ww:set name="element" value="#myObject.map[top]"/>
</ww:iterator>

I found this from the forums. I don’t know what “top” means. I imagine it’s some special syntax that tells OGNL to peek at the stack, but I can’t see it documented anywhere. (EDIT: docs here. Apparently it’s part of XWork.)

OGNL has interesting type conversion as well. For example, you set pages=3 as a query parameter. You’d expect #parameters.pages[0] - 1 == 2, and it does. But #parameters.pages[0] + 1 == 31. The only way I found to get around this was to cast to an int by hand, which meant:

<ww:if test="#displayPostsObj.page.nextPage == true">
 <ww:url id="pastURL" value="/index.jsp"><ww:param name="'page'" value="@java.lang.Integer@parseInt(#pageNum) + 1"/></ww:url>
 <a href="<ww:property value="#pastURL"/>">Past</a>
</ww:if>

That’s enough for now about Webwork syntax. Next post, I go into Webwork actions.

New Hackystat out

Posted by wsargent Wed, 07 Dec 2005 05:22:00 GMT

Hackystat 7.0 has been released. It follows the Personal Software Process model, but attempts to automate as much metrics collection as possible. I wrote about Hackystat before and have since had it working and collecting metrics for me. I’ve never gotten it implemented by management, but it’s the best way of tracking project status that I’m aware of. (Sidenote: if anyone uses Hackystat in the field on real shipping product, I’d love to hear your experience with it.)

There’s no explicit web page that lists the changes made, but the mailing list says:

* Complete refactoring of system into 63 modules organized into four subsystems.
* Complete redesign of the build system, with performance, maintainability, and extensibility improvements.
* Support for evolution in sensor data types.
* New Sensor Data Type: “Code Issue”
* New sensors for: PMD, Emma, FindBugs, Checkstyle, Subversion
* Stable releases and nightly builds are now binary distributions (30 MB rather than 180 MB)
* Improved property file design (hackystat.build.properties and hackystat.site.properties)
* CCCC sensor now works with standard version of CCCC.
* Hackystat is now Java5 compliant (backward compatible to JDK 1.4.2)
* Hackystat server now compatible with Tomcat 5.5
* Jira sensor works with SSL.
* Hackystat source repository now hosted using Subversion.
* And many more things, as documented in Jira here

You can download Hackystat at http://www.hackystat.org/.

AYE 2005, part 3 1

Posted by wsargent Mon, 05 Dec 2005 14:16:00 GMT

Wednesday morning, I woke up and thought about the conversation that I had last night.

I knew that some people thought that rationality was beside the point. I knew that there were some people who were more interested in relationships than in ideas. But this was the first time that somebody had told me that the world itself was not a logical place. And not only that, but that the world should not be a logical place. I found (and still find) the idea unsettling. More than that, I found the perceived disconnect between relationships and logic unsettling. The idea that relationships don’t have their own internal logic and rules. The idea that in the world of relationships, not only did logic not apply, but was irrelevant and annoying.

I thought about that world. It was by far the best explanation of why software projects fail that I ever heard.

It explains why software projects get started. Software projects don’t get started out of anything like a cost benefit analysis. The way people feel causes software projects to start. People start projects because they’re frustrated. They start projects because they hope. And when computer geeks come in and start asking a bunch of random useless or pointless questions that get in the way of the grand vision, that scribble all over delicately maintained relationships and contribute nothing… well, it’s no wonder. Hope and fear. In the beginning, the hope compels. In the end, the fear paralyses.

The fundamental disconnect is miscommunication. Many times a team will recognize that the meaning is being lost in the message. But the problem isn’t simply more meetings and more bullet points. A business or marketing team will be composed of NFs. A technical team will be composed of NTs. To understand each other, it is not enough to use different words or forego jargon. It is necessary to understand the other’s frame of reference.

A technical team has to be able to speak an emotional language. The technical team has to understand the hopes and fears of the business team, and address those first and foremost. It has to understand that the business team may view what they do as irrelevant to the world that they inhabit. Perhaps it’s overblown for a meeting to start by asking everyone how they feel (yes, I read Software For Your Head), but it does seem like recognition of the emotional dynamics in a project is missing. And for the business team, they don’t realize how as soon as they’ve started a software project, they’re not just dealing with different people. They’ve entered a different world.

At any rate, it does a lot of good for me to realize that explaining “why” to some people doesn’t make them feel any better.

With all this buzzing in my head, I barely remember that it was lunch until I saw the line of people under the pagoda. I talked to Johanna Rothman about the business of consulting and marketing, and again found myself struggling to keep up, if only because Johanna dispensed information at such a rate that I couldn’t write it down fast enough.

Finally there was the last session of the conference. This was “Management behind Closed Doors,” reflecting the new book that Esther and Johanna had published. They started off the session by discussing their own experience. Esther wrote code. She found that she was good at writing code, but found that different rules applied to management. We went through an exercise that split teams up into workers and managers. The workers had to build origami. More complicated origami took longer, but was sold for more. The managers had to get resources for their workers (paper), resolve concerns, and give status updates and provide coaching.

I elected to become a manager. Meetings were called every three minutes, and we were given different strategies and changes of leadership. In short, complete chaos. I thought that I would hate it, but I found that I actually loved keeping track of everything and exploring different avenues to resolve conflicting demands.

The second time the exercise was held, I became a worker. There were no meetings held. Teams worked together to ensure that the theory of origami was well understood, and the work environment was relaxed and sane. At the end of the exercise, far more origami had been produced despite less visible management from the top.

After that, we talked about why businesses are the way they are. But at that point I had to run to catch the SuperShuttle, so I didn’t play attention as much as everyone else.

I think that AYE 2005 was worth it. I met many interesting people, and had conversations with people who thought I was interesting. Which is always nice. More importantly, I came away with the new understanding of the methods we use in the field and the ideas that we have in our heads as we use those methods. And finally, I came away with a better understanding of myself. And I’ll leave it at that.

AYE 2005, part 2 2

Posted by wsargent Fri, 02 Dec 2005 05:47:00 GMT

The second day, I woke up and decided to skip the first session in favor of wandering around in a daze. Not from the sessions, but from the hallway conversations. I’d learnt something. I just wasn’t sure what yet. I checked my email, wrote up my notes. Finally decided to follow Dave Smith’s lead and got Starbucks.

The second session I went to was Reinventing Yourself, presented by Johanna Rothman and Esther Derby. I have to throw objectivity out of the window here. I think Johanna is wonderful. She’s about four feet tall, looks perfectly harmless, has a mind like a steel trap. (And Esther is nice too.)

The session started with a very interesting idea: we were asked to go through our careers from the first job we had, and mark our general job satisfaction at each point. This had some interesting repercussions, as we found that being unemployed is generally satisfying and job satisfaction may have little to do with seniority or power. (Johanna also had some interesting anecdotes about the perils of being a QA manager. I used to wonder why it was that so many companies had underpowered QA groups. The answer’s pretty simple. It’s the job of QA to tell management exactly what it doesn’t want to hear.)

Then we were asked to find a partner and talk about patterns that we see repeating in different jobs. I was paired with Sandra, and we talked about daycare centers and undervaluing ourselves. We were asked to develop three options for a career path. Given what we know about ourselves from experience, what would we pick out?

Finally, we were asked to write down what we thought we needed, and what we thought we could provide. This was an interesting exercise in itself, because it forced me to think about what I could actually provide… not from a technical perspective, but from my life experience. I had to think for a bit, and fight the urge to write “It could be that the purpose of your life is to serve as a warning to others.”

After the session was over, I had a couple of drinks with Stuart S. and Volker F. and tried to understand what it is they do for a living. Stuart explained it to me as best he could, but the context was still unclear… until I realized that Stuart and Volker are business therapists. Businesses themselves can’t need therapy, but people in a department can share a worldview and nurse grudges against other departments in much the same way as a married couple. So what Stuart does is lock people from different departments in a room together, prepare for a “frank exchange of views” and then get them to realize the other’s context and help them to agree to a better relationship.

Part of the reason this took so long is because Stuart’s language and way of thinking is so different to mine. He likes talking about Satir Training and is very comfortable with symbolism. Satir Training looks like performance art to me. And while I’m comfortable with abstract concepts, the idea of a solid object to represent a concept confuses me, as I “see” them both individually and don’t know which one to focus on.

After that, we went to dinner with Paul B. and another man. All NFs. I had a very confusing conversation that ranged from the concept of heroes to the value of reconstruction (a kind of therapy that involves 30 people, a facilitator and a fairly extensive geneology).

Finally, after we were dropped off back at the hotel, there was a conversation about the conversation. At which point I was informed that some people don’t care why something works, only that it does. Whether it’s magic, psychology or some unstated law of the universe is immaterial. In fact, the question of “why” is considered to be besides the point at best, and at worst impolite. “Why” is restrictive, uncaring, cold. It’s a question only applicable to physics, not the “real world” which consists of people and relationships.

My brain broke. To me, the “real world” is the one expressed through scientific theory. We are the result of billions of years of physics, millions of years of evolution, and the only reason we are able to have a conversation at all is because science is pinning us to the ground and giving us the brains to talk to each other. I expressed this by waving my arms through the air and babbling.

Apparently this is called “The Why Whammy.” I can see why.

Went to bed, very confused.

AYE 2005, part 1 3

Posted by wsargent Wed, 30 Nov 2005 04:48:00 GMT

People ask me how to describe AYE. It describes itself as “a conference designed to increase your effectiveness in leadership, coaching, managing, influencing and working in teams.” My own personal effort is “It’s the world’s only touchy-feely software conference.” Which is true, but doesn’t go into the central (and surprising) concept of AYE: you are supposed to get to know the people around you, as people.

In normal conferences, one person stands on a raised pedestal and pontificates, and everyone sits and takes notes. In AYE, you sit in a circle and one person faciliates. That is, one person (with decades of experience) will ask people around the room what they think, and what their experience has been with tough situations. What their attitudes are. And how they feel. It’s sort of a cross between a brainstorming session and group therapy. I suppose that’s why it’s limited to 150 people.

This has a very democratic feel to it, and it makes you far more aware of the various personages around you as people. I once saw James Gosling, in JavaOne, walk past rows of fans looking for handshakes and autographs. By contrast, Jerry Weinburg will ask if he can sit at your table and tell you stories about the APL and PL/1 programming teams.

I was very confused the first time I went to the conference. I didn’t know who these people were, or what they were doing. The first sign of learning is knowing that you’re clueless. At AYE, I felt like a newbie. Everything was so jumbled that I didn’t even know what I had learnt. But several months later, some of the things that I remembered from AYE were very useful. So I went again.

The first session I went to was interesting but I wouldn’t call it a success. It was a session about capturing requirements, but the flow of information was very much down rather than being distributed through the group as a whole, and I thought that some of the exercises were too unrealistic to be taken seriously as an analog for software development. More to the point, I wasn’t sure I agreed with the faciliator: he said that he’s never seen top down requirements implemented successfully, and not only have I seen it, I’ve done it myself. So that didn’t go well. But I did learn something from it.

There was an anecdote the facilitator told about his wife, a vet at a school. One of the standards for judging whether an animal is sick or not is to ask whether it is “bright” or “dull”. Students will learn what the meaning of bright and dull means through repeated trial and error (bright means roughly “everything an animal is supposed to do” and dull meaning “not doing what it should”). Eventually, the vet and the student will be able to look at any given animal and determine whether an animal is bright or dull. But they will be unable to articulate what data led them to this conclusion.

There is an obvious analogue to anyone trying to implement a system: the business users of a system will tell you that the old system is dull. And they want the new system to be bright. But they will be unable to tell you how and why, in much the same way that a fish has difficulty describing water.

Lunch was interesting. There was a four year old there, the youngest person I saw. One guy had brought his wife and kid over, and he asked me for my experience (given that I’d been last year and must have seen something worthwhile in it). So I tried to explain as best I could.

And then Ruby on Rails was discussed.

I know Aaron is interested in Ruby, for good reason. I think that Ruby has a lot to offer and that in some ways it’s a significant advance over other programming languages. But I don’t think it’s there yet. There is no decent IDE for Ruby. There are no commercial software libraries. Ruby doesn’t support boring legacy systems like DDE or CORBA. Its performance characteristics are still widely unknown. And then there’s the cold hard fact that Ruby doesn’t do anything new. There’s nothing I can do with it that I can’t do already in Perl or Java, and I just don’t find playing with new languages as fun any more. They are not major drivers in the success of a project, they don’t solve the domain issues, and they don’t provide any built-in facility for dealing with core recurring issues like persistence or transactions. Five years from now, Ruby will be more “standard” than Python or Tcl. But the next time I’ll look at Ruby is when the next cool “Ruby-killer” language comes out.

The coffee was terrible, so Dave Smith drove out to Starbucks and got “real” coffee. Thank you Dave. I also got to talk to some people who had flown out from England for the conference and heard some scuttlebutt (Apparently Laurent Bossovit is “big in England” – a phrase I still find culturally disconcerting but there you go.)

After lunch, the second session was The Simplest Possible Thing To Amplify Your Effectiveness. I went to this session hoping for some simple things I could do to kick a project into gear. We were given a project to do with one third of the room evaluating, one third of the room testing, and one third building. Then we were asked for input into things we did that made it work. This didn’t work for me. The tips were too low level for my liking (“Make sure all the chairs are arranged in a circle” and “Bring a pen and paper” being two I specifically remember). So I left at the lunch break.

At which point, Earl E. asked what I was looking for. I described my situation to him and he suggested I sign up for the SHAPE forum as a way to get more of a dialogue. Earl also had some more insight into the conference: he described it as more of a “teach a man how to fish” event than a “solve this problem” event.

After that conversation, I retreated back to my hotel room to recover. When I came out and got to the bar, I found Erik M., Alan F., and Josh K. engaged in a conversation.

We went to the hotel restaurant and got to talking about Agile and Extreme Programming at dinner. Josh is the single best advocate I’ve seen for Unit Testing. He’s solid, sensible, understands the weaknesses and strengths of unit testing in different situations, and makes his decision to unit test not out of ideology, but because he – personally – derives benefit from it.

And then Jerry Weinburg came up and asked if he could join us. He regaled us with tales of the First Days of Computing and gave some useful feedback on the value of certification (he’s against it) and his experience with large corporations.

And then, it was time for bed.

Explorer tips 1

Posted by wsargent Fri, 04 Nov 2005 04:44:00 GMT

One thing I like about Windows is the Explorer. The Mac Finder pales in comparison, and although some of the Linux distributions have some nice integration, they don’t have the drag / drop and file associations down yet.

I tend to use jEdit for random file editing simply because it comes with an integrated file system view. And I’m forever skipping around bits of the tree, which is where it comes in there’s all kinds of fun stuff you can do to skip across the filesystem.

Sometimes I need access only to a branch. That’s easy enough: just tell explorer to start off from a different root.

C:\WINDOWS\explorer.exe /e,/root,d:\home\wsargent

I have a whole row of these things that I put in a Windows toolbar:

explorer

I also use Zsh for the command line, and various symbolic links and mounts to make a windows system look like a Unix one. One thing I always found frustrating was the inability to get a Zsh shell pointing to the correct directory.

Cygwin now has a new script called chere which you can install using “chere -i -s zsh” that will open up a “Zsh here” menu item when you right click on a folder. So all is good.

Flight Tips 3

Posted by wsargent Thu, 03 Nov 2005 15:37:00 GMT

How to get through security:
Never check any luggage. One handheld bag, one bag for clothing and books. Keep keys and medicine on hand at all times.
Have your boarding pass and ID in your hand when you get to security.
Wear shoes that unlace and lace up easily.
Have your belt in your luggage when you’re going to security.
As soon as you are out, take the entire plastic box and move immediately to a chair, out of flow.

How to get through your flight:
Be nice to the flight attendants. Don’t talk over the security announcement and look like you’re paying attention. Remember that although for the most part they’re stuck handing out orange juice and crackers, they’re really there to save your butt if the flight goes down.
Especially, don’t try to sneak running phones or laptops past the flight attendants. You can hide from them, but you can’t hide from the guy next to you who wonders if you may have just condemned everyone to a fiery death.
If you have enough miles, use them to get aisle seat and sit near the front. First in, first out.
If you don’t have enough miles, then dump your handheld in your seat immediately, move out of flow and start looking for empty spaces in the overhead bins. Do not engage in conversation in line. Do not talk on a cellphone – you’ll be trying to do everything one handed.
When getting out, let everyone in the row before you exit before moving out yourself. It’s a protocol, and while you can beat the system if you try, it’s in your interests to play fair.

Take some granola bars on the flight. They keep well, and they taste better than the mini-pretzels you get. I get them from Costco.

In-ear headphones are great for blocking out noise and conversation, but don’t ever have them inserted when the cabin pressure changes. It’ll hurt.

Noise cancelling earphones are more of a bust for me, at least the model that I tried. I’m going to try again with a higher quality model to see if that works better.

Studio headphones (the big ones that cover your ears) work great, but are bulky and easy to break. They’re not cheap either.

Whatever you do, do not use open headphones (most Grado models) on a flight. They don’t block the sound of music and you’ll annoy the passengers around you.

If you land and your inner ear hasn’t adjusted, boil some water in a microwave and put your ear over it. The steam will help unblock it.

Despite what you might think, q-tips are a bad match for your ears. They push earwax into your ear as much as they pull it out, and then it will calcify and make matters worse. Try warm water to melt earwax.

Eclipse Component Browser 3

Posted by wsargent Wed, 19 Oct 2005 17:14:00 GMT

For the most part I haven’t found the ATG Eclipse plugin to be of much use since it assumes that you are doing all your development from inside a deployed ATG module. However, I have found one useful thing it does: it incorporates a component browser that you can use on the pre-existing ATG modules to poke through the default settings.

Add the ATG Eclipse plugin from http://www.atg.com/eclipse to the Update Manager.

Click on New / Other / Java / ATG Wizards / Existing ATG Module:

existingwizard

Remove all the source directories when creating the project, and you’ll get an ATG module you can see in the ATG Component Browser view.

component

Click on a component, and you can see the settings of the component, plus all the different properties file that layer the component.

properties

And that’s it.