Web Application: To couple or Not to couple?

Home

News: Web Application: To couple or Not to couple?

  1. Web Application: To couple or Not to couple? (25 messages)

    An usually annoying question when designing an action-based web application is: "Should I place everything in my action or should I separate the web logic from the business logic?" Although some frameworks want to make web development look like desktop development, we should not forget that in a web application chances are we will be dealing with things like cookies, http headers, application, session, http method (have you heard about REST?), view pages, etc. To have your business logic dealing with a http session object (or any framework-specific object that abstracts the http session) or deciding to what JSP page should the user be taken is probably not a good idea. Some people will say that by having your business logic mixed with the web logic is not just ugly but it hurts testability. The other side of the story is that to have two separate classes, one dealing with the http/web layer (ex: UserAction) and one dealing with the business logic layer (ex: UserService) is bureaucratic. If you don't watch yourself, you can end up placing business logic inside your action (easier) or action logic inside your business logic (less likely). So what is the correct approach? As always it depends. Depends in your application, how web related it really is, how much emphasis it places on testing, the size and complexity of your business model, if you will ever use your business model somewhere else, if you will ever make your business model available in a distributed system, and most important of all, it will depend on your personal taste. After you made up your mind about what approach to follow, then comes the second question: "How much should you couple your business model and your action (if you are using an action) to the web framework classes?" Some people will not care, but the majority will probably agree that the less the better. So let me try to summarize the options: 1 - Two classes: One action coupled with the framework and One business logic NOT coupled with the framework. 2 - Two classes: One action NOT coupled with the framework and One business logic NOT coupled with the framework. 3 - One class: Action and business logic together in the same class coupled with the framework. 4 - One class: Action and business logic together in the same class NOT coupled with the framework. My personal taste, from the best to the worst, is: 1, 4, 2 and 3. The reason I prefer the first option is because I get this feeling of the best of both worlds: I leave my business logic separated from the rest of my application and decoupled from the framework while I can loosen up in the action side and use the framework classes to help me do the dirty work like validation, error messages, view page redirection, etc. Most Java web frameworks will let you easily choose option 1 and 3, but few will let you choose 2 and 4. They will complain with the following argument: "How do you want to use me (the framework) and at the same time not depend on me?" The answer is Dependency Injection + Centralized Programmatic Configuration + Web Context abstraction through collections = Mentawai Web Framework. In the latest Mentawai release we have made available two different implementations of the MyBooks reference application. One that chooses the approach number 1 above and another one, more challenging, that chooses the approach number 4. You can access the recipe below to take a look in some of the MyBooks code: http://recipes.mentaframework.org/posts/list/52.page How about you? What approaches (1, 2, 3 or 4) do you prefer?

    Threaded Messages (25)

  2. I prefer the first option - two classes: one action coupled with the framework and one business logic not coupled with the framework. This allows me to use the full features of the web framework, while still not tying my business logic to the framework. It is tempting to put everything in the framework action, but this is generally not a good idea. With so many web framework choices (with none being perfect), chances of your web framework changing midway through the project are not so remote - they are definitely higher than any other layer. Even if you are planning to stick to same web framework, code is easier to maintain with business logic separation.
  3. Who does #2 work for?[ Go to top ]

    Is there a framework that allows #2 without having to write a 3rd class to link the framework action code to the non-coupled action? My opinion is that #1 is probably best unless you are doing something pretty small and on a short timescale. I imagine that if there were certain cases where the action code was complex you'd refactor those algorithms out to an action helper or a utility class.
  4. Re: Who does #2 work for?[ Go to top ]

    Is there a framework that allows #2 without having to write a 3rd class to link the framework action code to the non-coupled action?
    Mentawai allows that. :-) It can actually truly deliver a 100% decoupled web appliation, not even to annotations. MyBooks-POJO.zip is an example of such application. Everything is injected through DI and the web stuff is made transparent through Java Collections, in other words, the Session becomes Map, the headers become Map, etc. You can see some code samples here: http://recipes.mentaframework.org/posts/list/52.page or you can download the full application also in this link.
  5. This is still an interesting question, even if it has been rehashed countless times over the past 5-10 years. My preferences would go 1,3,2,4. If you had asked me several years back, I would have argued that the action logic should be separated from the framework. However, since then I've come to realize (at times painfully) that the separation doesn't buy much of an advantage. Yes, my controller logic is separated, but what are the odds that if I decide to change frameworks that my controller logic is still going to work the same way. If I make the switch from Struts to Spring MVC it would probably be close enough that I could use the same action logic and just execute it through a Spring controller instead of a Struts action. But that begs the question, why would I go to all that trouble to change to such a similar MVC framework. More likely, I'd be going from an MVC-framework to a component-based framework like JSF or Tapestry. In that case, my action logic is going to change so fundamentally that the separation I built in wouldn't matter. I'd need to re-write both my controller logic as well as my abstraction logic, assuming I still wanted to decouple from my new component based framework as well. If I had a really simple app that didn't need a service layer, I'd just throw it all into my framework-dependent controller. Is it a quick and dirty approach? Yes. But if I'm not going to take the time to separate out a service interface then I'm definitely not going to take the time to separate the single class from the framework. I'd be interested to know if people have alternate experiences where creating that separation between their action & framework really did create substantial benefits for them.
  6. I'd be interested to know if people have alternate experiences where creating that separation between their action & framework really did create substantial benefits for them.
    Well it could be interesting for upgrades, especially when the framework is not mature yet. For example, upgrading from an old version of Spring Webflow(pr5) to a recent version seems painful. But I also don't see many benefits of being able to replace a MVC framework by another one. Moreover I am not sure that having no compilation dependency is the guarantee of an easy migration between web frameworks...
  7. There's only one real option.[ Go to top ]

    "1 - Two classes: One action coupled with the framework and One business logic NOT coupled with the framework." This is the only real choice. The better your framework, the less code will need to go into the action. For instance, JSF can just use your model as controllers in many cases, or may require just a thin wrapper to access web components. "2 - Two classes: One action NOT coupled with the framework and One business logic NOT coupled with the framework." This doesn't make any sense. The layer that's translating between your model and the web could never be reused and would have to be rewritten each time you swapped the web layer anyway. 3 - One class: Action and business logic together in the same class coupled with the framework. bleh.. 4 - One class: Action and business logic together in the same class NOT coupled with the framework. double bleh..
  8. 1 was my first option, then 4 comes in second. I think SEAM encourages you to skip the action and go straight to the business logic (facade). Then you can use annotation-hell (sorry, but I don't like annotation, but this is just my personal opinion) to glue things there. JSF is a different approach all the way from the start. It is not action-based like Mentawai, Struts2, RoR, etc. For example: I have seen some people saying that "extending BaseAction" (or ActionSupport) on Struts is a big sin. I am not too religious about that, but to make everybody happy the extends BaseAction on Mentawai is totally optional. Also people who is crazy about unit testing will claim that any coupling will hurt testability. And yes: they want to test their action. Some people will even test getters and setters (ok, this is a joke, or maybe not, I am not sure now!) :-)
  9. ...decouple all the way[ Go to top ]

    3, 4 - bad practice - dont do it - it will just create bad habits... 1 or 2, depending on the app. 2 facilitates easier testing, and lot of web frameworks let you totally decouple your action from the framework. Struts 2 / Webwork - your actions can be POJOs - whic are inherently easier to test, not requirings Mocks/Fake/Dummy test objects. Your not required to extend a BaseAction / ActionSupport. Its fully compliant with a pluggable dependency injection layer - so you can use Spring - or even nicer you might want to try Google Guice - a really nice DI framework which brings back type safety - which was lost with Spring. Dave
  10. Not strictly true[ Go to top ]

    Even if the actions are POJOs they still have a dependency on web types such as HTTPServletRequest, which means you will need to use mock objects in you unit tests for these. no?
  11. not really[ Go to top ]

    Even if the actions are POJOs they still have a dependency on web types such as HTTPServletRequest, which means you will need to use mock objects in you unit tests for these. no?
    The trick is to not depend on web types such as HTTPServletRequest :) Let's take this example from the Spring reference docs
    @RequestMapping(method = RequestMethod.GET) public String setupForm(@RequestParam("petId") int petId, ModelMap model) { Pet pet = this.clinic.loadPet(petId); model.addAttribute("pet", pet); return "petForm"; } The @RequestParam("petId") tells the framework (Spring MVC in this case) where to get the parameter from. But if you're not using the framework and just writing testcases, this will work just fine: Clinc clinc = // do whatever to get your service/dao object SomeController controller = new Controller(); controller.setClinic(clinic); assertEquals(controller.setupForm(0, new ModelMap()), "petForm"); And you've just tested your controller without resorting to mock objects.
  12. Re: Not strictly true[ Go to top ]

    Even if the actions are POJOs they still have a dependency on web types such as HTTPServletRequest, which means you will need to use mock objects in you unit tests for these. no?
    No. Your actions wont have any reference to HTTPServletRequest. One of the ultimate goals is simple testing of your actions, so most frameworks make a huge effort to have no dependency on any container apis such as HTTPServletRequest. Sometimes, however it might be necessary - and then, yes, you would mock it.
  13. Re: There's only one real option.[ Go to top ]

    Some people will even test getters and setters There is absolutely no reason to have getters and setters unless they *need* testing. If you want public class variables, make them public, and teach your damn IDE to recognice the word "public" not the words "get" and "set".
  14. You forget one critical part: the view layer. If you don't couple 'action' with 'framework' it means that you must handle presentation layer logic right in the template files. That leads to a huge mess, while benefits of decoupling action from framework are questionable. My preferred way: -- 100% logic-and-code-free template files -- Actions coupled tightly with framework -- Separate business/service layer, but very coarse grained, not '1 service for 1 action' style -- Direct data access from action and business/service layers (no DAOs, ORM abstracts different databases well enough) Secondly, what comes to mentawai's uniqueness, your 'de-coupled' code didn't look much different than normal Struts 2 action, and 'pull' frameworks like JSF offers possibility for even greater de-coupling because you don't 'push' objects to template, but template 'pulls' what it needs by simply using accessors of the action class. In mentawai there still exists the contract that the 'push' output is a map, and messages is a list etc. Thirdly, i didn't like how the article's subject turned suddenly into mentawai marketing at the last few paragraphs. Cheap, i say. /Henri Karapuu
  15. Secondly, what comes to mentawai's uniqueness, your 'de-coupled' code didn't look much different than normal Struts 2 action
    Mentawai is totally different than Struts2. Mentawai is full-stack, does not use any annotation-hell or xml-hell and has centralized programmatic configuration through Java, BeanShell, Groovy, etc. This was its innovation back in 2005. I did not know (maybe I am wrong) that with Struts2 you can inject a session like a Map. I think you are taking decoupled as "not extending anything". This is much more than that.
    , and 'pull' frameworks like JSF offers possibility for even greater de-coupling because you don't 'push' objects to template, but template 'pulls' what it needs by simply using accessors of the action class. In mentawai there still exists the contract that the 'push' output is a map, and messages is a list etc.
    This is false. Most frameworks nowadays can pull stuff for the view layer. With Mentawai you just place the OutjectionFilter in the filter stack if you prefer to do it that way.
    Thirdly, i didn't like how the article's subject turned suddenly into mentawai marketing at the last few paragraphs. Cheap, i say.
    My appoligies, Henri. I think it is an opportunity for comparison with other frameworks, like you are doing. Good arguments!
  16. Mentawai is totally different than Struts2. Mentawai is full-stack, does not use any annotation-hell or xml-hell
    Sorry Sergio, i expressed myself badly. I was referring to uniqueness in the context of the discussion, which is coupling between different layers.
    I did not know (maybe I am wrong) that with Struts2 you can inject a session like a Map. I think you are taking decoupled as "not extending anything".
    I'v moved away from action based frameworks (last was Struts2/Webwork) back in 2004, but from what i'v gathered the Pojoness and dependency injection in Struts2 seems similar. As a side note, and probably un-called for, i'd have to say that currently the momentum is very strongly in component based frameworks, ajax and RIA. In the passee and heavily competed action framework market you need to offer much stronger benefits than just 'programmatic configuration' or 'de-coupled actions' if you want to have fight against mature, established, apache branded Struts2. /Henri Karapuu
  17. I did not know (maybe I am wrong) that with Struts2 you can inject a session like a Map. I think you are taking decoupled as "not extending anything".
    Yup, all the container scopes are represented like this and can be injected into the action.
    ...annotation-hell or xml-hell...
    I happen to like annotations, and think used properly they are a good language feature, however this is a different topic (or is it?). Any language feature can be overused. And Struts 2 can also adopt the 'Convention Over Configuration' approach if you choose you would like to do it that way. I think its good that a framework provides the option. I generally prefer to use annotations combined with xml - but thats just my choice, and it really depends on the application. Thanks
  18. Mentawai with injection looks rather similar to the new web MVC stuff in Spring 2.5.
  19. For me, as a general rule, #1 is the most obvious solution. But I have to say that the proposed architecture is rough. In fact, behind the term business logic there is an entire world and the relation between the action and the BL matters. I don't think that the BL should be a 1-1 mapping with the actions, provided that all the framework deps are removed. It would be a sort of #4 with a home-made adapter. For me first there is a system, that provides certain capabilities because IS something. Then you need a way to trigger what the system provides. Here come the actions and, yes, option #2 could seem an over-engineering. Oh, #3. Any time I have start that way I regret not to do #1. Guido
  20. It's like buying insurance[ Go to top ]

    I recall a lot of times when splitting the code into the action framework action class (Struts) or method (JSF) and the business facade looked like an overhead. However, I have two other images 'burned' in my head to remind me that taking the 'decoupled' approached is like buying insurance and ultimately if you drive long enough, your bound to be involved in an accident. I was called to consult for two different companies. The one used struts and wanted to expose their code as web-services. They had everything inside the action class (that used session and requests object as well hibernate code) and that was an obstacle that required a lot of re-coding. The same situation, similar architecture: I recall comparing two applications several years ago. Both written in legacy technologies. One put all client behavior in Oracle forms and the logic in Stored procedures and the other one used Win-Forms with the client, business and data logic in the same place. The first application did allow re-writing of a single tier - the presentation tier while the second application required a massive re-writing. Kids, just buy insurance, :)
  21. Re: It's like buying insurance[ Go to top ]

    Actually, insurance is provably a bad investment. If it wasn't so, no insurance company would be in business. The insurers are betting that they won't have to pay out as much as they take in. And by and large, their right. Even after a disaster, most insurers come out ahead. Partially because of the deductibles. The real lesson is that savings matter. Most people, for example, would be better off paying for their health care out of pocket (even when they're old or sick). $300/month over 30 years of health will buy you a couple babies, some broken limbs and braces, and a round of chemotherapy, plus all the viagra and you will need when you get older. You'll have to get your diabetes and heart medication in Mexico, because drug companies in the US eat up the insurance "savings." Rewriting the logic from a struts action or JSP isn't fun, but the time saved up front will likely afford it (with the added benefit that "Agile" promises of knowing what you really want when it's time to re-code.) The sad truth is, that like social security, the time saved will probably have already been spent by someone else. Truth is, decoupling doesn't buy you insurance. It buys you abstraction. And that's where it pays off.
  22. Re: Its like buying insurance[ Go to top ]

    I know we are not here to discuss the validity of the metaphor, but. . . Actually Insurance removes variability as the impact of the event you are insuring against. Decoupling removes variability as the cost of changing the decoupled code in the future. You pay a bit to ensure you are decoupled and get the benefits of knowing future changes will come easier. Therefore I think decoupling does buy you insurance. But the relationship between decoupling and abstraction is interesting. I think you decouple via abstraction. Abstractions don't come as a result of decoupling. The abstract model must exist before you decouple. Although you could theoretically decouple without an existing model, I don't know what the results would look like.
  23. "Business Logic"[ Go to top ]

    At the end of the day, decoupling is good and the overhead is negligible (well if you really want you can create a configuration nightmare from it, but you don't have to - there is always new() :-) ). However for most applications (and most frameworks) a lot of "business logic" is driven by the framework and the concrete user interface requirements.
  24. There are good reasons for decoupling: 1. Testability. Business logic decoupled from the presentation is trivial to test in a batch mode using JUnit and other testing frameworks. Ease of testing enables writing more tests. More tests mean better [business tier] quality. Hairball-style apps force testing from the front side, which is hard even with selenium and alike. 2. Web services. Though your mileage may vary, our experience shows that sooner or later there will be a requirement for web services or other remoting-style access. A clearly defines business tier makes it trivial. Coupled apps don't allow for this. 3. Caching. When need for horizontal scalability comes, Coarse-grained business facades are easily cacheable. Solid-state apps are no-go. Hope this helps. Regards, Slava Imeshev
  25. It's another question[ Go to top ]

    I feel like the real question (after you have decoupled presentation controller and business facade) is where to construct your pojo: 1. On the view contorller layer: assemble the pojo from user request parameters and hand it on to the business facade to 'Just keep it'. 2. Pass parameters either stripped or in a request-object ( a la evil DTO), and constructing the POJO inside the business facade. Personally, I like the second approach better because in many cases you would not want to rely on the presentation-tier to hand in a complete brand and valid POJO because your POJO may require some domain validation and application invariants validations. If your POJO may implement the state pattern (can move from state X to Y and cant move from Y to Z), this is a common situation to prefer the second alternative. I always try to look at the contract between the controller and the business facade as something that may turn into a web service one day. Boundary interfaces are best kept 'procedural' in nature unless your developing a tightly coupled small application. And yeah, its a coding overhead, I know.
  26. Currently the lifespan of a web-layer is shorter then the lifespan of the services. Especially is services are re-used, like webservices/SOAP. That means you should really seperate the two... Else you need to reinvent the wheel if you change the web-layer, or when you decide to expose the service some other way.