Tapestry Training -- From The Source

Let me help you get your team up to speed in Tapestry ... fast. Visit howardlewisship.com for details on training, mentoring and support!

Saturday, January 29, 2005

Should MyEclipse support Tapestry? Using Spindle?

There's a discussion going on in the MyEclipse discussion forums about adding Tapestry support to MyEclipse. I haven't used MyEclipse, but I've heard of it ... it's a collection of Eclipse plugins to support J2EE development and supports a number of standards and tools, such as JSF and Hibernate.

Now, MyEclipse is inexpensive (it's based on an annual subscription, which is a fun idea), but it is proprietary and Spindle is free ... but I can't help thiking that an improved/integrated Spindle as part of MyEclipse would be a good thing, and may help offload some of Geoff's vast effort with maintaining and extending Spindle (especially if some improvements worked backwards into Spindle). I can't wait for Geoff to weigh in on this.

Wednesday, January 26, 2005

Improved HiveDoc

I've spent the last day or so, in between shoveling out my driveway, creating a new HiveDoc XSLT stylesheet with pretty darn good results. I think this is more readable, and better layed out (to support more tweaking of the CSS). Still not as pretty as Spring's equivalent (and is thiers a direct result of ours, or parallel evolution?).

TSS relaunches on Tapestry

Sure, it's old news that TheServerSide has been running on Tapestry for the last several months (I did the work myself). I also wrote an article about it, which is finally available ... at TheServerSide.

Safety First

Friends Don't Let Friends Code Struts

'Nuff said.

Monday, January 24, 2005

Airline Frustration

Sunday 3pm. Nope (2 hours on hold) -- Monday 6:40 am. Ok, REALLY, (40 minutes on hold) Monday 3:00 pm and you connect through Pittsburgh. No jokes, 3:30 pm and you WILL make your connection. 65 minutes in line ... oh, you won't make your connection.And you skycapped your luggage ... very silly. Gee, that's odd, the computer can't locate your baggage information, but that happens sometimes ... I'm sure it will turn up.

So Suzy had to come pick me back up at the airport, and 93S to Quincy was jammed solid so we (2 hours) detoured through Jamacia Plain and Dorcester.

The theme of this blog was a trip to San Francisco to give some Tapestry training. Alas, we'll just have to do it next week instead.

Wednesday, January 19, 2005

HiveMind 1.1-alpha-1 Released

An early preview of HiveMind 1.1, 1.1-alpha-1 has been released on Jakarta.

I think the code and functionality in this release is stable and well tested, but the HiveMind crew has a lot more that will go into the final 1.1. release!

Sunday, January 16, 2005

HiveMind In Chains

The Gang of Four's Chain of Command pattern is a very useful one; we all use it all the time whether we realize it or not. David Geary has just started using it in anger with JSF, starting with the Jakarta commons-chain framework.

Chain of Command is very simple; you have a list of objects that all implement a particular interface. You simply invoke the same method on each object (in a specific order), until one object indicates that the chain is complete. Typically, the methods return a boolean, and a return value of true indicates that the chain has completed.

HiveMind 1.1 already includes an implementation of the Adapter pattern, so it was time to create Chain of Command. This takes the form of a general purpose ChainBuilder, service and a ChainFactory service used to build service implementations.

What differentiates HiveMind's Chain of Command from other implementations is that command interface is arbitrary and application-specification. There's no Command interface; the implementation generated on-the-fly adapts to whatever interface you already have. Your interface may have any number of methods, with any return type (including void), parameters, and exceptions. In 132 lines of (non-comment) code.

Using the ChainFactory, the chain of command becomes just another service implementing the interface, ready to be injected into any other service that needs it.

Tapestry 3.1 already has a number of command chains; it will be nice to refactor that code around this new functionality.

I think a good number of developers out there are aware of many of the Gang of Four's design patterns ... but they have trouble seeing how those patterns fit into their own applications. In the Gang of Four designs, the necessary objects are always instantiated and connected to each other, but it's left as a puzzle to the reader to deduce how they got that way.

In my terminology, the Gang of Four patterns focus on the production state of the system and of the individual services, and ignore the construction state, just as they ignore the destruction state. To be honest, I don't have a copy of the book handy, and I'm sure some of the examples do get involved in this issue (and some of the patterns are themselves creational).

Regardless, HiveMind takes this bull by the horns, because it's largely about the construction state. Using a combination of a HiveMind configuration and a service implementation factory, it becomes quite natural to have a configuration that describes those production state relationships, and create a service that encapsulates the behavior with those relationship in place. For chains, the configuration point describes the commands and their order, and the service implementation factory builds a service implementation that invokes the methods on the commands for you.

Tuesday, January 11, 2005

GatorJUG on Jan 13th 2005

I'll be presenting on Tapestry at the GatorJUG thursday evening (Jan 13th 2005).

Monday, January 10, 2005

NFJS Schedule for 2005

Jay and I worked out my appearanced at the No Fluff Just Stuff symposiums series for the first half of 2005. I'm trying to keep it down to two per month, and it's looking good.

  • Atlantic Northeast Software Symposium
    Philadelphia, PA
    March 11-13, 2005
  • Gateway Software Symposium
    St. Louis, MO
    March 18-20, 2005
  • New England Software Symposium
    Boston, MA
    April 8-10, 2005
  • win Cities Software Symposium
    Minneapolis, MN
    April 29-May 1, 2005
  • Rocky Mountain Software Symposium
    Denver, CO
    May 13-15, 2005
  • Central Florida Software Symposium
    Orlando, FL
    June 24-26, 2005

I'm doing my three standard sessions(Tapestry, Tapestry Components and HiveMind) and am working on additional sessions... one of which is about bytecode enhancements for testing (EasyMock) and at runtime (Javassist and HiveMind). Once Tapestry 3.1 is in beta, I may add a session on improvements in 3.1.

I hope to have some more "real world" examples ready shortly ... and, I can't wait to simplify the presentations with the 3.1 improvements. So much less handwaving will be needed! I won't have to talk about parameter directions anymore!

Saturday, January 08, 2005

Friday, January 07, 2005

Seperation of Concerns vs. Inheritance

One of my coding catch-phrases is Aggregation Trumps Inheritance. By that, I mean that combining small simple objects is a more powerful technique than inheritance.

I didn't always think this; coming out of the Objective-C/NextStep camp, I was used to using lots of inheritance. In fact, for a long time, I thought a framework was a set of base classes for me to subclass. You can see this in the implementation of Tapestry, where you start with Tapestry base classes.

Even at the time, I was concerned that the Three Amigo's had a problem with UML. Namely, that when doing a sequence diagram, it was very, very awkward to show the flow from an object to a super-class implementation of a method. There simply wasn't the necessary geometric direction to draw the line. This seemed to be a problem ... UML didn't seem to handle inheritance very well, and that made it difficult to diagram some design I had ... especially those that involved overriding a base class implementation of a method.

In retrospect, the idea of a framework as a set base classes is a bit flawed. It made sense in Objective-C land, due to the lack of a garbage collector. Memory management was a buggy, agonizing process (remember retain cycles, anyone?) so you wanted to minimize the number of objects allocated. Therefore, better to subclass and allocate a single object than to allocate several related objects and have to manage who-owns-who.

That isn't the approach I take any longer; if you look at Tapestry or HiveMind, you'll see how I trust the garbage collector, and use large numbers of really small objects ... objects that may implement an interface or two, but are otherwise inheritance unencumbered, you know, POJOs (plain old Java objects). And, if I'm inclined to diagram in UML, it works fine ... no ambiguity about which object owns which implementation of which method. HiveMind especially has very few base classes or interfaces exposed to your code, which is the way it should be.

As I take Separation of Concerns ever more seriously, I see more places where I was using inheritance out of inertia or reflex, and I can code better using smaller objects. Most often, I'm using the GoF Strategy pattern.

For example, I was adding a simple expression parser to HiveMind. I started thinking about a PropertyToken and a ClassNameToken as the leaves of my AST (Abstract Syntax Tree), with AndToken, OrToken and NotToken classes to add structure. Each node would have an evaluate() method that would return true or false. The leaf tokens would do some real work (see if a JVM System Property is true, or see if a class exists) and the other tokens would combine those values together. Real CompSci Parser 101 stuff.

But then I noticed that I really had two concerns here: the structure of the AST, and the way each node is evaluated. Using inheritance, I would inherit the AST structural behavior from some AbstractToken base class, and the subclasses would each provide their own evaluate() method implementation (as well as any additional properties).

One I saw it that way, I realized that the evaluation part was completely separate and could be factored out. My final solution for the AST uses a Node class, and an Evaluator interface. Each Node owns a left and right child node, and an evaluator. The Node class is about the structure of the AST ... the evaluator is about how the Node evaluates to true or false. The Node.evaluate() method internally delegates to the Node's evaluator (the Node passes itself as a parameter).

The end result was much less code to write and test. First I tested the Node class to make sure that structure and evaluation worked correctly. Then I defined Evaluator implementations (AndEvaluator, OrEvaluator, etc.). Ultimately, And, Or and Not were completely stateless internally ... so I made them singletons. Breaking the code apart this way made it easier to mock Evaluators when I was testing Nodes and vice-versa.

I'm tackling a similar problem in Tapestry now: re-worked the way page recorders work. In Tapestry 3.0, a page recorder is responsible for persisting certain page properties into the HttpSession as attributes, and restoring page properties from those attributes in later requests.

The 3.0 code is broken in a couple of ways; the page recorders are owned by the engine, not the request cycle, which can cause conflicts when you build a Tapestry application using frames (updating the frames cause race conditions as different threads use and update the page recorders in different ways).

It was always my intention to allow different implementations of IPageRecorder, so that other schemes could be used, such as storing data in HTTP Cookies ... but that never happened.

With HiveMind providing configuration and infrastructure, it will be much more reasonable to make this pluggable. In the long term, I want to support more complex life cycles for page data ... such as properties that stay persistent until you navigate to some other page in the application.

So, I'm finding that in the new code, the page recorder is a thin buffer between the page instance and a PropertyPersistenceStrategy object that does the actual work ... and the strategy object is dynamically looked up (using a name stored in the page specification), which is the key to pluggability.

The page recorders can now be lightweight, created as part of a request and discarded afterwards; goodbye thread contention and it simplifies the life cycle and the IPageRecorder interface.

Anyway, back to the moral: if you can subdivide an object into smaller pieces ... do it! Any time you can change an "is-a" relationship to a "has-a" relationship, you are going to find advantages in coding, testing, the works!

Pragmatic vs. Dogmatic Languages

So, my earlier post about Ruby has sparked some comments by Glenn Vanderburg. Glenn was standing next to Dave Thomas during that "hard sell" of Ruby, then proceeded to demo Seaside (a continuations-based Smalltalk web framework) during the drive back to the airport (I only got a small peek because I was driving; Erik Hatcher was the main audience).

Glenn appreciated the fact that the update-copyrights.rb script I wrote, shabby as it is, is a Ruby script, and not Java code in Ruby syntax. In other words, I did my best to use Ruby-isms, including a little duck typing, blocks and iterators, and so forth. We're both disappointed I didn't write tests for the script.

This gave rise to some interesting email discussions, the most productive part of which was some new terminology (that I hope I did not subconsciously steal from someone):

  • Pragmatic vs. Dogmatic Everyone gets hung up on types, dynamic vs. static, scripting vs. everything-else. I'd rather use "pragmatic" for non-type-encumbered languages (Ruby, Perl, Python, JavaScript) and "dogmatic" for Java, C#, COBOL ... everything that forces structure down your throat.

    In Java 1.5 terms, I like auto-boxing, but generic types are abominable! It makes the code much harder to read and the only gain is a minimal amount of compile-time type safety -- that isn't really safe. Dogma. Apparently, the dogma at Sun is "Java code that performs no casts must not ever throw a ClassCastException". So much for Dave Thomas' (and others') idea that the Java compiler should just quietly inject the necessary cast for you (based on all the other type information available) ... instead we have the syntax from hell.

  • lovely spareness is what I like in Ruby, maybe Python ... what I miss from Objective-C. You get a lot done in very little code and the code is readable. It's the aesthetic of Ruby and it's admirable.

These terms, and the concepts behind them, resonate with me. Looking at how both Tapestry and HiveMind have been evolving, it is much the same: less dogma (well, beyond "services must have interfaces!"), and much more spare XML, with the frameworks doing a better job figuring things out from defaults. Ruby is full of this same "less is more" philosophy, which is why people get passionate about it.

My last big change of language was from Objective-C on NextStep. The transition from Objective-C to Java was initially very painful ... so much of Java seemed unnecessarily baroque. And a couple of key features I pined for were missing. In fact, those features have only shown up more recently as Java Aspects ... and as Ruby Mixins. Aspects make my eyes hurt; Mixins are minimal, and powerful. Ruby is something like coming home again to Objective-C.

Ruby won't be my primary tool for a while (if ever), but it's definitely something I want to keep in my toolbox, ready to go.

Wednesday, January 05, 2005

Playing with Ruby

So, I've been peeking a bit at Ruby in tiny fractions of spare time over the last few weeks. Ruby is a fully object-oriented, dynamically typed, scripting language. It's designed to be fast, simple and powerful. It has closures which are just amazing (if difficult to describe), and the lack of types makes many common programming patterns much less of a chore.

I first heard about it a year or two ago from Greg Burd (he's the kind of guy who just knows what's cool before other people do).

I didn't really give Ruby another look until recently. Dave Thomas really pushes Ruby on a (somewhat confused) Java audience at the NoFluffJustStuff symposiums. I too was resistant, but Dave really does a hard sell on Ruby ... how could I resist something that's "a dog's breakfast, but it works!". Dave sealed the deal by sending me a copy of his book (Programming Ruby, aka "The PickAxe", which suffered an untimely death-by-NyQuil on the way out to ApacheCon and had to be replaced).

In fact, with the rolling over of the new year, I found a good use for Ruby ... a copyright updater for the Tapestry and HiveMind source code. I had written one in Python a ways back, but it was limited to Java files.

What I wanted was something a bit smarter ... that would be able to adapt to different types of files (Java, XML, properties) and would be able to update the copyright message, rather than overriding it. That is, convert:

# Copyright 2004 The Apache Software Foundation
To:
# Copyright 2004, 2005 The Apache Software Foundation

My trembling first journey into Ruby is this script, which does the work. It's sloppy, doesn't report errors well, and took me too long to write (almost as long as it would have in Java!) ... but it works and is impressively fast. In fact, I've been very surprised at just how fast Ruby is to load, parse and execute. Visibly faster than Python ... faster than Java I'd bet.

I may have to revise some of my comments in my upcoming TheServerSide Tech Talk (filmed last April).

Dr. Dobb's reviews Tapestry In Action

Just came across this brief review of Tapestry In Action. They generally liked it, but criticized the index (a not unheard of complaint). The index was the most painful part of a very painful process, and it shows.

Monday, January 03, 2005

Why Open Source? OSS vs. Proprietry vs. In House

This detailed paper is a great reference to the advantages of open source over proprietary software. It eloquently and elegantly rebuts much of the FUD out there (such as "OSS is anti-capitalism").

On a related subject, a discussion of open-source vs. in house development has come up at a No Fluff Just Stuff discussion. The gist of it was, that with open source software, you don't have the same level of knowledge of the inner workings of a framework that you would have if you developed it in house. This makes in house frameworks more enticing than equivalent open source projects.

Erik Hatcher had a great response to that. Pretend that the open source project was developed in house. Have one team developer work with the "in house team" that developed the "internal project" to learn how to use it ... exactly the same way as you would if the project really was developed in house. The difference is that you'll use more email and less phone or cube visits.

You'll still do the same things ... build some prototypes and experiments, hit some brick walls, work your way through them. At the end of the day, the team will have expended the same effort to get up to speed on the "in house" project. The advantage is that there will be more expertise in the greater world on the open source project, and it will (generally) have more functionality, and be better tested.

In other words, have someone on the team "own" the open source project. In the unlikely event that the open source project is abandoned by its original developers, you still have the complete source code and necessary expertise to continue maintaining and extending the project.

In effect, open source gives you all the benefits of an in house development (such as availability of source code, and direct access to the developers) without the actual costs of developing the software in house.

A final note; more than one architect I've talked to has stated (more or less) "any project that begins by designing the perfect framework for the project, fails." That's because, at the outset of a big project, you don't know the domain well enough to design a framework for that domain. At the end of the project, you do.

With open source software, you can bypass that; you gain the expertise of others who have already blazed a trail into your domain. Or, at the very least, you get to build your project out of larger building blocks. Either way, you're likely to get to that first iteration, where you actually know something about your application domain, that much faster.

2004 Timeline

So on this timeline of Java events in 2004, HiveMind gets mentioned (Sep. 24th) but Tapestry does not! Perhaps I need to change this blog's title to "HiveMind (and a little Tapestry)"?