Understanding Nested Conversations
I had a bit of epiphany on the subject of nested conversations the other day when I was thinking about them and thought I’d share. I think nested conversations have been a little misunderstood with people unsure of how to use them, myself included, but I think I have found the best way to think of them.
In summary, nested conversations do for regular conversations what conversations do for session scope. With session scope, you cannot have mutliple instances of a named variable, you have to put each variable instance in its own conversation where it will be unique. However, if you want to have multiple instances of a named variable within the conversation, again, you cannot and you have the same problem you have with the session scope, that variables must be unique. Therefore you have to have each variable in its own nested conversation under the main conversation the same way we had the top level conversation under the session scope.
In some weird web app which lets you pick a person and then put costumes on them, you might have a main page where you select the person, and then in separate browser windows you can pick different outfits for that person. You put the selected person value in a different conversation so the value of #{selectedPerson}
is local to the conversation allowing multiple selected people in different browser windows. This overcomes the limitations of the session which allows only one value for #{selectedPerson}
However, if you had that conversation open in multiple windows or tabs so you can compare different costumes on that person, there would only be one value of #{selectedCostume}
for the conversation shared between all windows. As you select a costume in one window, it would affect all the other windows as they share the variable in that conversation. Using nested conversations would allow the conversation to have different values for the selected costume under the same parent conversation with the same selected person.
Taking it further you could select the person in the top level conversation, select the costume in the nested conversation, and then you could have multiple windows open with further nested conversation letting you pick different shoes to go with that costume. Also, if you change the person in the top level conversation, it will change the selected person for all windows using that conversation or any of its nested conversations.
I’m not sure there is a great need for nested conversations, I’ve never really used them or found the need and I don’t think users open that many browser windows or tabs to create different logic paths within a conversation. I think it is acceptable to limit the data isolation to a single conversation level.
4 thoughts on “Understanding Nested Conversations”
Comments are closed.
Hi Andy,
Thank you a lot for sharing your view on conversation aspect of the Seam. It really helps to form a rich and full picture of the term.
Regarding the nested conversation I find it very useful from navigation prospective in a use case when one need to do a lookup for an input on the main conversation by redirecting to a dedicated search page. When value is selected and nested conversation is ended it will automatically restore the parent conversation, so no need to keep track of what the calling page was.
It would be interesting to know you opinion on components design: backing beans vs action beans (well, seam components), the granularity and degree of reuse.
Thanks a lot for your blog.
Andy Z.
Hi Andy,
Yes, that is a useful side effect of nested conversations! I tend to use page flows since it constrains the navigation a user can make, and you don’t have to worry about them going to some other page that will begin a conversation with join=true and the new page ends up running in your old nested conversation. Not a problem though if you have conversation pages with no/few links on them for the user to click on that will take them outside your current conversation.
Regarding component design, for my needs, which is mostly searching and CRUD, I use the EntityHome and EntityQuery components and generally have one per CRUD or search page respectively. I tend to keep things like factory methods related to the pages in the entity home bean and entity query associated with the page. Seam with its statefulness really does remove the need for Dao type components, although for more complex data, sometimes a dao type of ‘data producer’ is still needed when the data fetch is more complex. For action listeners and responding to user events, typically I do that in the entity home beans also. Again, there are few places where you will end up using that bean, and I have yet to use an Entity Home bean for anything other than the page that displays the entity details and the page that lets you edit the entity.
I tend not to build large hierarchies with big plans for reuse since most code can be refactored later on as needed and most code doesn’t offer much opportunity for reuse. This offers a nice balance between being an architect astronaut and having a bad design. Just keeping it open for refactoring is probably more important than spotting places for patterns and reuse the first time around. Saying that, with todays tools, it is pretty much impossible to not be able to refactor, so I guess the real trick is to only write applications with files your IDE can refactor!
Cheers,
Andy Gibson
Dear Andy,
I was working on a use case that begins with the user selecting a menu option that led him to a query view. Then a list of entities is shown and he selects some and chooses actions on them (like delete, update something, modify some attributes, and so on). Any option can lead to other sub views, with specific attributes.
After performing the action, the user can go back (using the browser back button which is a little problematic, with ajax issues in updating the view on some browsers and all – btw I think you should write a post someday about it) to the list to select some other row or choose to perform another action on them or go back to the query view to make another query or to go back to the menu to choose another option. So many possible paths.
I had a helluva time figuring out how to estabilish @begin and @end conversation points in this scenario, that is not so unusual.
The hotel booking sample has a very straight and clear path so it’s easy to see the conversation boundaries, but what is the best approach when the things get a little more complicated with multiple possible paths?
May the page flow strategy be a feasible solution is this case?
Thanks,
Geraldo.
Apologies for the delay in the reply, things have been busy. The biggest problem you have is that your data changes must take place in a separate conversation since nested conversations share the same persistence context with its parent. You need to be able to make those changes to the data and persist them in the span of a conversation. This should help define how your flow goes. If you start on the search form, and select items and go to the listing form, that could be one conversation so you can keep that state separate. Then you could click the link to make the changes to the data and that propagates no conversation, but, it does pass in the conversation Id that the selection and listing runs under. This way, you can start a brand new conversation containing the data editing, and you can end that conversation, commit the data changes, and go back to your search page by going back to the listing page and manually adding the conversation Id that was passed in when you started the editing process.
I might have to create a new post to explain this a little better since it also gets around the issue of not having a Persistence Context per nested conversation. Oh, and one big page flow probably won’t work since the conversation lasts as long as the flow and all the data changes will build up in the same flow.
I’m going to have a think about this and maybe do a post to reflect my thoughts a little better,
Cheers,
Andy