Help

Stephan Schmidt says that people don’t get the difference between business and UI logic:

People most of the time use business logic in their templates, be them JSP, Velocity or Rails. They confuse business logic and UI logic. Those are two different things.

As an example of something that should be avoided, Stephan gives the following code:

<c:if test="${user.loggedIn && user.bookedProducts}">  
 // show menu  
</c:if>

Well, you can count me among those who don't get the difference. I don't see how it is clear that the expression in the code above is implementing business rather than user interface logic. In fact, it seems to me that distinguishing the exact boundaries of what constitutes the /user interface/ is in general more art than science.

In this particular example, it seems to be the && that Stephan objects to. If I'm reading him correctly, he would not have a problem with this:

<c:if test="${user.loggedIn}">  
 // show menu  
</c:if>

or this:

<c:if test="${user.bookedProducts}">  
 // show menu  
</c:if>

However, I don't see that the use of conjunction, a priori, is enough to turn something into business logic.

Any user interface depends upon attributes and operations of model objects. Sure, we /could/ introduce some intermediating layer to shield our user interface from a direct dependency upon our model, but this merely moves the dependency around; it does not eliminate the dependency, nor solve the question of exactly which logic belongs in which layer. What is unclear is the criteria for determining which logic must be implemented by the model, and which may be safely implemented in the user interface (or intermediating layer) code that uses the model.

We talk about business logic all the time, so you might think that this is some kind of well-defined notion, but as even Wikipedia admits,

Business logic is a non-technical term ... there exists no definition of business logic in any programming language specification or API, nor in any academic research ... it should be noted that business logic is a poorly-defined term which is used in several different ways by several different groups of people.

Nevertheless, Wikipedia goes ahead and defines the following scope for the term:

Business logic:
  • models real life business objects (such as accounts, loans, itineraries, and inventories)
  • prescribes how business objects interact with one another
  • enforces the routes and the methods by which business objects are accessed and updated

Stephan's code example is not defining a business object, nor an interaction between business objects, nor does it seem to me that it is enforc[ing] the routes and the methods by which business objects are accessed and updated.

So, assuming that this expression does not occur in multiple places in my templates, I would be inclined to leave the original code alone. It seems to me that the cost in complexity of introducing a new method (possibly a new object) to encapsulate this expression is simply not worth the effort, unless there is some additional concrete benefit.

On the other hand, if this same expression does pop up in multiple places, I would almost certainly encapsulate it in a method of some model object:

  1. in order to satisfy DRY, and
  2. to allow me to document (via the method name, or even JavaDoc) exactly what the expression represents; what is so /special/ about this expression that causes it to occur repeatedly.

So does that make me a defender of the use of (short) scriptlets in JSP, PHP or RHTML? Well, no. But my objection to the use of scriptlets has a different basis. What I find objectionable is the mixing of highly dissimilar languages and language paradigms in the same source file. I remain a fan of declarative user interface definition.

14 comments:
 
28. Nov 2007, 02:21 CET | Link
Sakuraba

I remain a fan of responsive JS widgets encapsulated in Grails GSP Tags and their declarative use in templated UIs by Sitemesh.

 
28. Nov 2007, 02:35 CET | Link

Hi Gavin,

user.loggedIn is from the business domain, while showMenu is from the UI domain. So using the business domain within the UI domain mixes abstractions and leads to problems. Not always and not with simple cases, but more often than not. Especially in large projects which are in maintenance mode.

And it's not about shielding, it's more about adapting or translations. Someone, most often a product manager, has to think about the mapping logic. In large UIs or websites, the state of showMenu might depend on a lot of things, not only on user.loggedIn. It might depend on the number of purchases you've made or the products you bought. Or on a promotional sale. And with DRY you should only define the translation from the summary of states to one state in one place. This is also often a piece of software that frequently changes because business decisions change.

When moving this to a new layer you can use a rule engine for the state, if the need arises. You can safely change the conditions that lead to showMenu. When encapsulating this in a DSL (think RSpec) you can make the mapping code human readable.

I've been biten several times with distributing the mapping from domain to another over dozens of pages. And in large applications with several hundred of pages a lot of this mapping occurs. With Swing development this is a established pattern called ViewEditor where you decouple the UI logic from the business logic for easier testability. If you put the translations into the template, you can also argue to put SQL code in there ;-)

But as you've said, business logic is a fuzzy term. What I wanted to express with my post, there is a difference between the UI domain (showMenu) and the business domain (user.hasBookedProducts).

Peace -stephan

 
28. Nov 2007, 02:54 CET | Link

No matter how you slice it you are mixing business and display logic. Having a showMenu method in the user model seems a little dirty as well.

I think I would prefer the compound condition in the template over putting display logic in the model. Either way will be DRY since that would be a partial template if I needed to reuse it.

 
28. Nov 2007, 05:31 CET | Link
Jay Balunas | jbalunas(AT)redhat.com

I have seen and been part of the obsession to separate out everything into its own layer and abstracting everything. Sometime it feels like abstractions have abstractions :)

Why do we do this? Because if something changes then we don't need to modify class a we only have to modify class b and c. In my experience, even with large applications, rarely are there changes that do not cross multiple layers, and by abstracting everything you are essentially just adding layers that need to be changed.

Don't get me wrong abstraction, and encapsulation are good things and make code easier to understand, write, and modify, but too many times it is added when not needed.

My $.05

 
28. Nov 2007, 06:13 CET | Link
user.loggedIn is from the business domain, while showMenu is from the UI domain. So using the business domain within the UI domain mixes abstractions and leads to problems.

If that is the case, then your implementation of showMenu() is mixing business domain and UI domain. You've just moved the problem around. But, in fact, I don't really think there is any real problem here. The UI depends upon the model; that's the MVC architecture. You don't need to try and hide this fact, it's perfectly correct and natural.

Not always and not with simple cases, but more often than not.

Simple cases are important. A more complex solution may indeed be justifiable in complex cases. But if the simple solution works well for the simple case, why introduce a more complex solution?

In large UIs or websites, the state of showMenu might depend on a lot of things, not only on user.loggedIn. It might depend on the number of purchases you've made or the products you bought.

If this is indeed the case, then a complex solution is justifiable. But you didn't mention anything about that in your original blog, so YAGNI applied.

When moving this to a new layer you can use a rule engine for the state, if the need arises.

Whoah, whoah! YAGNI!

I've been biten several times with distributing the mapping from domain to another over dozens of pages. And in large applications with several hundred of pages a lot of this mapping occurs. With Swing development this is a established pattern called ViewEditor where you decouple the UI logic from the business logic for easier testability.

You're changing the subject. No-one has argued that there is no need for distinct UI and model layers. What we were talking about was /the particular example you gave/, of a very simple expression in the UI layer that referred to the model layer.

If you put the translations into the template, you can also argue to put SQL code in there ;-)

I'm sorry, but this doesn't follow logically. Just because I claim that it's perfectly okay to use simple expressions in the template does not imply that I must also claim that it's okay to use SQL there.

Furthermore, you could use this argument template to justify /any/ useless additional layer:

If you but put the XXX into the YYY layer, you can also argue to put the SQL code there

Could be used to justify architectures with thousands of layers.

 
28. Nov 2007, 06:29 CET | Link
I remain a fan of responsive JS widgets encapsulated in Grails GSP Tags and their declarative use in templated UIs by Sitemesh.

I don't understand how this relates to the topic we're discussing. Please explain...

 
28. Nov 2007, 06:31 CET | Link
In my experience, even with large applications, rarely are there changes that do not cross multiple layers, and by abstracting everything you are essentially just adding layers that need to be changed.

Right. The whole idea of a layered architecture makes great sense when the interfaces between the layers are narrow, and the internal implementation of the layers is complex.

However, in most multi-layered business applications, the interfaces between the layers are very large and complex, while the internal implementations are relatively simple.

So you end up spending more time writing adaptors that push attributes around than you spend solving the business problem.

(I'm not saying this is /always/ true, just that it is very /often/ true.)

 
28. Nov 2007, 11:58 CET | Link
Whoah, whoah! YAGNI!

I didn't mention a lot of other thinng in my blog post, because real life is much more complex than a post.

Just because I claim that it's perfectly okay to use simple expressions in the template does not imply that I must also claim that it's okay to use SQL there.

Because it's ok to put business expressions in the template, it's not ok to put SQL in there? Where do you stop?

I'm not saying this is always true, just that it is very often true.

Peace -stephan

 
28. Nov 2007, 13:07 CET | Link
I didn't mention a lot of other thing in my blog post, because real life is much more complex than a post.

Your post showed a simple problem, and proposed a complex solution. If you wish to justify a complex solution, you'll need a more complex problem.

Very often, real life is simple, but we /make/ it complex by blindly applying a complex pattern without questioning whether the pattern is truly justified in a particular instance.

 
28. Nov 2007, 17:24 CET | Link
Alexandre Poitras

Personnall, I try to be pragmatic. If some logic gets too complex in my Facelets/JSP page, I get ride of it and put in a Java class where it can be more easily tested and made explicit. If I have some java code manipulating my JSF view, I try to isolate it from the domain model since it obscures the business logic.

Unless you have two different UI clients I don't see the point of arguing what is UI logic and what is business logic.

 
29. Nov 2007, 00:36 CET | Link
Sakuraba
I don't understand how this relates to the topic we're discussing. Please explain...

I kind of misunderstood the direction this discussion would he heading to. I thought the emphasis would be on declarative vs programmatic UI logic, which in turn could be translated into a discussion about declarative JSF components (e.g. Rich-, Icefaces) vs programmatic JS components (e.g. ExtJS, etc).

Basically I just picked up your last statement in which you referred to the older blog post about declarative UI logic and described that this can also be achieved with with programmatic UI components by encapsulating them with e.g. GSP tags.

But as I already mentioned, this is in no way related to what the real message of this blog entry is about (what I misunderstood when writing the first reply), so feel free to ignore my misleading statement at the top. ;)

 
29. Nov 2007, 00:54 CET | Link
Sakuraba

Now having read the entry for two more times, I just want to add that IMO in Java Web/Enterprise development it has become common to associate additional layers (even for trivial delegation) as a good and absolutely necesarry practice. Most of the times people have forgotten about the cost additional layers can bring into the development cycle.

I have seen code of 'layered to the fullest' applications, where 70 % of the work was a total waste of time, because

a) the layering was built around trivial delegation and a simple change most of the times affected every layer.

b) the flexibility a new layer brings was highly unlikely to be of any use in the future (Let's abstract away the persistence provider, because MAYBE in X years we will switch from Hibernate to TopLink and our 'service layer(aka DAO delegation layer)' must not require a change).

c) the time new developers needed to understand the need for all layers harmed productivity.

 
05. Dec 2007, 14:18 CET | Link
Stefan Schubert

There's a point with Stephan and one with Gavin. Stephan defines a best practise how to satisfy DRY. A lot of DRY violations happen in UI artifacts because of the lack of tooling. Mostly in complex internet portals it is very hard (because of tooling) to identify DRY violations because access to business objects is actually spread over dozens of JSPs in different ways. Maybe it's a problem of the developer. So he needs to know best practises.

Gavin says you don't need such a best practise in simple examples. He's right. You don't want to pollute your code with lots of YAGNI practises to many to overlook and to decide which one is useful. This is another problem. Lots of patterns lead to more code pollution.

Today we actually decided to introduce a DAO layer. (we're not using Hibernate) And I for myself am not quite sure whether this is really a useful decision - even if I with others voted and worked towards it. Because the proprietary ORM code forces us to enforce such a silly DAO usage using anonymous inner classes not to pollute the DAO interfaces with the tight ORM-knows-my-services coupling.

With Hibernate (or better JPA) you see that if you have a clean API you may better throw away the additional layers. And this is just what I'm seeing in Gavins statement. Like with Seam that does not enforce the usage of controller beans between your components and your UI like JSF does.

I don't know what is right - I just see that it's important to have rules. Rules that actually help your code to be clean and rules that your developers understand and can maintain.

 
11. Dec 2007, 02:58 CET | Link
I don't know what is right - I just see that it's important to have rules. Rules that actually help your code to be clean and rules that your developers understand and can maintain.

All I'm saying is that rules are no substitute for good judgment. Slavish adherence to patterns and coding standards can lead to complexity and bloat. I believe that it's generally better to inculcate good /values/ (such as DRY, YAGNI, etc), good judgment and individual responsibility, than it is to set up all sorts of inflexible rules.

But then, I'm very anti-authoritarian :-)

Post Comment