logo       

Re: Best practices in a thin-controller application: msg#00101

php.zend.framework.mvc

Subject: Re: Best practices in a thin-controller application

Are you sure both Trip and Destination are both equally-weighted
objects of the domain?
May there be a trip without destination?
And does every destination has a trip?

The last one really does not make sense if you talk that sentence.

...

>Feels a little strange to me, as I've always considered the collection
>to be the root of the domain, at least when treating tables and domain
>models as though they were the same thing. Is there a better way?

What do you mean by "root" of domain?
Tables and domain models aren't the same things.
A domain model exists without a table with no problems, persistance is only a technical drawback of software or the need for storing something because we have no chance to let the object live forever.

A user of a system is a user of the system. He doesn't die if he leaves our system. And if he comes back he isn't born again. We only have a problem to reflect this reality concept in software, so most of the time we need a database.
But it's not the problem of the object user...:-)

A domain model is *always* the concept that lives in the real world and in your mind and has to be expressed and materialized with your software.

>The semantics at this point are confusing, because Collection is sort
>of like a table, whereas List is sort of like a rowset...but their
>names don't clearly imply this fact.

Again: don't think in database terms. Never. You wouldn't do it in the real world, why you should in your software?

You use collection for the sum of all your elements in the database.
What is that good for?

Better express your needs it in pure speech:
"Show me a list of all Trips to (from?) France"

Who answers this question?

Think of a collection or list as something like a list on paper.
It's only a list of things (objects) that are not "living", they have no
state, they are only written on something or said by someone.

If you really have a list/collection that has behaviour, that can do something and that could change e.g. its state then you would need to have an object like that.
But do you know any list or collection that lives or has real behaviour?
Me not.

Just a few thoughts. I don't know your exact requirements, so you have to find out yourself. But always try to express the concept in your head and then create a model of that. Don't think of technology like a database.
That is solved somehow.

...

Errors should be there where they make sense.
And entities (domain objects) should never be created (be returned) if their creation has failed but only in a consitent state.
Only if the creation has a state other than "valid" and it is intended to return such an inconsistent object.

Therefore I would replace

$this->view->trip = new Travel_Trip($this->_getParam('id', null));
if ($this->view->trip->failed == Travel_Trip::NOTFOUND) {

with

$this->view->trip = new Travel_Trip($this->_getParam('id', null));
if (!($this->view->trip = instanceof(Travel_Trip))
...error handling...

because $this->view->trip->failed implicits that the object was created properly and has an attribute failed (which seems paradox).


Greetings,
Nino



Adam Jensen schrieb:
Hello!

(I apologize if this gets sent out more than once...my other email
address, Adam.Jensen-gkxvx00wFtQ@xxxxxxxxxxxxxxxx, does not seem to be able to
post to the
lists anymore.)

I'm trying to rethink some of my controller code due to Bill Karwin's
"ActiveRecord does not suck" post, and I'm having some trouble
figuring out where to put what.

Here's an example. Say we're building an application for tracking the
travel schedules of employees. There are two kinds of domain objects:
Trips and Destinations. Every Destination has a Trip, and every Trip
has many Destinations. Users interact with the domain on the Trip
level…they can list, view, add, edit, and delete Trips, adding and/or
removing Destinations in the process. Each of these is represented in
the controller by an appropriately-named action.

So, at this point we have the following classes in the library:

* Travel_Trip
* Travel_Trip_Destination
* Travel_TripsController

The first problem arises when I try to write the "list" action. Each
of the domain objects listed above represents a single entity…none of
the indicated classes is designed to represent a collection. So we
need to add another class for managing the collection:

* Travel_Trip_Collection

Feels a little strange to me, as I've always considered the collection
to be the root of the domain, at least when treating tables and domain
models as though they were the same thing. Is there a better way?

The other problem here is that, while the Travel_Trip_Collection
represents the total collection of Trips in the system, it will need
to return smaller collections of trips in response to particular
method calls. For instance,
Travel_Trip_Collection::fetchAllByCountry('FR') will need to return a
collection containing all trips to France. It doesn't seem right to
use the same collection for this, so we add another class:

* Travel_Trip_List

The semantics at this point are confusing, because Collection is sort
of like a table, whereas List is sort of like a rowset...but their
names don't clearly imply this fact.

Moving on, my next problem is handling user errors in the remaining
methods. Take a look at this:

[code]
public function viewAction()
{
try {
$this->view->trip = new Travel_Trip($this->_getParam('id', null));
} catch (Travel_Trip_Exception_NotFound $e) {
throw new Zend_Controller_Action_Exception('Requested trip not
found.', 404);
}
}
[/code]

This works, but seems a little inappropriate on a couple of levels.
First, I don't think exceptions were meant to be used this way;
they're functioning almost like goto statements, and that makes me
uncomfortable.

Second, we don't get much feedback from the model as to what exactly
the problem is with the user's input. It could be one of several
things:

* The user did not provide an ID parameter.
* The user provided an invalid ID parameter.
* The provided ID number is valid, but does not correspond to any Trip
in the Collection.

In the past I've always tried to do something slightly different for
each of these circumstances, so that the user always knows what was
wrong about his/her request. In order to do this with domain model
exceptions (as above), I'd need three separate exception subclasses,
right?

I suppose the other option for error handling is to have the model
keep track of its own error state…but that introduces extra controller
code for checking the error state, a la…

[code]
public function viewAction()
{
$this->view->trip = new Travel_Trip($this->_getParam('id', null));
if ($this->view->trip->failed == Travel_Trip::NOTFOUND) {
throw new Zend_Controller_Action_Exception('Not found', 404);
}
// check for other error codes as well…
}
[/code]

That's a mouthful; I think I like the exceptions better :)

Anyway, I'm sorry that my questions are not more specific; I'm really
just looking for some clarification as to how the domain layer is
supposed to be implemented, as it's not something I've had much
opportunity to study. Does it look like I'm on the right track, or is
there something I'm missing?

Thanks!

Adam Jensen, Zend Certified Engineer
Web Development
UNT International

jazzslider-Re5JQEeQqe8AvxtiuMwx3w@xxxxxxxxxxxxxxxx
http://www.international.unt.edu





<Prev in Thread] Current Thread [Next in Thread>
Google Custom Search

News | FAQ | advertise