Page 2 of 2

Re: Proper Usage of a Controller

Posted: Wed Jul 29, 2009 12:47 pm
by alex.barylski
well they're back.. and throwing exceptions over non-exceptional cases is so 2002 How do pass those exceptions to the user interface to be shown as error messages? just wondering
$e->getMessage()?
Personally, I don't use autodocs. I don't see much value in it, I document what needs documenting myself (ie, everything that isn't completely self explanatory). Documentation generated just from method definition is not very useful in my opinion (and any good IDE can do that by the way)
IDE dictates a lot of what we as programmers strive for, unfrotunately. A counter argument, would be, a good IDE with refactoring tools would make adding/removing arguments from a method sigature a single operation as well, but it's because PHP is difficult to refactor (being a dynamic language) that forces us to get creative, such as using associatve parameters.

Dynamic programming is awesome, I love it compared to more static programming such as C/C++ however I am also a fan of explicit coding, it's makes everything more clear and easier to understand.

I think we face an interesting dilema as programmers who must:

1. Write code for themselves so it's easier for us to maintain
2. Write code for others to easily understand and learn

Two very different crowds, two different challenges.

Ideally we find a solution that meets both crowds half way.
I'm not talking about one specific field. When updating often you are only updating a partial list of fields (for example, just the username and email). The array approach accepts a partial list of parameters the same as the full list, with the same interface as the create method. Much simpler to implement, maintain and modify.
I agree.
How do you handle a variable number of arguments to update using your approach? do you create mock null variables to pass for the parameters that aren't available, or do you use error suppression? either solution sounds pretty bad
First I would ask, why I need a variable number of arguments? To me, that sounds like a design issue. My views are usually composed of several smaller views, each of those sub-forms (for lack of a better word) are usually mapped one to one with a model method. Updating credential details, personal details, etc.

If their amalgamted into a single form, I would simple multiple model methods in one save operation, alternatively, I might have multiple forms on oe physical page and submit to each individually. Nothing is so monolithic to require lengthly variable parameter lists.

If someone updates their credentials, they POST a form with:

1. Username/Alias
2. Password
3. Password reset
4. Email

4 fields, two of which are optional, in which case they would be passed to the model as empty/null

Code: Select all

updateCredentialDetails($_POST['user'], $_POST['pass1'], $_POST['pass2'], $_POST['email']);
I actually avoid variable parameter lists like the plague, rarely will you ever see that technique used in my code, if the parameter list cannot be broken down into something concrete, I take that as a design smell and begin refactoring until it all fits togather explicitly.

I hated that about MFC and C++ -- very common practice to have overloaded methods in addition to default arguments, it made working with the API very difficult.

Cheers,
Alex

Re: Proper Usage of a Controller

Posted: Wed Jul 29, 2009 1:12 pm
by Eran
$e->getMessage()?
what a thorough response..
So unless you handle your exceptions in your view logic, I'm guessing you somewhere catch those exceptions (controller/model?) push them into an array and pass it to the view? how do those error messages travel from your exception throwing in the model all the way to the model layer?

I throw exceptions just before a fatal error would have occurred, and collect them at the end of the dispatch loop. In such a case I would show an error page. Otherwise return false or something else that allows the program to continue without breaking into a catch block.
First I would ask, why I need a variable number of arguments? To me, that sounds like a design issue.
It's really not, and it's very very common. I'm really surprised you haven't seen it before.
I'm sure you are well familiar with database rows in relational databases. when you insert a new row you have to fill all the fields that are not null or do not have default value, and when you update a row you don't need to update all those fields. In fact, you can update a variable amount of fields. This is useful, since you don't need all the information to update just part of the row.

I mimic this behavior in my update methods, allowing for different use cases to update a variable amount of parameters out of all the parameters available, all using the same validation/filtering logic (using a validation chain of the passed array) - thereby abstracting the update process. Other methods might add some logic before updating (such as comparing passwords etc.) but all defer to the same update method, keeping my validation and filtering centralized in one place in the model while not repeating the same logic multiple times.

Re: Proper Usage of a Controller

Posted: Wed Jul 29, 2009 1:26 pm
by alex.barylski

Code: Select all

what a thorough response..
So unless you handle your exceptions in your view logic, I'm guessing you somewhere catch those exceptions (controller/model?) push them into an array and pass it to the view? how do those error messages travel from your exception throwing in the model all the way to the model layer?
Hahaha...fine...sheesh.

Two step view implementation:

Code: Select all

public function showHomeAction()
{
  $response = $this->getResponse();
  $request = $this->getRequest();
 
  $model = new Model();
  $model->doSomething(); // Validation errors throw exceptions
 
  $response->setRedirect(get_internal_referrer());
}
 
My bootstrap actually implements the try-catch as the boot strap is 'usually' specific to each application in my case (although I use the same one in 99% of cases). Upon exception I determine if it's a userland validation error and redirect or foward to the appropriate referrer and set a message object with the contents of $e->getMessage()
It's really not, and it's very very common. I'm really surprised you haven't seen it before.
I'm sure you are well familiar with database rows in relational databases. when you insert a new row you have to fill all the fields that are not null or do not have default value, and when you update a row you don't need to update all those fields. In fact, you can update a variable amount of fields. This is useful, since you don't need all the information to update just part of the row
Never said I never seen it before, of course I have. :lol:

Monkey see, this monkey not nessecarily do, is all.

My forms/views are design in such a way to accomodate full updates. There is no need to partially update a table unless I'm doing something updating the timestamp after a login, in which case I would implement a updateTimestamp() method.

If someone wants to leave all fields empty in a FORM and POST that, fine, but my validation will possibly complain and stop from posting, optional fields get sent in to the data base and because I implement postback, the default values are what are expected to be posted anwyays.

Cheers,
Alex

Re: Proper Usage of a Controller

Posted: Wed Jul 29, 2009 1:57 pm
by Eran
My bootstrap actually implements the try-catch as the boot strap is 'usually' specific to each application in my case (although I use the same one in 99% of cases). Upon exception I determine if it's a userland validation error and redirect or foward to the appropriate referrer and set a message object with the contents of $e->getMessage()
That's pretty decent, however what about several error messages? at some point you need to aggregate errors in an array-like construct. Why not simply pass an error array to the view? it's also useful in RESTful situations, where you just want to send a serialized array of errors
My forms/views are design in such a way to accomodate full updates.
Don't your models sometimes invoke updates on other models? (as per propagating relationships between them) in such a case often the detail updates are partial. Sure, you can create a method for each singular case, however that approach is not very scalable as the size of the project grows. I need the ability to generically update against a known stack of validators/filters

Re: Proper Usage of a Controller

Posted: Wed Jul 29, 2009 2:06 pm
by alex.barylski
That's pretty decent, however what about several error messages? at some point you need to aggregate errors in an array-like construct. Why not simply pass an error array to the view? it's also useful in RESTful situations, where you just want to send a serialized array of errors
I guess that could be considered a weakness, as multiple errors are not something my framework accomodates. I just don't see a need for it, to be honest, my users have never complained about receving single error messages, and much of what a user does is validated first on the client side, so usually the only errors that get through are things like:
Email address already exists.
Don't your models sometimes invoke updates on other models? (as per propagating relationships between them) in such a case often the detail updates are partial. Sure, you can create a method for each singular case, however that approach is not very scalable as the size of the project grows. I need the ability to generically update against a known stack of validators/filters
My models at one time did, yes, but now I keep them as specific to a table as possible, if there are relations that are above and beyond what my little active record can handle, usually advanced selects, I call up my DBA and ask for a VIEW.

As for cascading deletes, updates, etc, I usually introduce a facade to tie togather the discrete models.

Validation is done *mostly* by the framework (currently using a mapping file) but I'm considering using types and reflection to automatically validate all incoming parameters according to 'type' library I'm currently toying with, we'll see. :)

Cheers,
Alex

Re: Proper Usage of a Controller

Posted: Wed Jul 29, 2009 2:28 pm
by Eran
I guess that could be considered a weakness, as multiple errors are not something my framework accomodates. I just don't see a need for it, to be honest, my users have never complained about receving single error messages, and much of what a user does is validated first on the client side
For me it's a must, since not all of my projects involve client side validation, definitely not for the entire project (think massive administration section). Also, most projects allow at least some functionality with javascript turned off, which requires this. Being able to reuse the error arrays for RESTful implementation (which I've been doing a lot recently) is also a big plus for me.
My models at one time did, yes, but now I keep them as specific to a table as possible, if there are relations that are above and beyond what my little active record can handle, usually advanced selects, I call up my DBA and ask for a VIEW.
That explains a lot - I use Data Gateway and not active-record. Different styles for different patterns, I guess.

Re: Proper Usage of a Controller

Posted: Wed Jul 29, 2009 2:41 pm
by alex.barylski
For me it's a must, since not all of my projects involve client side validation, definitely not for the entire project (think massive administration section). Also, most projects allow at least some functionality with javascript turned off, which requires this.
I hear ya, I validate my applications against every standard I possibly can, this includes making sure the application runs entirely without JS enabled.

It also means that users might be bothered with more than one attempt at trying to submit a form. No one has ever complained, yet, probably because they all had JS enabled. I will probably now, look into a multiple error message reply. Thanks :D
Being able to reuse the error arrays for RESTful implementation (which I've been doing a lot recently) is also a big plus for me.
Not sure I follow, reusing error arrays in RESTful implementations?

I have only experimented wit REST, but they are essentially just REST controllers that would invoke the model directly anyways, so whatever the model returned is what REST or a standard controller would receive back, so there is no duplication.

I personally hardcode all language text and use _() to replace with translated text at runtime, this way my inline text acts as a sort of plain english documentation, I stopped using language CODES years ago, the upkeep was just to dman high and so cryptic after a few months.
That explains a lot - I use Data Gateway and not active-record. Different styles for different patterns, I guess.
My models are not bound to any specific pattern, sometimes I use AR, others I hardcore code the SQL, others still pull on RSS feeds, etc.

It's probably for that consistency I prefer my models to have a strict, clear, well defined API, whereas the implementation typically uses my own version of AR (actually not really but it's as close as pattern as I can find), OO SQL, etc.

I refactor the models probably more than anything, so having the ability to print the interfaces for 20+ models pin them to a wall and hilite sections, indicate changes, etc, is really quite a powerful refactoring tool...imagine that...

Whiteboard, hiliters and Doxygen...a poor mans refactoring tool :D

I like that having to clearly specify the interface to the models, I find keeps me very disciplined and a reminder that all fields must be validated, etc.

Cheers,
Alex

Re: Proper Usage of a Controller

Posted: Wed Jul 29, 2009 2:54 pm
by Eran
Not sure I follow, reusing error arrays in RESTful implementations?
Yep.

Code: Select all

public function sendmessageAction() { //RESTful controller action for adding messages
      $messages = new Messages();
      $result = $messages -> add($_GET);
      if( is_array($result) ) { //$result is an error array
            echo json_encode(array('errors' => $result));
      } else { //Successfully added message, send response code
            echo json_encode(array('success' => 1));
      }
}
In a regular controller, I would just pass the same error array to the view and display it there.
My models are not bound to any specific pattern ... It's probably for that consistency
sounds more like an inconsistency to me?
I find keeps me very disciplined and a reminder that all fields must be validated, etc.
The way I work with the input arrays, is that if a field is not specified in the validation stack, it does not pass. Meaning, I either defined what passes as valid for that field, or that field will not be involved in any insert/update operation. there are no oversights due to "lack of interface", so less discipline is required (the models police themselves)

Re: Proper Usage of a Controller

Posted: Wed Jul 29, 2009 3:53 pm
by alex.barylski
In a regular controller, I would just pass the same error array to the view and display it there.
Hmmm...see I'm thinking...a controller (RESTful or not) would just query the model as per usual, but a RESTful controller would simply use a different template, one which produce JSON array or XML or XHTML or PDF or whatever.
sounds more like an inconsistency to me?
Haha...I suppose it could seem that way but see what I'm thinking is...so many people misunderstand what a model is. People associate it with data patterns like TDG or AR or data mapper and that usually becomes their model, validations creep into the controller and model manipulation looks wild and varied in controllers:

Code: Select all

controller()
{
  $model = DataMapper();
  $model->first_name = 'Alex';
 
  $model->save();
}
Another controller might look like:

Code: Select all

controller()
{
  $model = new TableGateway(array('first_name' => 'Alex'));
  $model->insert();
}
Now both are viable solutions and both can be used "by" a model but neither should be "your" model. A model (IMHO) is an abstraction, more a virtual layer that should wrap the underlying implementation specific libraries, regardless of whether you use straight SQL or ORM.

These models then, have a clearly defined, explicit (albeit concrete) interface that autodocumentors can pick, as can new programmers to a codebase. Not to mention being able to print those interfaces ona whiteboard and mark it up while observeing the big picture.

In this sense, my models API are consistent, more so than what I typically observe in many applications that use a variety of data source management systems.
The way I work with the input arrays, is that if a field is not specified in the validation stack, it does not pass. Meaning, I either defined what passes as valid for that field, or that field will not be involved in any insert/update operation. there are no oversights due to "lack of interface", so less discipline is required (the models police themselves)
Thats not really what I mean with discipline, more in the sense that, discovering a concrete API is a difficult task, especially one that works. I refactor like crazy, because even the slightest name change can make a huge difference (for me anyways). My models are tiny, like all classes, my rule of thumb is less than 50 lines of SLOC and about 12 to 20 per method.

No more than a few member variables. I work with a lot of classes which results in more wiring code, but far more reusability.

Have clear, clean API's is a must for this to work and be readable. I guess my concern would be, if I had a model that had a super function, one that took any number of arguments and saved only those arguments, that the model interactions would start looking like:

Code: Select all

$model->insert$array1);
$model->update($array2);
 
if($a == $b){
  $model->select($array3);
}
Whereas more concrete API,s with explicit arguments, would be:

Code: Select all

$pkid = $model->createUserAccount($user, $email);
$model->updateLastLogin($pkid, $time());
 
if($a == $b){
  $results = $model->selectAllPreviouslyAuthenticatedUsers();
}
I prefer long, verbose, descriptive method names (especially for my models). Part of those descriptions are well named variable names passed to the function (how they are passed -- associative array or explicitly is irrelevant) so your code starts looking like plain english.

Part of my concren fear is that, passing associative arrays as argument lists would result in code that is not as descriptive.

Code: Select all

$model->update($array);
Unless you inlined the array the above is not very descriptive, not like:

Code: Select all

$model->updateUserCredentials($user, $pass);
While I see dynamic programming as a good thing, I also see it possibly allowing for less descriptive code, which being explicit does do.

I don't know what else to say, my model API are strict, clear and concise, and while I refactor a lot, it's not that big of a burden, I pre-plan a lot on paper, which is going to save me a lot of headache at implementation. If your not a big planner, then maybe a less descriptive, more dynamic approach is better suited to your coding style.

Cheers,
Alex

Re: Proper Usage of a Controller

Posted: Wed Jul 29, 2009 4:11 pm
by Eran
People associate it with data patterns like TDG or AR or data mapper and that usually becomes their model
Never said anything about that. I have plenty of models that are neither of those patterns - in fact, some don't use a pattern at all (not all models need persistent storage). What I meant was that for consistency's sake, in my opinion it's best to use one database modeling pattern across the board, instead of mixing-and-matching. That way my base database model class can take full advantage of the pattern it's employing, instead of being oblivious to it.
my rule of thumb is less than 50 lines of SLOC and about 12 to 20 per method.
That means about 2.5 methods per class. Somehow that doesn't sound right. In my case, most methods are between 4-10 LOC, and I don't have an upper limit on many methods in one class (as many as relevant).
I work with a lot of classes which results in more wiring code, but far more reusability.
Reusability? we are talking about domain models here. They are supposed to be specific to the domain they are created for. A 'Users' model in one project would probably be somewhat different from a 'Users' model in another project, as they represent different entities.

I really think that trying to create reusable domain models is not a useful goal to have. The generic and recurring elements you can abstract to a base model class, but the concrete implementations are domain-specific. I go with a class per entity or actor in the system. Adding more classes in order to keep in line with a LOC rule-of-thumb is not something I would do.

Re: Proper Usage of a Controller

Posted: Wed Jul 29, 2009 4:40 pm
by alex.barylski
Never said anything about that. I have plenty of models that are neither of those patterns - in fact, some don't use a pattern at all (not all models need persistent storage). What I meant was that for consistency's sake, in my opinion it's best to use one database modeling pattern across the board, instead of mixing-and-matching. That way my base database model class can take full advantage of the pattern it's employing, instead of being oblivious to it.
I agree but still it's an impossible goal. Models are of varying data sources, obviously a majority RDBMS, but still.
That means about 2.5 methods per class. Somehow that doesn't sound right. In my case, most methods are between 4-10 LOC, and I don't have an upper limit on many methods in one class (as many as relevant).
Most functions have 10 SLOC, I had a script to compute this for me, but I've since lost it. The largest function (of 300+) was like 75 lines and it desperately needed refactoring. I think the average was about 12-15 SLOC.

Rule of thumb...not absolute science :P
Reusability? we are talking about domain models here

Classes in general. Obviously domain models are about the least reusable, second to controllers.

Re: Proper Usage of a Controller

Posted: Wed Jul 29, 2009 4:47 pm
by Eran
Models are of varying data sources
Data sources, not necessarily storage. Some models might be an interface to an internal / external service, a resource manipulation class and so forth. Those do not involve a database.
Classes in general. Obviously domain models are about the least reusable, second to controllers.
We were discussing the different patterns and abstractions for domain models in relation to validation/filtering, So I don't see how that reusability bit is relevant