Even though I’ve been at a project that uses Spring Webflow for over a year now, I havn’t gotten to use it much. Part of it is because I’m running around in meetings, other part is because I have been focused on architecture and back end programming. But those are the “easy” parts. I don’t really mean easy, but it’s on the GUI side of an application you find all the funky code where everyone is doing their separate thing and messing around with requests and sessions. My previous experiences mostly include Struts, so I’ve seen and performed my share of framework misuse. 😉
Spring Webflow tries to encapsulate this and abstract everything away, but it can be misused in a number of different ways too. Where there is a will there is a way. 😉
The following is my initial experiences with a relatively simple flow. Some of the tips have not really been tested yet, but hey, you learn by doing the wrong thing too don’t you? 😉 We tried hard to maximize usage of webflow code and support, and minimise our own. Readability and maintainability was also a major concern.
Stay object oriented
If you can, reuse your domain objects. If you have to create a specific object to keep extra data, reuse as much of the domain objects as possible. This can be achieved by inheritance or composition, I tend to lean towards composition. This also means that an ISBN number should be an ISBN-object, not one of those god awful Strings. 😉 Check primitive obsession for the details: http://www.jamesshore.com/Blog/PrimitiveObsession.html.
Use binding mechanisms
This is closely related to the previous item. Spring and Spring Webflow uses the notion of binding to figure out how to convert request parameters (that’s really all the text you type in a form is) that are Strings, to what is expected in the object you use to represent the form (and this is ideally your domain object, remember?).
If you have a ISBN object in your form object, Spring will detect this and use the custom binder you supplied for this. This is of course a highly reusable class based on the java.beans.PropertyEditor interface. This can be reused in every form you have a ISBN number, and it will parse and validate that the entered String actually is a ISBN number. You can of course choose to ignore it if it does not parse, and do the extra validation in your validation step, but I really don’t see any reason for this. If it doesn’t bind as a ISBN there is no reason to validate later on either. The end result? You reuse code, and can focus on working with well behaved objects in all other parts of the system.
Use a FormAction object to implement logic
Webflows are usually defined in XML. It is possible to define them in Java, but I havn’t tried it yet. When specifying it in XML they can get pretty large and unmaintainable, with lot’s of XML for calling services and setting results on scopes etc. One of the best ways we have found to resolve this is to use a FormAction object.
FormAction is one of Spring Webflows own objects that we extend and create methods on. It has access to classes specific to Webflow and thus access to special scopes etc. If you then want to show all the books available in you database you would call the retrieveAllBooks method on the FormAction. This method would then retrieve from the database (service/repository) and put it on the flash scope for the JSP (yeah, we probably should experiment with different view technology too) to display.
This relieves us of all the clutter of defining input parameters to methods and returns in XML which quite frankly looks quite nasty. It does however communicate intent in the XML so you can roughly understand from the flow what it is meant to be doing. Creating one mother method here would of course remove that advantage, so keep them short and have descriptive names.
Unit test your flows
This is actually one of the biggest surprises for me; that I actually liked it. I thought the cost/value ratio for unit testing webflows was too high, but once I got a hang of it, it had incredible value. This might be partially due to the fact that changes to a webflow don’t propagate before you reload your webapp. Never the less, being able to test how it responds to changes in what was on the request proved invaluable. But do watch out; not everything should be tested in your webflow test. Remember you are testing the flow.
It’s a bit of a learning curve, but do use it.
In the end…
Overall impression is that it’s a really good framework for flows. I was partially convinced earlier on, but the last days of experiences really won me over. As I said initially my trials was done on a relatively simple flow, but I believe I discovered enough to extrapolate this to many other cases too.
Please do add other experiences in the comments. 🙂
2 replies on “Spring Webflow Zen”
I am looking for best practices about binding form data to a backing bean when the view does not match the domain object. For example, storing a phone attribute but having the JSP show three fields (for area code, three digits, four digits).
The easiest answer is to create attributes for each field to be bound too (such as phone1, phone2 and phone3). Or leave the attributes the same but create set methods for each field and have the method create the phone attribute from the pieces. Both of these solutions involve contaminating the domain object.
A third solution involves writing custom binding code so as not to change the domain object, but that seems more complex and I am not sure how you would then use that data to repopulate the form fields.
The final solution would be to create a backing bean that is different from the domain object and find a way to copy the data from one to the other. This seems to be the recommendation from your section entitled “Stay object oriented”. I was wondering if you had any other thoughts on the subject?
Well, my first thought would be to change the domain-object to represent the three fields. As you have a need to separate things, and well separating the area-code from the number would probably be smart anyway (and you would avoid primitive obsession).
From what I understand you can’t really change the domain object. If you have a PhoneNumber domain object, you can create a custom binder for all objects of type PhoneNumber and assemble three fields to one. I’m not quite sure how the binding/names of the separate fields would come into play here.
Creating a separate object with all the fields and then copying it all to the domain object would be a last resort. It’s the old DTO, duplicate definitions thingy all over again.
When I said stay object oriented, I also said to reuse as much of the domain object as possible. So if you have to create a new object, reuse the domain object too. In a small case with just the phonenumber this is not obvious, but if you say that you are actually editing a Customer with and address a solution could be to build a CustomerForm object that references a Customer object. Then the CustomerForm could contain the specific phone1 etc. but for all other fields reference the Customer object (a JSTL reference would be something like ${form.customer.name}). This way you reuse as much of the original domain object, but add a little extra logic in the CustomerForm to accomodate the UI.