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

Reply via email to