MVC vs PAC


#1

at the expense of flexibility and the addition of repeated binding logic. The *******ised approach tightly couples the controller to the template and in some cases, the model, essentially locking everything together and making it inflexible. Keep in mind, it's the misunderstanding of the MVC model in the first place that caused this mess ( http://blog.astrumfutura.com/2008/12/the-m-in-mvc-why-models-are-misunderstood-and-unappreciated/ ) In any non-trivial application (and if you're using MVC your application will fall into "non-trivial") MVC models are not domain models. They're designed to exist as a bridge between the domain and the GUI. As such, it makes perfect sense for Views to know of them.

As I've said before, the reason that we call PAC "MVC" in the web world is that people were trying to implement MVC. The architecture was stumbled upon by people accidentally missing the point of MVC. The original MVC architecture was created by academics who thought very carefully about what they were trying to achieve and it offers many advantages over the pseudo-MVC most frameworks offer. And the web actually lets you create a purer implementation of the architecture because you don't have to worry about refreshing views to account for state changes in the model.


Refactoring to MVC
#2

Genuine request here... perhaps you could start with the code from the "From Flat PHP to Symfony2" article I linked to above, just before the article adds "a Touch of Symfony2," and show additional step-by-step refactoring. Show a situation where you lose flexibility or repeat logic, and how you would fix that problem.


#3

Ok smile I'll use the first part of their example, a list of posts.

Firstly, here's a domain model which provides very generic accessors to the domain state. I won't supply the full PDO backend but you can see what it's doing from the model API.

class Posts {
	private $pdo;
	
	public function __construct(PDO $pdo) {
		$this->pdo = $pdo;
	}

	public function findByField($field, $value, $sortOrder) {
		//Pseudocode, ignore that this won't work...
		return $this->pdo->query("SELECT * FROM posts where $field = $value ORDER BY $sortOrder");
	}


	public function findAll($sortOrder) {
		//Pseudocode, ignore that this won't work...
		return $this->pdo->query("SELECT * FROM posts ORDER BY $sortOrder");
	}

	public function findById($id) {
		//Pseudocode, ignore that this won't work...
		return $this->pdo->query("SELECT * FROM posts where id = $id");
	}
}

This is going to be reused throughout the application anywhere that posts are required.

Next, here's a generic View which contains the logic that is common across any type of list:

class ListView {
	private $model;
	private $template;

	public function __construct(ListViewModel $model, Template $template) {
		$this->model = $model;
	}

	public function output() {
		$this->template->assign('items', $this->model->getRecords());
		return $this->template->output();
	}
}

And an interface to provide an API for the getRecords method:

interface ListViewModel {
	public function getRecords();
}

Now we're ready to link the domain model to the GUI via a Model (MVC model, ViewModel, Application Model. Whatever terminology you want to use). The important distinction is that this holds application state rather than domain state. Since we're listing every single post, the application state is that "All posts have been selected". Not a great example. but I'll come to that later:

class EveryPostList implements ListViewModel {
	private $posts;

	public function __construct(Posts $posts) {
		$this->posts = $posts;
	}

	public function getRecords() {
		return $this->posts->findAll('date desc');
	}
}

Since there is zero user interaction in a simple list there is no controller!

Now we just wire everything up:

$template = new Template('postList.tpl');
$posts = new Posts($pdo);

$model = new EveryPostList($posts);
$view = new ListView($model, $template);

echo $view->output();

Advantage 1: There is no controller. Controller code is unnecessary by definition when there is no user interaction.

Advantage 2: Because the controller isn't acting as an entry point and template selection is done by the router (or elsewhere within the front controller) it's easy to use a different template and I don't need to create another controller, I just wire everything up differently.

Advantage 3: Everything is reusable. Let's say I only want posts by a specific user. I add a new Application model and just wire everything differently.

class UserPostList implements ListViewModel {
	private $posts;
	private $userId;

	public function __construct(Posts $posts, $userId) {
		$this->posts = $posts;
		$this->userId = $userId;
	}

	public function getRecords() {
		return $this->posts->findByField('userId', $this->userId, 'date DESC');
	}
}

I don't need to add a new controller just to achieve this, I just wire all the existing components differently:

$template = new Template('postList.tpl');
$posts = new Posts($pdo);

$model = new UserPostList($posts, 123);
$view = new ListView($model, $template);

echo $view->output();

Everything has been reused but I can wire this exact code with a different template, a different model, a view which paginates the list, etc.

Anywhere I want a list of posts I can use this View and template combination along with the relevant application model that bridges the gap to the domain reducing repeated code dramatically.

Advantage 4: Because the controller isn't doing View Selection, nesting views works with ease. Let's say I want to compare the posts of two users side by side. I already have the ability to get a list of all posts by a specific user, so that code can easily be reused:

class NestedView {
	private $views = array();
	private $template;

	public function __construct(Template $template) {
		$this->template = $template;
	}

	public function addView($name, View $view) {
		$this->views[$name] = $view;
	}

	public function output() {
		$this->template->assign('children', $this->views);
		return $this->template->output();
	}
}

And it just gets wired up:

$posts = new Posts($pdo);

$view = new NestedView(new Template('compareTwoUsers.tpl');;
$view->addView('user1', new ListView(new UserPostList($posts, 123), new Template('postList.tpl')));
$view->addView('user2', new ListView(new UserPostList($posts, 321), new Template('postList.tpl')));


echo $view->output();

The template would then do something like:

<div style="width: 50%; float: left">
	<h2>First user's posts:</h2>
	<?php echo $this->children['user1']->output(); ?>
</div>
<div style="width: 50%; float: left">
	<h2>Second user's posts:</h2>
	<?php echo $this->children['user2']->output(); ?>
</div>

This is for demonstration, In reality I have a helper function in the template which builds the nested views. I basically supply a route such as $this->getView("/usersposts/123") and it uses the same router as the main application to build the MVC triad and return the view.

Advantage 5: Controllers become agnostic of everything else.

It's not unreasonable that in the example above I'd want to show the posts of a specific user rather than hardcoding it at the wiring stage! In fact, it's almost certain. This is information that's needed from the user and as such is where the controller is genuinely needed.

Let's take our "Posts by a specific user" ViewModel from earlier, and amend it slightly:

class UserPostList implements ListViewModel {
	private $posts;
	private $userId;

	public function __construct(Posts $posts) {
		$this->posts = $posts;
	}

	public function setUser($id) {
		$this->userId = $id;
	}

	public function getRecords() {
		return $this->posts->findByField('userId', $userId, 'date DESC');
	}
}

I've made the userId mutable. It's the controllers job to set this state based on user input:

class UserPostController {
	private $userPostList;

	public function __construct(UserPostList $userPostList) {
		$this->userPostList = $userPostList;
	}

	public function setUser($id) {
		$this->userPostList->setUser($id);
	}
}

Imagine the router is routing /user/postlist/123 to $userPostController->setUser(123)

Trivial stuff, but it's powerful. The viewModel doesn't care where/how it's being used. The view doesn't need a controller in order to exist and all the classes in the system really are this simplistic.

Ok, that's simple. Let's go back to the nested view. I'll have a route such as /user/postcompare/123/321 to compare the posts of user 123 with user 312. I simply create a controller to allow for it:

class UserPostCompareController {
	private $userPostList1;
	private $userPostList2;

	public function __construct(UserPostList $userPostList1, UserPostList $userPostList2) {
		$this->userPostList1 = $userPostList1;
		$this->userPostList2 = $userPostList2;
	}

	public function setUsers($user1, $user2) {
		$this->userPostList1->setUser($user1);
		$this->userPostList2->setUser($user2);
	}
}

The two instances of UserPostList would be the same as the ones passed to the nested view:

$posts = new Posts($pdo);

$view = new NestedView(new Template('compareTwoUsers.tpl');;

$postList1 = new ListView(new UserPostList($posts), new Template('postList.tpl'));
$postList2 = new ListView(new UserPostList($posts), new Template('postList.tpl'));

$view->addView('user1', $postList1);
$view->addView('user2', $postList2);


$controller = new UserPostCompareController($postList1, $postList2);

//The dispatcher would do this
$controller->setUsers($_GET['arg1'], $_GET['arg2']); 

echo $view->output();

And here, everything is reusable. Essentially any view can pull in any view with ease because Views don't have their logic tied up in controllers.

Advantage 6: Actually this is more of a side-effect of better separation of concerns, but it's still an advantage: Controllers, views and models don't need to extend from weighty base classes. Controller, view and ViewModel code in my framework really is that sparse. You program the bare minimum around interfaces.

Going back to the original user list, I can add a ViewModel and a Controller to deal with any set of criteria, e.g. searching the posts

class SearchablePostsList implements ListViewModel {
	private $posts;
	private $criteria;

	public function __construct(Posts $posts) {
		$this->posts = $posts;	
	}
	
	public function setCriteria($criteria) {
		$this->criteria = $critera;
	}

	public function getRecords() {
		//Query the model based on the criteria
		$return $this->posts->find('......');
	}

}

class SearchablePostsController {
	private $model;

	public function __construct(SearchablePostsList  $model) {
		$this->model = $model;
	}

	public function main() {
		//Do something with posts and set:
		$this->model->setCriteria('...whatever!');

	}
}

Any part of the system can be reused, I can reuse these viewmodels with different controller (perhaps one that uses GET and one that uses POST), I can reuse the controllers with different views. I can substitute the model entirely. For example. I might make a domain model which extends Posts and always filters out posts by a specific user unless you're logged in as an admin (All domain logic) and pass it in as $posts when I wire everything up.

I'm afraid I don't have time to go any further this evening but feel free to ask any specific questions! Hopefully this will help shed some light on this approach.

I'd like to see how you'd achieve similar in Symfony without ugly hacks such as invoking a controller when there hasn't been any user input, or ugly inheritance trees.


#4

Sorry, it's too late for me to edit but the wiring code for the nested view with the controller should look like this:

$posts = new Posts($pdo);

$view = new NestedView(new Template('compareTwoUsers.tpl');;

$postList1 = new UserPostList($posts));
$postList2 = new UserPostList($posts));

$view->addView('user1',  new ListView($postList1, new Template('postList.tpl'));
$view->addView('user2',  new ListView($postList2, new Template('postList.tpl'));


$controller = new UserPostCompareController($postList1, $postList2);

//The dispatcher would do this
$controller->setUsers($_GET['arg1'], $_GET['arg2']); 

echo $view->output();

#5

I certainly appreciate all the effort you put in. When I asked for a step-by-step refactoring, I was kinda hoping to start at the first step of identifying the problem -- a concrete example where you lose flexibility or where you have to repeat logic. This looks like you went straight to the last step, your final solution, and skipped the intermediate refactoring steps.

This part in particular puzzled me, because your "wire it up" code seems to be doing what other frameworks use the controller for -- fetch data, pass it to a template, and render. Except you've eliminated the controller, and now this code lives in some undetermined place. (You vaguely suggested it might live in the router or the front controller.)


#6

The problem is, it's not a controller. By definition "A controller can send commands to its associated view to change the view's presentation of the model (e.g., by scrolling through a document). It can also send commands to the model to update the model's state (e.g., editing a document)." giving it the job of constructing object trees breaks the Single Responsibility Principle which in turn violates separation of concerns, the controller shouldn't be concerned with where its model or view come from.

As to where it goes, In any framework you need somewhere that initialises the right controller based on the route. You move that logic up to there to the top level of the application. And you'll notice that the view is the only place which has access to the template. The point is separation of concerns. Of course all the same jobs need to be done, the goal is to separate them to give the application more flexibility.

Edit: This isn't an MVC issue per se, it's a front controller issue, I was just trying to demonstrate why giving the view access to the model is beneficial.


#7

We both already know that a framework controller doesn't fit the definition of an MVC controller, so let's forget about the terminology for now. Let's say frameworks have a collection of WireItUp classes. The router defines which WireItUp class should be invoked for a given route, and the front controller ultimately instantiates the WireItUp object. The WireItUp object proceeds to fetch data and render a template.

This seems to fit what you're describing, yet all I've done is stop using the word "Controller" and replaced it with "WireItUp".


#8

Except that isn't all they do.

Ignoring the definition of a controller....

1) Where do you handle user actions? Surely not in your WireItUp object? That's an instant SRP violation.

2) How do you decide how to initiate the WireItUp object and which one to use for a given route? This has to be done somewhere. Whatever you call it, you need an entry point that makes some decisions on how the top level of the application will work.

3) The initial discussion was about Views accessing data from models directly which was what I was trying to address. The frameworks you describe all extract some data from the domain model and pass it directly to the view and then output the view. What I was trying to demonstrate was the benefit from a distinction between an MVC model and a domain model as well as a specific view layer. What I was trying to demonstrate was the flexibility added by introducing ViewModels which act as a bridge between the domain and the GUI.


#9

The only action available to the user is the HTTP request, which means the router, at least in part, handles user actions. And any form processing -- at least in Symfony -- is done in separate form and validation classes. So whereas a WireItUp object would farm that work out to a controller, instead Symfony's controller farms that work out to a form class.

With config files. I'd think every application, whether pure MVC or no, needs a place to associate routes with WireItUps/Controllers.

I thought the original question was more generally about the relationship between views, models and controllers. Perhaps I was mistaken.


#10

I disagree. A HTTP request isn't a user action. This highlights a very poor separation of concerns. The MVC triad is for the GUI it should not be concerned whether the user action is triggered by a HTTP request or, like a desktop application, an in-memory pointer between a button on a form to a controller. From a software architecture point of view, there is zero difference between sending this request via HTTP or window messages, callbacks and references to objects in memory. All this stuff is abstracted away in any other language. In a Java MVC applications running on windows you wouldn't worry that the initial request was actually triggered with a win32 API call. The application developer simply should not be concerned with such low level underlying architecture. HTTP is no different.

As such, none of this has any impact on the merits of PAC vs MVC. From what I can tell, your reasoning for using PAC over MVC is that PAC requires a simpler front controller. Which honestly says nothing about the merits of one architecture over the other.

With config files. I'd think every application, whether pure MVC or no, needs a place to associate routes with WireItUps/Controllers.

Exactly my point. You need a config file. Configure the wiring there and skip the "WireitUp" object entirely. All you're left to deal with as an application developer is something to handles the user action, which funnily enough neatly fits the definition of an MVC controller.

I thought the original question was more generally about the relationship between views, models and controllers. Perhaps I was mistaken.

It was, but specifically the differences between PAC and MVC. Which in this case is the role of a controller as a gateway between the model and the view.

It seems to me, you're imposing restrictions on the software architecture based on your own inability to sufficiently abstract the underlying architecture. Which may be a valid reason to pick a certain software architecture, but it certainly doesn't add anything to the debate about which architecture is better because you're not discussing the software architecture (MVC or PAC), you're basing your decision on the limitations you've decided to impose on the underpinning technology.


#11

How else can the user interact with our application? Everything the user does is translated by the browser into a request. From the perspective of our server-side application, the HTTP request is the only way we get any input from the user.

Much more than just the front controller is simpler. The view will never need to respond to user input, nor will it need to respond to changes in the model, because there isn't any input beyond the one-time only HTTP request. And a view that doesn't need to respond to anything or update for anything is basically a template. A one-time only rendering. If we try to build a technically correct MVC view that responds to input that will never come and updates for model changes that won't happen, then we'll be building functionality that will never be needed in a server-side web application. Likewise, a technically correct MVC controller would have little or nothing to do in a server-side web application, since there is only one kind of input that happens one time only. PAC seems a much better fit for web applications, and it's no coincidence that that's how all the major frameworks have been built, even if they have the wrong name for the pattern.

So the config file would list what data to fetch and what template to render...? That seems... awkward.

... it certainly doesn't add anything to the debate about which architecture is better because you're not discussing the software architecture (MVC or PAC), you're basing your decision on the limitations you've decided to impose on the underpinning technology.

Well... yeah. We know we're writing web applications. If we wrote our code in such a way that they could become desktop applications with little or no change, then we're going to be spending a lot of effort on functionality that realistically will never be used.


#12

In a Windows desktop application the only way to get any input from the user is via window messages. There's no such thing as buttons, there's just clicks at co-ordinates on the screen. These underlying events are very dumb. The windows API function calls don't have concepts of "buttons", "objects", "controllers" or any such high level components, simply that a click was registered at certain co-ordinates. It's the technology you're working with, be it .NET, Java, C++, Delphi that translates these low level events into anything that is meaningful to the application and routes it back to the correct memory location for the action that you, as the developer, has registered to trigger when a click is registered at certain co-ordinates.

From the perspective of our desktop application, the windows event is the only way to get any input from the user.

This event might contain things like what type of event it was, click, keypress, mouse movement etc but they all come in a very basic format which generally comes in as "The user has done something". Simpler than HTTP even.

It's down to the technology to abstract these low-level messages into a format that is meaningful to the application. In a Win32 application the creation of a button at a low level would hook into the click event and if the co-ordinates of the click were in the same place as the button it would intercept the event, and call the function that the application developer had chosen to associate with the click. There may be a hundred different callbacks registered to the click event, it's up to some internal decision making that's usually abstracted by the programming language or a library within it to decide which registered callback needs to be triggered. This is exactly what our router does in PHP. This is no different to HTTP, we're told a user "has dome something" and we can send across some relevant information about what they have done.

You are too concerned with imposing restrictions on yourself because there are some technical challenges to think through. If they're that worrysome, abstract them away and never think about them again!

In my opinion, you're approaching the problem from the wrong end. You're starting off by deciding the limitations of the technology and picking an architecture which can work within those limitations. My approach is to decide which is the best architecture and then work around any limitations that come up, if they even exist in the first place (Which I'd argue they don't!). As such, take a step back. Which is better for a developer to use: MVC or PAC, or something else? Answer that first. Then you can see if there are any limitations.

Much more than just the front controller is simpler. The view will never need to respond to user input, nor will it need to respond to changes in the model, because there isn't any input beyond the one-time only HTTP request. And a view that doesn't need to respond to anything or update for anything is basically a template. A one-time only rendering. If we try to build a technically correct MVC view that responds to input that will never come and updates for model changes that won't happen, then we'll be building functionality that will never be needed in a server-side web application. Likewise, a technically correct MVC controller would have little or nothing to do in a server-side web application, since there is only one kind of input that happens one time only. PAC seems a much better fit for web applications, and it's no coincidence that that's how all the major frameworks have been built, even if they have the wrong name for the pattern.

It's true that we don't need to refresh the view. But this is an optional part of MVC. The key difference between MVC and PAC for us as web developers is that in MVC the view requests data from the model instead of being fed it by the controller. This is for separation of concerns only. Everything else is irrelevant, it makes no difference if the view needs to be refreshed or indeed what it needs to do. It's an issue of pure OOP theory and not one of practicality and is totally unaffected by the underlying techology.

So the config file would list what data to fetch and what template to render...? That seems... awkward.

The config would just map a route to the various components. Exactly what any router does only contains metadata about which controller to initiate (if any), which view to initiate and what parameters need to be passed to those components. This allows a true separation of concerns because any component can be easily reused anywhere.


#13

I think we finally stumbled on the core of this debate: Whether to pick an architecture that is useful in any application environment, or to pick an architecture that is specifically tailored for web applications.

My preference -- and I'd confidently wager the preference of the vast majority of web developers -- is for the latter. It comes down to effort vs payoff. Our web applications will almost certainly never be used as desktop applications. And if that scenario never materializes, then the payoff never materializes. And if there's no payoff, then it seems like wasted effort.


#14

That seems like a cop out to me. I've demonstrated several times in several threads including this one how MVC benefits us over PAC as web developers and despite hefty debates, the only responses I get are either philosophical: "The tree fell in the forest while I was away but it's back exactly how I left it every time I return. I don't consider it a real tree." or argumentum ad populum: "Everyone else does it this way". What I've yet to see is anyone show the benefits of PAC over MVC or point out any real-world issues with applying MVC proper on the web.


#15

You've posted lots of code, but it still isn't clear to me where the benefits appear. That's why I wanted to see step-by-step refactoring that starts from a concrete example that demonstrates the problem your code attempts to solve.

Pretty sure my points of view never involved a tree. And even in retrospect, I think my responses have been very concrete (not philosophical), such as effort vs (lack of) payoff, asking where wire-up code is supposed to live, and asking for step-by-step refactoring.


#16

This is an interesting conversation but I feel the debate about PAC versus MVC is not just of web versus non-web but also about type of web project.

Web projects come in many forms, you have product development which can be software as a service and is long life cycle with many hands versus build release and forget development( short running microsites etc. ). Programming practices for both are not completely interchangeable due to the type of development pace they promote and types of debt they incur( rapid prototype versus long term feature change stable ).

Short fire and forget development by its nature can often ignore the pay the debt phase that long term development has to do to stay alive so some practices can turn seriously detrimental to the health of a product by killing velocity.

My main problem with all frameworks except the micro frameworks is that to be popular they try and cover both these bases leaving a pretty schizoid design process and a lot rules have to be applied at a human team level of what can be done done and how it should be done. This in turn is very tiring as it leads to a lot of whys, actually it is far more hassle than say Zend 1 as an MVC framework actually solves.

What should be focussed on is as a business owner which methodology promotes the highest truck/bus number http://en.wikipedia.org/wiki/Bus_factor and also promotes the ability to unit test versus integration test as that can be the difference between 10 minutes or 3 hours after coding finished to release to an integration environment causing development traffic jams. As developers we serve businesses so we need to think about long term team productive management versus initial release point so we sometimes need think more like business owners.

I haven't had much sleep as today I have to feature cost on a balls up of a Zend framework project( a lot due to the practices it promotes such as helper brokers being used as some form of monkey patching dependency inversion technique ) and whenever I think about that project I get very angry so my brain is not at its best coherance. So my question is Tom what benefits does PAC give and what benefits does it take away and in contrast what does a purer MVC offer and also what does it take away?


#17

The problem with step by step refactoring of that problem is that you're starting off with an example that has made a lot of assumptions and there are a thousand steps. Even the symfony example page takes a lot of code/writing to explain how to get to a very simplistic point. The problem is, the differences between PAC and MVC don't show themself until after that point.

Consider this endpoint from that page:

// src/Acme/BlogBundle/Controller/BlogController.php
namespace Acme\\BlogBundle\\Controller;

use Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller;

class BlogController extends Controller
{
    public function listAction()
    {
        $posts = $this->get('doctrine')->getManager()
            ->createQuery('SELECT p FROM AcmeBlogBundle:Post p')
            ->execute();

        return $this->render(
            'AcmeBlogBundle:Blog:list.html.php',
            array('posts' => $posts)
        );
    }

    public function showAction($id)
    {
        $post = $this->get('doctrine')
            ->getManager()
            ->getRepository('AcmeBlogBundle:Post')
            ->find($id)
        ;

        if (!$post) {
            // cause the 404 page not found to be displayed
            throw $this->createNotFoundException();
        }

        return $this->render(
            'AcmeBlogBundle:Blog:show.html.php',
            array('post' => $post)
        );
    }
}

This is basic PAC. The controller queries the model and passes the result to the view. There are several issues here, I'll try to go through them step by step.

Let's add a listByUserAction that lists all the posts by a specified user:

public function listByUserAction($userId)
{
    $posts = $this-&gt;get('doctrine')-&gt;getManager()
        -&gt;createQuery('SELECT p FROM AcmeBlogBundle:Post p WHERE p.userId = ' . $userId)
        -&gt;execute();
    return $this-&gt;render(
        'AcmeBlogBundle:Blog:list.html.php',
        array('posts' =&gt; $posts)
    );
}

As you can see it involves a lot of repeated code. In actual fact the only thing that's changed is the query.

To use that same logic with a different template, I have to repeat the logic yet again:

    public function listWithAdifferentTemplate($userId)
    {
        $posts = $this->get('doctrine')->getManager()
            ->createQuery('SELECT p FROM AcmeBlogBundle:Post p WHERE p.userId = ' . $userId)
            ->execute();

        return $this->render(
            'AcmeBlogBundle:Blog:list-alternative.html.php',
            array('posts' => $posts)
        );
    }

Here all the data-fetching logic has been repeated. And I need to do it a fourth time if I want the full list with a different template.

Problems with this system:

1) I add a "published" flag that each user can set when a blog is added to decide whether it's visible or not. I now need to go through an manually edit each query because I repeated it.

2) I add a second variable "heading" to the template. I now need to go through every single method that's using the template, find what the variable should be and supply it to the template.

3) Common logic for things like pagination, form processing and listing records must be repeated every time it's needed rather than defining it once and reusing it.

4) How do I reuse this code? I want to display two lists of posts, use my example from before, comparing the posts of two different users side by side. It's simply not easy. The most convenient method is doing two queries in the controller and passing two data sets to the view. Repeated code galore.

5) With this code in particular, it breaks the Law of Demeter. Why is a Doctrine object being searched for by the controller (Tell, don't ask). Why does it need to inherit from a base class? This class has a horribly weighty API: http://api.symfony.com/2.0/Symfony/Bundle/FrameworkBundle/Controller/Controller.html Considering most controllers will never use most of these methods it's very poor Separation of Concerns.

How does MVC proper fix these problems?

1) The query and all the logic surrounding it is stored in one reusable place, the MVC Model and it's fully interchangeable without affecting anything else. I demonstrated this earlier in the topic. Essentially it becomes a change in one place instead of a change in every place.

2) Because there's less repeated code, this is a change in one place. The MVC Model. I change any models which will be used with that template. Because this model is reusable it's one change per model, rather than one change per instance of the template. Secondary to that... in the Symfony example, how do I find everywhere that's using the template? In MVC everything is API based so I can extend the interface:

interface ListViewModel {
     public function getRecords();
     public function getHeading();
}

Now I know that any class which implements ListViewModel will need an additional method adding. In fact, my IDE, Zend Studio even picks this up for me and highlights anywhere I've defined a class that implements ListViewModel and doesn't supply all the methods. I don't have to traipse around the entire codebase looking for duplication of: "return $this->render(
'AcmeBlogBundle:Blog:list-alternative.html.php',
array('posts' => $posts)
);"

and potentially adding some code to resolve $heading, then supply $heading to the template.

3) This logic goes in the view and is fully reusable. Pagination is a good example. How do you do it in symfony? Repeat the logic in every controller/template because you don't have a proper view.

4) I demonstrated this earlier. Because the controller isn't doing view selection, Views can be used without a controller and very easily nested. And because they have their own instance of a model with its own state, two instances of the same view can easily be created with two instances of the model and everything is reusable with ease. I'm genuinely interested in how this is achieved in PAC. Every example I've seen has involved either ugly hacks using inheritance, controller action chaining or creating a new instance of the whole triad within the controller. And what's worse, because the controller has access to GET/POST it's likely that it's using POST['user'] to decide which user information to show. This is an instant killer of reusability.

5) This is more than likely just poor design on Symfony's part but it goes a long way in demonstrating the competence of the developers and if they can't understand why Law of Demeter violations are bad or why inheritance trees should be avoided, are they really in a position where they are able to fully comprehend the subtle differences between MVC and PAC? Probably not. They probably used PAC because they copied everyone else rather than thinking about what they were actually trying to achieve. In fact, I suspect that they don't even know what MVC is. They used PAC because they'd learnt MVC from another web framework and hadn't even considered the prospect of giving the view access to the model. Once again it seems that the PAC architecture exists here entirely accidentally rather than due to any kind of informed decision making process.

Pretty sure my points of view never involved a tree. And even in retrospect, I think my responses have been very concrete (not philosophical), such as effort vs (lack of) payoff, asking where wire-up code is supposed to live, and asking for step-by-step refactoring.

I've yet to see any demonstration of how MVC is more effort. In fact my point was that it reduces complexity but making components reusable and removing the binding logic and repeated code entirely. Answer this: Why is PAC better than MVC?


#18

I've officially split the original thread into two threads, primarily because the topic changed focus to MVC vs PAC and I think that makes sense as a thread of its own. Plus I feel the OP was afraid to post back after the debate got started, so hopefully cleaning up his original thread will grant him the option of returning and asking any additional questions about his MVC/PAC implementation.

I do hope this conversation continues as there is a lot of good information here that many will be happy to read.

Thanks,
cpradio


#19

Nonetheless, it seemed like our nu-uh/ya-huh discussion would continue indefinitely on these forums unless one day we can settle it with simple, concrete, step-by-step refactoring examples. You could even reuse whatever you write for your site.

I see and acknowledge that repeated code. Though, I'm skeptical that the best solution is rearchitecting the whole system. It seems to me that common code between any two controller actions could be resolved simply with a private method within the controller. For example, if you wanted to isolate the list rendering code or the data fetching code:

class BlogController extends Controller
{
    // ...

    private function renderList($items)
    {
        return $this->render(
            'AcmeBlogBundle:Blog:list.html.php',
            array('posts' => $items)
        );
    }

    private function getPostsByUserId($userId)
    {
        $posts = $this->get('doctrine')->getManager()
            ->createQuery('SELECT p FROM AcmeBlogBundle:Post p WHERE p.userId = ' . $userId)
            ->execute();

        return $posts;

        // A little further into the refactoring process,
        // and Symfony projects would actually move this data fetching code
        // into a PostRepository class
    }
}

Pagination can be and is reused. In templates, it would look something like this:

{{ pager.render('AcmeBlogBundle:Blog:pagination.html.twig') }}

Form processing can be and is reused. The form itself and validation rules are defined in their own classes, so all the controller has to do is:

if ($form->isValid()) {
}

In all these cases, when we run into any code repitition, we simply isolate the common parts into their own method or their own class, which I think is pretty standard refactoring. So now the question is: would rearchitecting the whole system make this easier? And I, at the very least, would like/need to see how that refactoring would progress.

Now that we've isolated the data fetching code, I think it's straightforward how you would reuse it. Your own code, in fact, also makes two different queries, and it does so in your WireItUp code, which we already know is analogous to a framework controller. Moreover, your own code also passes two data sets to the view. Your compareTwoUsers template is passed "user1" and "user2".

Normally I'd have to grant you this one, but in Symfony, extending the base controller is completely optional, and it exists only for convenience. The Symfony docs/book goes on to describe how you can define your controllers as standalone, injectable objects. My impression is that not many people using Symfony bother to do that, and the reason, I suspect, is once again effort vs payoff. An injectable object is typically easier to unit test, but in this case, unit testing a controller pretty much means you're actually doing functional testing, and it's actually more convenient to fill your database with test data than it is to create a mock doctrine object for injection. A standalone, injectable controller would also be easier to transplant into any other framework, but since no one ever really intends to even try that, this is another payoff that will never materialize. And so people typically opt for the convenience of the base controller.

Ditto in Symfony.

Ditto in Symfony.

In Symfony, pagination logic exists in one place within the controller, and one place within the template. I showed above how query logic can be isolated, and templates can use either "include" or "render" to reuse template partials or to reuse the output from other controllers.

Ditto in Symfony.

Based on all the above, it seems there's an awful lot about Symfony you didn't know, and your assumptions about it thus far simply haven't been accurate.


#20

So basically it's an OOP vs Procedural debate now? Chaining methods in this manner sacrifices: Polymorphism - I can't substitute a method with another method very easily (I need to use inheritance just to achieve this). And Encapsulation - The application state is shared among every controller action.

I see and acknowledge that repeated code. Though, I'm skeptical that the best solution is rearchitecting the whole system. It seems to me that common code between any two controller actions could be resolved simply with a private method within the controller. For example, if you wanted to isolate the list rendering code or the data fetching code:

The problem here is that as far as I'm aware, most programmers are not clairvoyant. Look at the example from earlier, it wasn't written this way to begin with and in most cases wouldn't ever be. You, the application developer has had to go back and modify code which is currently working 100% for its original goals. You've gone back and re-structured the entire application based on the needs of a change which happend after-the-fact. This means re-testing all your old code and making sure you haven't broken anything.

As I said, it's an OOP vs procedural debate at this stage. In OOP it's easy to substitute any part of the application. Now you've moved it into a procedural level by passing state between functions this isn't possible without hacks such as inheritance (Which isn't the right tool for this job, and creates immense scalability issues). Try to completely change the implementation of getPostsByUserId() for a specific controller but keep everything else the same. Nope. Not without a dodgy workaround or changing the controller code and repeating logic.

Pagination can be and is reused. In templates, it would look something like this:

Forgive me, but that code is far from self explanatory. Pagination logic involves knowing the total number of records, the number of records to display per page and what page is currently being viewed. I can see none of that there.

Form processing can be and is reused. The form itself and validation rules are defined in their own classes, so all the controller has to do is:

It's not just the processing though, it's the display logic surrounding the form. The logic for whether the view should show any errors, what variables are available in the view, etc.

Now that we've isolated the data fetching code, I think it's straightforward how you would reuse it. Your own code, in fact, also makes two different queries, and it does so in your WireItUp code, which we already know is analogous to a framework controller. Moreover, your own code also passes two data sets to the view. Your compareTwoUsers template is passed "user1" and "user2".

Two queries are run. Only one is actually coded. There is a difference here, it's subtle i'll admit but it's important. The distinction is that each MVC triad has its own state and can be isolated within the application. At the same time, any part of either of the triads can be substituted for something else. I could be, for instance, comparing the posts in one database to the posts in another by substituting the model in one of the triads. There would be 4 classes defined, two models, one controller and one view. Both instances of the view would be of the same class (but different instances), both instances of the controller would be the same class (but different instances) and the two models differ entirely, they could have different dependencies, different configurations, anything. But since they're loosly coupled to everything else and abide by encapsulation rules, this isn't a problem.

This is where the flexibility happens. Because OOP affords us Encapsulation and Polymorphism, I can re-use and substitute in and out any of the components with ease. Using procedural style methods in a "controller" class limits this flexibility. You're tied into an implementation because it has to be $this->method(). You can work around that in a very ugly way with inheritance but your controller is still forced to know of all the dependencies used by any of the methods. In my database example, it needs access to a model which accesses the first database and a model which accesses the second database. Not good!

This is messy. It reduces portability because nothing is isolated. I can't just copy certain features between projects because everything is tied together. In my other project I want the list posts by users funtionality but there is only one database so I the compare 2 databases method wont work... and I can't even initiate the class because the second dependency doesn't exist.

It's very basic OO theory: A class should have a single responsibility. It affords it reusability and will inevitably mean it has fewer dependencies making it portable as well.

Normally I'd have to grant you this one, but in Symfony, extending the base controller is completely optional, and it exists only for convenience. The Symfony docs/book goes on to describe how you can define your controllers as standalone, injectable objects. My impression is that not many people using Symfony bother to do that, and the reason, I suspect, is once again effort vs payoff. An injectable object is typically easier to unit test, but in this case, unit testing a controller pretty much means you're actually doing functional testing, and it's actually more convenient to fill your database with test data than it is to create a mock doctrine object for injection. A standalone, injectable controller would also be easier to transplant into any other framework, but since no one ever really intends to even try that, this is another payoff that will never materialize. And so people typically opt for the convenience of the base controller.

I'd argue the reason that few people do this because Symfony controllers have too many responsibilites (See Flaw: Class Does Too Much. Each controller action in Symfony is performing a single task. In OOP this should be its own object. And why does a controller have a render method?! That's absurd. It's clearly view logic!
Why is it view logic? Because the controller should not be concerned with any implementation details about the view. As it stands, the controller initiates the view which means it's impossible to use a different template system without modifying the controller! That is truly ridiculous.

Ditto in Symfony.

I think you missed the point here.. but again it's an OOP vs procedural debate.

In Symfony, pagination logic exists in one place within the controller, and one place within the template. I showed above how query logic can be isolated, and templates can use either "include" or "render" to reuse template partials or to reuse the output from other controllers.

This was the point I was getting at. "Template partials" are pointless because you have to supply the data to them, which means fetching it from somewhere and repeating the data fetching logic. I want to pull in a stateful object. I want a reusable component. I want to call a simply functon such as $this->getView('/user/details/123'); from any other view and without any additional work have it pull in a table of details for a specific user.

Actually, this hits the nail on the head. This is why using a controller action to configure the application is a bad idea. It's not easily reusable so you can't instantly create a MVC triad with the same configuration from anywhere, it's tied to the outside world.

Ditto in Symfony.

This was about Views being reusable. They simply ARE NOT in Symfony. You must supply the data every single time you use a view which means at worst re-writing the data fetching logic or at best re-writing the binding logic each and every time. In MVC you create the views and pass it a model and everything just works.

Based on all the above, it seems there's an awful lot about Symfony you didn't know, and your assumptions about it thus far simply haven't been accurate.

I don't claim to be an expert at Symfony, I don't like it because it uses PAC. That's what I have a problem with, Symfony itself is irrelevant.