Separation of logics: Logical

By Freeaqingme on Friday 31 December 2010 00:57 - Comments (6)
Category: Zend Framework, Views: 2.464

This article was originally posted on April 19th 2009

Everybody who has projects that exist out of more than 100 lines of code faces the problem of keeping his code clear, and maintaining a good oversight. Of course, none of us wants to go over all his code just to find that one line or method you’re looking for.

To overcome this problem, some smart people ‘invented’ Design Patterns a long time ago. A design pattern is ‘a general reusable solution to a commonly occurring problem in software design.’ (Wikipedia). A commonly used design pattern is MVC: Model–view–controller. MVC is used to separate your application in three parts: the Data (Model), the output (View), and the User action/input (Controller).



The Model: This is used to retrieve and store data used anywhere in your application. This data is also called the domain, please note that this has got nothing to do with domain names!The storage can be basically anything, from fullblown Oracle Databases to Sessions, from the Google APIs to Punched Cards. The nice thing of this is that whenever you want to change storage, or something inside the storage is changed (like a row in your db-table is renamed) you only have to apply the changes once at only one place.

Especially in terms of Web Applications almost every application is useless without output, this is where the view comes in. The view retrieves data from your model or controller, and displays it in a way that a user can understand it. mostly this will just be some (x)html page. Sometimes some logic needs to be done before the data from the model can be displayed to a user. Now you can of course put the code that is responsible for that in your view. However, a lot of people don’t like having logic in their views, and chances are that you need the same logic in multiple views. Please do not put this logic in your models nor controllers; it has got nothing to do with either data retrieval nor handling user input. Though it isn’t part of the MVC pattern, it is considered best practice to put them in view helpers. These are reusable blocks of code that are aimed specifically at what data should look like to an end-user.

Maybe most abused by developers is the controller. The ‘nice’ thing of controllers is that you can (read: are physically able to) put all your code in your controller. All that a controller does (or should do) is parse the user input, and decide what view to use. The parsed user input can be passed on to the View, which in turn can call the appropriate models with the user parameters that were passed on by the controller. These days it is considered good practice to leave your controllers as empty as possible. I had a good link here, but it went down. The updated url is this one.

Now please remember that a design pattern is solely a guideline on a best-effort basis. There are no solid rules, and there are always exceptions to think of. While programming, such exceptions may come to your mind very often because of deadlines, hurry, a girlfriend, other projects, laziness, or any other ‘good’ reason. To help you defy these exceptions, there are a few golden rules (in random order):
» Views or models should never invoke user parameters directly.
» Models should never contain stuff that is related to the view
» Controllers and Views should never contact a database or contact a third-party API (or any other kind of storage)I.
» Models should be able to work independently from Controllers and Views
» Views should never insert something directly into a model

Because HTTP is a stateless protocol, some of the old rules of MVC cannot be complied with. Therefore, I have altered this picture a bit, just in case some things were not clear yet. This will generally be the dataflow in a stateless webapplication using MVC:
http://dolfschimmel.freeaqingme.com/wp-content/uploads/2009/04/modelviewcontrollerdiagramzf.svg

If you still have questions about MVC, feel free to leave a comment, or simply pay a visit to #zftalk @ Freenode

Volgende: MariaDB: Replaces Mysql, gives you more (without effort!) 01-'11 MariaDB: Replaces Mysql, gives you more (without effort!)
Volgende: "Please moderate" 12-'10 "Please moderate"

Comments


By T.net user Barleone, Friday 31 December 2010 01:30

Say, I have a ZF application, with only /index/index and /error/error including controllers, views, and some models for database access.
In /index/index/ I receive ALL requests because I have useDefaultControllerAlways enabled.
Therefore: a request like http://example.com/home/ or http://example.com/contact/ will be handled by IndexController and IndexAction.

Right now, IndexController/IndexAction() does all the magic:
- retrieve pages from a Model > create array with sitemap > for the View.
- retrieve pagecontents from a Model > passing through > to the View.

So, my IndexAction() isn't as empty as possible. Q: What should I do?

Note: Link broken: http://rails.frenzicmojo.com/2009/01/synchronicity.html
offtopic:
Please use the tweakblog [more] tag: Wiethoofds meuk en 'overige': Tweakblogs & de [more]-tag

[Comment edited on Friday 31 December 2010 01:36]


By T.net user Freeaqingme, Friday 31 December 2010 03:12

Well, first of all, I would suggest not using useDefaultControllerAlways. I would suggest using a route with url /* so that all urls are mapped to that route. This would allow you to later on add other functionality that doesn't require the index controller (and action).

Having said that, I would change the action to something that merely passes on the requested pagetitle to the view. Then inside your view you could call your modellayer, and retrieve the page (to then display it).

If your sitemap depends on user parameters, you could take a look at front controller plugins. These are classes that get called on every page request, and therefore allow you to perform controller related stuff that is necessary with each page load without having to duplicate any code. In your front controller plugin (probably in a method named preDispatch()) you could then pass on the user parameters required to build your sitemap on to your layout.

Whether your sitemap is dependent on user parameters or not, you should (imho) construct that inside your layout, or a viewhelper getting called from inside your layout. The layout (or viewhelper) can just pull its data from your modellayer, there's no need for your controller to do that! If you haven't done so already, you may want to look at Zend_Navigation. This is a component that helps you set up a navigation menu and sitemap in a matter of minutes.

If you want more tips on how to incorporate all different pieces ZF provides into one application, you may want to checkout the (free!) book, Surviving the deep end.
So, my IndexAction() isn't as empty as possible. Q: What should I do?
Beware, if it works for you, it works. Design Patterns are no solid rules, they're sets of guidelines that can be used to hold on to. It does not mean that you need to adhere to it to the letter. When your application grows, this will eventually become impossible. Also, there are thousands of interpretations of each Design Pattern out there, so please use them as something that helps you, not something that limits you.
Note: Link broken: http://rails.frenzicmojo.com/2009/01/synchronicity.html
offtopic:
Please use the tweakblog [more] tag: Wiethoofds meuk en 'overige': Tweakblogs & de [more]-tag
Thanks. Link fixed & more tag added.

By T.net user YopY, Friday 31 December 2010 09:45

Just wanted to note that design patterns aren't specifically methods of keeping 'oversight' over your code. It's also arguable to call MVC a design pattern; a lot of sources call it an architectural pattern instead, as it's not just a solution to a specific problem, but a pattern to model an entire application.

Your definitions are a bit off too. The view doesn't retrieve data, instead, data is sent to the view from the controller. Significant difference there. There is however a pattern whose name I forgot where the view decides which data gets retrieved, but it's not called MVC (although it's closely related).

By T.net user Freeaqingme, Friday 31 December 2010 21:03

YopY, you're right that Design Patterns aren't specifically meant for keeping "oversight" over your code. However, this post discusses MVC, and MVC happens to be a pattern that does maintain a good oversight of code by separating logics. MVC may indeed be an architectural pattern, but I think that architectural patterns are simply a subsection of design patterns. After all, MVC also is a common solution to a common problem. See also the definition of design patterns on Wikipedia:
In software engineering, a design pattern is a general reusable solution to a commonly occurring problem in software design. [...] It is a description or template for how to solve a problem that can be used in many different situations.
Furthermore, I think it's a bit far fetched to say that my definitions are off. As I mentioned already there are many defiinitions and interpretations of each design pattern, and that doesn't necessarily mean that one is more right than the other. Though, I'd like to be convinced why the view can't retrieve the data it needs from the modellayer (yet no one has been able to). There's absolutely no need for the controller to be a man in the middle - that only obfuscates things.

[Comment edited on Friday 31 December 2010 21:03]


By T.net user Barleone, Sunday 02 January 2011 00:21

Freeaqingme wrote on Friday 31 December 2010 @ 03:12:
Well, first of all, I would suggest not using useDefaultControllerAlways. I would suggest using a route with url /* so that all urls are mapped to that route. This would allow you to later on add other functionality that doesn't require the index controller (and action).
Maybe I'll do that after the first release of my ZF app, if applicable. I still need ZF default routing stuff for another ZF module in my ZF app.
Having said that, I would change the action to something that merely passes on the requested pagetitle to the view. Then inside your view you could call your modellayer, and retrieve the page (to then display it).
To my opinion, that would be crossing the line to what's exceptable. MVC isn't there for nothing, and a View should not interact with Models.
If your sitemap depends on user parameters, you could take a look at front controller plugins. These are classes that get called on every page request, and therefore allow you to perform controller related stuff that is necessary with each page load without having to duplicate any code. In your front controller plugin (probably in a method named preDispatch()) you could then pass on the user parameters required to build your sitemap on to your layout.
My sitemap does not depend on user parameters, but it is dynamic and stored in a database. Actions, Controllers and Views actually don't exist except for the IndexController and index.phtml.
Whether your sitemap is dependent on user parameters or not, you should (imho) construct that inside your layout, or a viewhelper getting called from inside your layout. The layout (or viewhelper) can just pull its data from your modellayer, there's no need for your controller to do that! If you haven't done so already, you may want to look at Zend_Navigation. This is a component that helps you set up a navigation menu and sitemap in a matter of minutes.
My IndexAction() retrieved db stuff and creates a nice array() to provide the View. The View then reads the array and creates its html. However, I'm working on a ZF Navigation based solution.
If you want more tips on how to incorporate all different pieces ZF provides into one application, you may want to checkout the (free!) book, Surviving the deep end.
I read parts of the book earlier this week. The author also likes to use Model-aware Views, blegh.
[...]
Beware, if it works for you, it works. Design Patterns are no solid rules, they're sets of guidelines that can be used to hold on to. It does not mean that you need to adhere to it to the letter. When your application grows, this will eventually become impossible. Also, there are thousands of interpretations of each Design Pattern out there, so please use them as something that helps you, not something that limits you.
I understand, and since I'm ignorant enough, I'm looking forward to figure things out myself. ;) No seriously, thanks for sharing your thoughts on ZF MVC. d:)b

[Comment edited on Sunday 02 January 2011 00:26]


By T.net user Avalaxy, Friday 07 January 2011 19:02

Nice explanation, thanks :)

Comment form
(required)
(required, but will not be displayed)
(optional)

Please enter the code from the image below: