Hi All, I've been following this list for a while now and I really like most of the stuff I've seen. However, I don't believe that removal of Action interface is a move in the right direction, for several reasons.
First of all, I don't see a difference between Action and Command, and I don't think there should be commands within actions -- if you need a new command you create a new class that implements Action interface. I can see all kinds of issues arising from allowing developers to define commands within actions, ranging from difficult and clumsy configuration file, to inability to define different interceptors for different commands, to opening door for inexperienced developers to abuse the feature which would lead to bad designs and as a consequence give bad reputation to Xwork/Webwork. IIRC Rickard had a post few weeks back where he asked if we should get rid of CommandDriven, and I believe we should. If we agree that commands within actions are a bad thing, there is still an option to specify on the action level which method should be called and to default to execute() if nothing is specified. It would even be possible for actions to inherit other actions and override only the things that should be different, such as which method to call. However, I still don't think this is good approach because it represents a fundamental paradigm shift from Command-based framework to Facade-based one. Both are valid approaches, but I think that existing Command-based approach is much better fit for Xwork. Main difference is that when you are using commands you typically map one use case to one command (Action) class, while with a facade you usually map one use case to one method (which is pretty much what Gu is doing in his AccountManager class). The biggest problem I see is that use case parameters and return values are handled very differently in those two approaches. Command keeps parameters and return values as part of its state which makes it easy for dispatcher to populate them from the request using introspection and for the views to read them after the execution. Facade methods, on the other hand, need to be passed appropriate parameters during invocation and they return a result that would have to be pushed to ValueStack in order for the views to use it. Obviously, Facade methods can easily be wrapped using Action objects. The fact that there is an additional layer is a good thing, not bad. For example, why allow configuration like this <action name="AccountManager.createAccount"> <view exception="PermissionException">Login.jsp</view> <view el="'if test="'return' >1000 "">BigAccountSummary.jsp</view> <view el="'if test="'return' <=1000 "">SmallAccountSummary.jsp</view> </action> when you can easily write your CreateAccountAction like this: private Account account; private long balance; ... public String execute() { AccountManager am = new AccountManager(); try { balance = am.createAccount(account); if (balance > 1000) return BIG_SUMMARY; else return SMALL_SUMMARY; } catch (PermissionException pe) { return LOGIN; } } I think this is exactly the logic that belongs to Action classes and pushing it into the config file might be pushing it just a little bit too far :) I don't think we should write an XML interpreter and/or use expression evaluation to figure out which view to go to. That logic is much better done in Java than in XML, even if we disregard the fact that simple map lookup to get the view is much, much faster than whatever we would have to do to make the above configuration work. Previous example also shows that action class fields (and their appropriate getters/setters) are very much related to the command itself: execute() method uses them either as use case parameters or as return values. How would we handle adding additional method (command) to this action, for example transferAccount() from Gu's AccountManager? Should we reuse account field as one of the parameters to transfer or introduce two new fields, sourceAccount and destinationAccount? I think neither option is good, first one because it uses inappropriate field which makes action more difficult to use for the person creating a view, and second one because it means that our instance fields are a union of all the fields needed by all commands, which is terrible design in my book and also makes action difficult to use even if it is well documented which fields to use for each command. I think the most appropriate thing to do in this case is to create TransferAccountAction that wraps the call to AccountManager.transferAccount(). In one of the messages Jason also mentioned that getting rid of Action interface "allows you to have one Action with multiple entry points without having to do a big if-else block to do this yourself", and I'll have to disagree. Commands are ideal way to avoid big if else statements -- command dispatcher should be making a decision which action to call, not the code within the action itself. I guess the typical example for multiple commands might be the case where you need to read some persistant data, display form that allows user to edit it, and then when the user submits the form update your database. I agree that it might be convinient to be able to have both read and update methods in the same class, but is this really necessary? After all, those two commands are different, very likely need different interceptors (no validation or transaction interceptors for read only command, for example) and are likely to have different security requirements (everyone can read, but only certain people can update data). I think it is wise to separate those commands into different classes and do one of the three things to avoid duplicating code: 1) encapsulate all the shared data into a bean and have that bean returned by the getModel() method Rickard was proposing earlier; 2) extract all shared fields and their getters/setters into abstract superclass that has execute() marked as abstract; or 3) both of the previous two :) Another thing to keep in mind is that using reflection to call arbitrary methods instead of calling execute() through interface will have a performance penalty, no matter how small that penalty is. Not the major reason why I don't like proposed idea, but a reason that shouldn't be ignored nevertheless. My belief is that a great framework should be: 1. Simple and easy to use, even for beginners Everyone should be able to grasp the concepts used and to start using framework within hours. This is an area where Webwork 1.x shines and some other popular frameworks miserably fail. I'm not sure that getting rid of Action interface would actually make things simpler. I think it would actually make configuration more complex, for all the wrong reasons. 2. Flexible, but not too flexible Usually simplicity leads to flexibility, but by allowing developers to call arbitrary methods on any object we might be making rules little bit too relaxed. All is good while good and experienced developers that know what they are doing are using features like this to their advantage, and I believe that most of the people the are following this list and shaping great framework belong to that group. Unfortunately, many developers that will hopefully be using Webwork (if it is to become the world's best and most popular web app framework) are neither good nor experienced and might easily misuse features like this. It is because of them that I believe that Xwork should be flexible within boundaries and enforce some rules that will encourage even inexperienced developers to apply best practices and good design patterns. Keep in mind that inappropriate use can easily lead to very bad and inflexible designs, applications that don't scale, etc. I can easily see situation where someone is creating all the commands in one huge Java class, making teamwork impossible. Or someone splitting command methods into multiple action classes based solely on the fact that they need to have different interceptors applied. Why give developers an opportunity to mess things up? 3. Focused on the specific problem Xwork does an excellent job of executing commands that implement Action interface, providing results to various view technologies, and redirecting user to the appropriate view. Let's not lose this focus by trying to make it execute "anything, anywhere". Finally, why fix something that's not broken? Actions as they stand today are really powerful and I don't see any reason whatsoever that would make me think that executing a method is better than executing a class. CommandDriven on the other hand reminds me of an infamous "goto" statement -- something that very rarely makes sense to use and should be avoided like a plague in all other cases. Even if you have all your services and their facades already built, it not only makes sense to have a layer of Xwork actions in front of them, it is probably the best thing to do. Actions are the place to decide what view user should be redirected to based on the result of service execution. You might want to expose your services to many different systems, either directly or through a web services layer. They should be responsible for doing certain task and returning appropriate result, but the burden of deciding which view to display should not fall on them -- that's what the Actions are for, at least in my humble opinion. Wow, this is really long, especially for my first post on the list. I promise to be shorter in the future :) Regards, Aleks ----- Original Message ----- From: "Jason Carreira" <[EMAIL PROTECTED]> To: <[EMAIL PROTECTED]> Sent: Wednesday, February 19, 2003 4:33 PM Subject: [OS-webwork] Proposal: Removing the Action Interface Based on the idea earlier of setting the method to execute for commands and making the default alias use the "execute()" method, thereby making the Action Interface unneeded, I'm proposing to remove the Action Interface from Xwork 1.0 / Webwork 2.0 and allowing any object to be used. If no-one has any objections, I'll be doing this. Jason -- Jason Carreira Technical Architect, Notiva Corp. phone: 585.240.2793 fax: 585.272.8118 email: [EMAIL PROTECTED] --- Notiva - optimizing trade relationships (tm) ------------------------------------------------------- This SF.net email is sponsored by: SlickEdit Inc. Develop an edge. The most comprehensive and flexible code editor you can use. Code faster. C/C++, C#, Java, HTML, XML, many more. FREE 30-Day Trial. www.slickedit.com/sourceforge _______________________________________________ Opensymphony-webwork mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/opensymphony-webwork ------------------------------------------------------- This SF.net email is sponsored by: SlickEdit Inc. Develop an edge. The most comprehensive and flexible code editor you can use. Code faster. C/C++, C#, Java, HTML, XML, many more. FREE 30-Day Trial. www.slickedit.com/sourceforge _______________________________________________ Opensymphony-webwork mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/opensymphony-webwork