struts-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Mike Menzies <glo...@gmail.com>
Subject Re: JspHelper concept to improve MVC separation
Date Mon, 07 Oct 2013 21:08:59 GMT
Hmm.. ya, that makes a lot of sense. I think I will try this approach going
forward. We sort of bastardize model-driven a little bit by having a layer
that stores and retrieves the model in the session on every request (among
other things)... which in most cases is not needed.

You've given me some things to think about. Thanks Dave.


On Mon, Oct 7, 2013 at 4:00 PM, Dave Newton <davelnewton@gmail.com> wrote:

> "The" model? "The" model is whatever you want exposed to the view layer;
> there's nothing that states it has to be the lowest-level domain object
> available--it's just "that which you wish exposed to your rendering".
>
> I don't usually use the built-in validations (for a variety of reasons) so
> I'd have to experiment with that to find what I liked.
>
> Dave
>
>
> On Mon, Oct 7, 2013 at 4:56 PM, Mike Menzies <glopal@gmail.com> wrote:
>
> > I can see that approach working well. You don't feel that it's misusing
> > ModelDriven... by not directly returning the model?  Also, if you are
> > validating your model, would adding @VisitorFieldValidator to the domain
> > getter within the decorator work the same?
> >
> >
> > On Mon, Oct 7, 2013 at 3:43 PM, Dave Newton <davelnewton@gmail.com>
> wrote:
> >
> > > Then I'm not sure I see the point; `ModelDriven` would do the same, but
> > > you'd expose the decorator, not the underlying domain object. I tend
> > > towards the same pattern, but delegate directly to a domain model, so I
> > can
> > > precisely control access (and document) at the view level.
> > >
> > > Dave
> > >
> > >
> > >
> > > On Mon, Oct 7, 2013 at 4:38 PM, Mike Menzies <glopal@gmail.com> wrote:
> > >
> > > > Yes. That's pretty much exactly what it is.
> > > >
> > > >
> > > > On Mon, Oct 7, 2013 at 3:35 PM, Dave Newton <davelnewton@gmail.com>
> > > wrote:
> > > >
> > > > > So it's a presenter/decorator?
> > > > >
> > > > > Dave
> > > > >
> > > > >
> > > > >
> > > > > On Mon, Oct 7, 2013 at 4:26 PM, Mike Menzies <glopal@gmail.com>
> > wrote:
> > > > >
> > > > > > Hello,
> > > > > >
> > > > > > My name is Mike, and I work for a fairly large company that
uses
> > > > Struts 2
> > > > > > for most of its web apps. Some of these web apps are quite large,
> > and
> > > > one
> > > > > > in particular has grown into a monster. In my ongoing efforts
to
> > > clean
> > > > up
> > > > > > this project, I have developed what I like to call a JspHelper.
> > > Before
> > > > I
> > > > > > explain exactly what that is, I'd like to provide you with some
> > > > examples
> > > > > of
> > > > > > the problems that I set out to fix.
> > > > > >
> > > > > > *Problem 1 - Monster JSPs*
> > > > > > During early development of this project, struts tags were highly
> > > > > > leveraged. I was not involved with the early phases of this
> > project,
> > > > so I
> > > > > > can't speak to why they were used so extensively.. but they
were.
> > > Tons
> > > > of
> > > > > > nested if tags that read var tags that were set in the JSP.
Some
> of
> > > > these
> > > > > > JSPs were very hard to follow.
> > > > > >
> > > > > > Even though I am a fan of struts tags, I've come to realize
that
> > they
> > > > > > should not be overused. JSPs cannot be unit tested and JSPs
are
> > hard
> > > to
> > > > > > debug.
> > > > > >
> > > > > > So cleaning up a JSP means shifting logic out, in most cases
into
> > the
> > > > > > action. An easy clean up could be something like this:
> > > > > >
> > > > > > <s:if test="articles != null && articles.size >
0 &&
> > > > > user.canViewArticles">
> > > > > >
> > > > > > into
> > > > > >
> > > > > > <s:if test="showArticleSection()">
> > > > > >
> > > > > > It's instantly more readable, and the logic is in a testable
Java
> > > > class.
> > > > > > Following this approach creates a lot of methods in the action,
> > which
> > > > can
> > > > > > be a problem if you already have...
> > > > > >
> > > > > > *Problem 2 - Bloated Action Classes*
> > > > > >
> > > > > > When the project was small, it made a lot of sense to create
> > > > > > abstract/parent action classes to share code between actions.
As
> > time
> > > > > > passed, we just continued shoving any shared code in one of
two
> > > > > "abstract"
> > > > > > classes... even if the code was only being shared between two
out
> > of
> > > > the
> > > > > 20
> > > > > > actions.
> > > > > >
> > > > > > The fix for this trend is to moved shared code into services,
so
> we
> > > > began
> > > > > > enforcing that practice. But this approach had its limitations.
> We
> > > use
> > > > > > Spring injection for all of our services, and some times a
> > particular
> > > > > piece
> > > > > > of logic just required too much stateful input... it just made
> more
> > > > sense
> > > > > > to leave it on the action where it had easy access to everything
> it
> > > > > needed,
> > > > > > as opposed to shoving it in a stateless service and having to
> pass
> > > in a
> > > > > ton
> > > > > > of arguments.
> > > > > >
> > > > > > What we really needed was some best practices put in place for
> the
> > > > > creation
> > > > > > of stateful, non-Spring services.
> > > > > >
> > > > > > *Enter JspHelperInceptor
> > > > > >
> > > > > > *
> > > > > > It wasn't until after I created this inceptor that I realized
it
> is
> > > > > almost
> > > > > > identical to the ModelDrivenInceptor. At which point, I wondered
> if
> > > > that
> > > > > is
> > > > > > what I should actually be using.. but more on that later.
> > > > > >
> > > > > > All this interceptor does is push an object onto the value stack.
> > > > That's
> > > > > > it. Your action implements JspHelperAware which provides Object
> > > > > > getJspHelper(), and the intercept code reads almost line for
line
> > > with
> > > > > the
> > > > > > ModelDrivenInterceptor.
> > > > > >
> > > > > > The idea behind this JspHelper, which is just a POJO that you
> > define,
> > > > is
> > > > > to
> > > > > > provide a place where all (or most) of the data your JSP needs
> can
> > be
> > > > > > found. This means that OGNL can find any public members or
> > operations
> > > > > > faster, and also developers can trace back any OGNL expressions
> in
> > > the
> > > > > JSP
> > > > > > to it's corresponding Java code.
> > > > > >
> > > > > > This approach places code in a shareable component. You can
> easily
> > > > > > aggregate one JSPHelper into another one, and then either provide
> > > > wrapper
> > > > > > methods or simply push the aggregate helper onto the stack using
> > the
> > > > > s:push
> > > > > > tag for direct access to it's members.
> > > > > >
> > > > > > This approach makes the actions leaner, and provides a very
clear
> > cut
> > > > > view.
> > > > > > I find at times that the action tends to be both controller
and
> > view,
> > > > > when
> > > > > > really it should only act as the controller (IMO).
> > > > > >
> > > > > > This technique is functionally very similar to ModelDriven,
but
> > it's
> > > > used
> > > > > > slightly differently. I've used a JspHelper in combination with
> > > > > > ModelDriven, and I've found the JspHelper to be a good place
to
> > store
> > > > > > logic.. and leave the Model strictly as a business object.
> > > > > >
> > > > > > *Conclusion
> > > > > > *
> > > > > > I have personally found this technique incredibly useful in
> > cleaning
> > > up
> > > > > > code. You can shift all of the JSP exclusive logic and properties
> > to
> > > > the
> > > > > > helper without touching the JSP (the OGNL expressions remain
the
> > > same).
> > > > > > Then after that initial step, you have a real handle on the
exact
> > > input
> > > > > > your JSP needs, and the actual clean up process progresses faster
> > and
> > > > > with
> > > > > > less errors. I'm still in the process of establishing some best
> > > > > practices,
> > > > > > but so far this approach is working for us.
> > > > > >
> > > > > > I would like some honest feedback
> > > > > >
> > > > >
> > > > >
> > > > >
> > > > > --
> > > > > e: davelnewton@gmail.com
> > > > > m: 908-380-8699
> > > > > s: davelnewton_skype
> > > > > t: @dave_newton <https://twitter.com/dave_newton>
> > > > > b: Bucky Bits <http://buckybits.blogspot.com/>
> > > > > g: davelnewton <https://github.com/davelnewton>
> > > > > so: Dave Newton <http://stackoverflow.com/users/438992/dave-newton
> >
> > > > >
> > > >
> > >
> > >
> > >
> > > --
> > > e: davelnewton@gmail.com
> > > m: 908-380-8699
> > > s: davelnewton_skype
> > > t: @dave_newton <https://twitter.com/dave_newton>
> > > b: Bucky Bits <http://buckybits.blogspot.com/>
> > > g: davelnewton <https://github.com/davelnewton>
> > > so: Dave Newton <http://stackoverflow.com/users/438992/dave-newton>
> > >
> >
>
>
>
> --
> e: davelnewton@gmail.com
> m: 908-380-8699
> s: davelnewton_skype
> t: @dave_newton <https://twitter.com/dave_newton>
> b: Bucky Bits <http://buckybits.blogspot.com/>
> g: davelnewton <https://github.com/davelnewton>
> so: Dave Newton <http://stackoverflow.com/users/438992/dave-newton>
>

Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message