You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@struts.apache.org by Ted Husted <te...@husted.com> on 2003/03/21 18:44:35 UTC

Re: Design philosophy, beans, model to view [LONG]

If you are just presenting data to the user, then I would say just go
ahead and use the model beans. The one thing to watch for is whether
there are any properties that call back to the model. If there are, you
need to make sure that everyone writing a presentation page that uses
this bean knows which properties to call (and which NOT to call).

But as long as you are presenting properties that have already been
transferred from the data storage to working memory, just do it. =:0)

The presentation page uses reflection, so you are not coupling your page
to the model bean type but to its "protocol" -- what it names
the properties. If the model bean properties ever change, you can always
substitute an adapter, or "wrapper" bean, that maps the new properties
to the old properties. (Or just update the pages, whichever is preferable.)

Gathering input from the user is a thornier problem.

(1) The first issue is that ActionForms should only use String and
boolean properties. Why? Because the primary job of an ActionForm is to
allow for validating input. A non-String property can't store whatever
invalid input a client might present. We could just throw it away, but
the classic Struts use case has always been that we should present 
invalid input for correction, exactly as it was input.

There is nothing to prevent you from using an Integer for an ActionForm
property, but if the user inputs "12ZY4" you can't re-present that value 
for correction.

<ot>
Though, I've been wondering why we just don't have the tags (or
whatever) check the request if a property is null, and use the request
for the input buffer instead. (I might try this in Velocity.) There has
also been a recent patch proposed regarding validating maps, which might
also work for a HttpRequest. If we can use the request to buffer invalid 
data, then we can use native types. If we can use native types, then  it 
becomes easier to implement a business interface on your ActionForm. 
Business methods can then interact through the interface.
</ot>

One alternative here is to provide both Strings and native versions of 
your properties (like a ResultSet). But then you either end up 
replicating the String properties or creating confusion over which 
property to call when. If you go this way, pretty soon it becomes just 
as easy to maintain two separate beans with distinct purposes.

(2) The second argument is security. Populating a method on a business
bean might fire a business process that we aren't ready to execute yet.
Good argument, but with limited applicability. Many persistence systems
are transparent and don't have methods like that.

(3) The third argument is validation. Most business beans, it is posed,
do not know how to validate themselves, and they especially don't know
how to cope with web semantics and web validation issues.

<ot>
Though, I'm thinking validation is a perfectly reasonable thing for a
persisted object to do. And being able to validate String input, in
these days of multi-tier development, is also a reasonable feature now.

Any bean that might be populated from an external resource, whether it
is a database, XML element, or HTTP request, should be able to validate
itself. There's no telling what happened to its data between sessions.
For example, a DBA could have run a query that changed its state in an
unexpected way. Defensive programming would seem to dictate that a 
persisted bean must know how to validate (or test) itself at runtime. 
This is not a presentation issue, it's a model-state issue.
</ot>

(4) The fourth argument is composition. Often a single HTML form is made
of properties that will be used by several different objects. These are
more easily represented by a single object than multiple objects.
Nesting objects is an option, but, in practice, the nested "dotted" 
syntax can confuse other players, like JavaScript. Meanwhile, the more 
objects you nest, the more security issues you might raise (by exposing 
business methods that should not be called from the presentation layer).

I'm still kinda sold on the composition argument. I find that a "data
entry object" does make sense for most complex applications. Often, we
need to format the data in certain ways outside of what the model would
expect. We may also need to provide helper methods to make HTML controls
easier to render. And we should identify the input fields, as opposed
to whatever other non-input fields may exist in the model. In practice,
a Data Entry Object becomes a coarse-grained, denormalized transfer 
object, where the property userName often equates to something like
user.Name in the model. The DEO can be an interface defined in the 
business layer but implemented in the presentation layer.

Meanwhile, I find that my ActionForms often need properties that don't
exist in my persistence model, but do exist in my data access
signatures. So the Data Entry Object is a place where you can
encapsulate what you need for

* persistence objects (straight data)
* data access methods  (filters)
* presentation objects (formatting)

To help get from the ActionForm properties to the persistence
properties, I'm starting to think about a fancy version of
BeanUtils.Populate that would automatically map patterns like userName
to user.Name if you passed it a set of target beans. It might also take
a configuration to map coarse names to fine names, the way
Hibernate maps properties to columns.

(I'm actually starting to think in terms of a master XML element that
could be used to map DEOs (ActionForms) to persistence objects to
relational tables, with the appropriate validations between each layer.
This might be used to create separate XML documents for each gizmo you
are using [Validator, Hibernate, Struts]. The convenience of a desktop
database dialog with the power of native tools.)

So, for now, I generally recommend defining a coarse-grained ActionForm 
with all the input properties that you application uses. (For larger 
applications, it may be a module or other logical subset of the 
application.)

For each set of validations (or "forms"), define a different formbean. 
If you are using the Struts Validator, you don't have to define a new 
subclass (the validator goes by the formbean/attribute name). Otherwise, 
you can subclass the "properties" ActionForm and define a validate method.

This approach lowers maintenance, maximizes coherence, and minimizes 
coupling. Achieving high coherence and low coupling is the primary goal 
of a MVC architecture. There is still duplication between data-entry and 
model properties, but it is manageable.

The "duplication" is even *useful* for Test Driven Design. You can start 
by designing the application using coarse-grained ActionForms and let 
the UI tell you what data access signatures you need. Your object graph 
or database schema can then live on the other side of your data access 
signatures and be whatever they need to be. This gives you the chance to 
design the model (object/database layer) after you have tested what the 
client/UI actually needs.

In practice, we often design the model too early and end up writing code 
that we never use. A coarse-grained data entry object lets you design 
and test the UI before mucking about with the business object or db layer.

In the Action, you can use BeanUtil.copyProperties to beam over any 
properties that happen to match. For those that don't, you may have to 
resort to a manual transfer. [person.setName(actionForm.getPersonName)] 
Some people use an adaptor or data mapping object here to encapsulate 
the dirty work. We probably need a better general purpose utility here, 
like BeanUtils.mapProperties, or something.

Often, there is a relationship between the form validations and your 
use-case (or client story). It can be useful to name your formbean after 
the underlying use case, to help keep everything straight. I tend to use 
generic names for my ActionForm classes (like FormProperties and 
FormHelper), but very specific names for formbeans (like 
"permit_search_all" and "permit_store"). This keeps the 
formbeans/validations aligned with the use-cases they represent (store a 
permit, search all the permits).

(See also "Wither ActionMappings" 
<http://www.mail-archive.com/struts-user@jakarta.apache.org/msg57843.html>)

HTH, Ted.


-- 
Ted Husted,
Struts in Action <http://husted.com/struts/book.html>



---------------------------------------------------------------------
To unsubscribe, e-mail: struts-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: struts-user-help@jakarta.apache.org