Comments are inline :)
>I just wanted to get some more information on some things you've been saying
>and get a feel from the angle you are coming from.
>
>See I've covered and developed this type of model architecture (domain
>model) on a framework we had developed in house and it just seemed too much
>work, somewhat bloated and at the end it was confusing.
>
>We had a domain model, which through the use of a TableDataGateway locator,
>acquired instances of Table Data Gateways (some models needed more than one
>TDGs and different models would be required in a process).
>
>We saw a lot of:
>
>public function save($data) {
> $this->_table->save($data);
>}
>
>public function add($data) {
> $this->_table->insert($data);
>}
>
>public function delete($data) {
> $this->_table->delete($data);
>}
>
>After a while it makes you sick and think, well, why didn't we just make the
>Table Data Gateway itself the model instead of being a proxy to the Table
>Data Gateway?
Inheritable magic methods ;). If you use a specific mapping convention, you can create a __call() method among other things to proxy calls to a proxied layer of the Model (i.e. the data access object). Why duplicate a zillion methods when you can just filter incoming calls for matching proxy calls and divert them internally to where its appropriate?
>We reassured ourselves by telling each other that it was because we wanted
>to make the application be able to handle more than one data source and less
>coupling which "stinks" there's also the old "What if we wanted to use
>another data source? like the file system for instance?" (ahh right...
>yes... best to stay flexible)
Do be careful though - in a round about way using the multiple source excuse won't fly in reality. Will you really really really use a different data source?
>So off we went into our merry way with our "proxy" domain model.
>
>As Zend came about and matured, we decided to adopt it and tried out the
>extend Zend_Db_Table_ABSTRACT class - this time, we tried just using the
>Table Data Gateway
>as the model itself.
Here's the problem though - it couples you to the data access structure binding each Model to a specific table. That's why Zend_Db will never fully replace a true ORM. I get the feeling your main difficulty was in ORM can do on the fly, mapping. Zend_Db (indirectly) presumes a 1:1 relationship between Models and database tables which limits the directions your Model can take, which hamstrings them when applying Model design from the outside-in (starting with Model API and working back to the database).
>At this point in time, we really can't see any downsides. Less code, less
>indirection. Room to refactor into bigger and better model layers... We feel
>it's a win/win so far.
Not to misunderstand me, if your Model is truly that simple than work away. I don't preach everlasting loyalty and obsessive worship when practical reality determines a simple solution. Complexity for complexity's sake rarely pays well :).
>What I want to know is why you have decided to move away from this type of
>model and shift to how we were doing it?
Probably because of my environment - we work on enterprise applications where the Model is like the sand beneath your feet. It's always shifting, it's broad and complex, and simple table mapping just doesn't work very well. A Model can conceivably pull and push from a lot of database tables (and other sources in this day and age). Instead you end up looking down towards the database, rather working up from it. So you develop your Model, constantly mocking out data access (since the business rules must be carefully and exhaustively tested) and then worry about how to fit the bugger in a database structure (as indicated by the Mocked out interfaces you happen to develop alongside everything else). It sounds messy, but if you use short iterations and constantly apply refactoring it's not as crazy a process as you might think. Mainly it just requires patience and a little faith. My best buddy in the last year for explaining the process is Behaviour-Driven Design. Calling a Unit Test a Test in TDD disguises that it's intent is to explore, understand and specify behaviour, not verify that "Stuff Works".
>My team and I are pretty much pragmatic and are always open to reasonable
>best practice, so it would be good to get your angle on it.
>
>> I am not so keen on this method anymore. This is how I have done it up
>> until now, but what you are returning from getList() are instances of
>> Zend_Db_Table_Row_Abstract. Which means that other parts of the code
>> could theoretically do something like:-
>
>> $user_one->id = 0;
>> $user_one->save();
>
>Say that we make it so that the records produced by "getList()" is a read
>only array?
>Say that we decided to use setFetchModel(Zend_Db::FETCH_ASSOC); to produce
>more generic array output?
>Would it still be invalid?
>
>> If we assume that "id" is an auto_increment primary key, what business
>> does any other part of the application have changing that id?
>
>Models work with Controllers... so... controllers have the right to morph
>model, right?
Controllers map user intent to Models. In a weird way, only Models alter Models :). Controllers are ignorant, stupid, lowly translators of intent into a form the Model can use (typically just other Model calls!). For example, a user might submit an Order with a payload of data. The Controller picks up that it's a newly submitted Order, locates the Order Model, and tells it to do it's thing for a new Order with the following data. What the Model does after that is a mystery to the Controller - it's completed its function by translating the HTTP request into a Model action.
That was the main message of my article - we're over reliant on Controllers and leaving behind stripped down Models. In my method, I can run a battery of new Order tests on the Model directly; under the other alternative I'd have to test via the Controller which is...not exactly pretty. Ever tried to apply TDD to a Controller? It's not worth the pain until you get as far as needing acceptance tests when your View is more finalised.
>Models are read only to views and controllers can change the model as
>required.
>
>> Instead what I am working on at the moment, is based around the idea
>> that my models will "use" Zend_Db(_Table/_Row) not extend them. This
>> means that the database access is locked away from the rest of the
>> program, so if you are working with a team of developers, there is
>> much less chance of someone making a mistake like the one above.
>
>I know what you're saying, but is it really a mistake? I don't understand.
>Controller uses the model and there are strict rules in dev teams for views
>not to change the model. For instance, the team I lead know better than to
>have
>model morphing functionality where they do not belong.
By the same logic we could do away with type hinting, APIs, and indeed classes :). It's sort of an accepted idea that if you leave the window open, some scoundral will climb through and leave your house in a bit of a mess. It's better to enforce a specific API and be as closed and narrow as possible to discourage undocumented dependencies that will play havoc when you go to refactor and realise much later than these untested access points are really used, and are now thoroughly broken.
If you want direct data access through the Model then fine, but expose it in a controlled tested way.
>> It also means that your models should match your application closer,
>> and expose less public code. This makes your application more
>> decoupled and should make it easier to maintain.
>
>It could also bloat your model and over complicate things.
Sure, it could. It's a judgement call like every other facet of programming. There are applications where needing a Model (in the theoretical sense) is borderline silly. If all your application does is redisplay data from a database - does it need a horrible mess? Probably not. Domain modelling and using fully decoupled Models is not a universal law - it's an generally advisable solution not the rule of law. I promise - I won't hunt you down and execute anyone! :)
>> I came up with something like:-
>
>> class User {
>> protected _table;
>> protected _id;
>> protected _name;
>>
>> public function getId(){ return $this->_id; }
>>
>> public function getName(){ return $this->_name; }
>> public function setName( $value ){ $this->_name = $value; }
>>
>> public function setTableHandler( Zend_Db_Table_Abstract $table )
>> { $this->_table = $table; }
>
>> public function __construct( ){ }
>>
>> public function save(){
>> // Use $this->_table to save the row.
>> }
>>
>> public function load(){
>> // Use $this->_table to load the row.
>> }
>>}
>
>> At first, this may seem like you would be needlessly creating a lot of
>> get and set methods, but a good IDE will be able to make snippets for
>> you to reduce the typing, and if you are doing something like test
>> driven development, then is only a small increase in the grand scheme
>> of things.
>
>Uhk! see this is why we decided to steer away from this type of model.
>There's too much sh!t! How is this better than using Zend_Table data gateway
>as the model?
It could use a more efficient proxy, but in the right Model it makes sense. Who says load() maps to one table only? It could be aggregating from a dozen. Or two. Either way the matching of proxy methods is a simple exercise in isolating the data access which makes adding additional tasks to those methods far easier than being forced to extend/adapt the existing Zend_Db methods. It looks silly in a really simple Model matching just one table - that's not always the case.
>What I'm seeing here is that you're using the Zend TDG as a data source for
>your data source. but TDG already has a data source - (the table)
It's using TDG as a general access API to the datasource - you could use pure ext/mysqli (nothing wrong with that either). TDG automates a lot of the CRUD however instead of building it from scratch. Models generally don't give a toss where the data comes from and how - so long as it has access to something else which does.
>As for relying on a good IDE, code templates and phing can only get you so
>far.
Far enough in my opinion. Painful repetition begs for automation ;).
>> Also, whose job is it to make sure your data values are in correct
>> ranges? For arguments sake, lets say we are modelling a car. We might
>> have something like:-
>
>> class Car {
>> protected $_num_gears;
>> protected $_current_gear;
>>
>> public function __construct( $gears ){
>> $this->_num_gears = $gears;
>> $this->_gear = 0; // neutral (-1 could be reverse! )
>> }
>>
>> public function ChangeUpGear(){
>> $this->_current_gear++;
>> }
>> public function ChangeDownGear(){
>> $this->_current_gear--;
>> }
>> public function SelectGear( $gear ){
>> $this->_current_gear = $gear;
>> }
>> }
>
>> Now it's pretty obvious where you would add extra code to make sure
>>that your gear selections are within the allowed ranges. For example,
>>if I tried to SelectGear(6) in a 5 gear car, I could throw an
>>exception. Then if any other parts of my code attempted to do it, I
>>would know right away - if I were using the models return from
>> Zend_Db_Table->fetchAll(), I would not!
>
>I see this and I think that it's obvious that the validation logic would
>fall upon the controller, no?
If you're Modelling a Car, it might be a good idea to let the Model know the Car only has 4 gears. It wouldn't be a very useful Model if you had to keep telling it that minor detail :). So the argument can be made that Models should be self-validating. Why would a user-intent-translator be the only one to know?
>To me I see it as models being dumb and returning data from the data source.
I suggest calling them data access classes then. A Model is called a "Model" because it presents a behavioural model of some system.
>Controller layer handle requests, which includes validation.
>
>> $user->loadFromArray( array('id' => 0) );
>
>> I am thinking I am going to move towards putting the loadFromArray()
>> functionality so that it is protected and you have to pass the array
>> of data to the constructor. This would make it much harder to
>> accidentally update the wrong value in the model.
>
>This may be over engineering things. By thinking in the way of "This would
>make it much harder to
>accidentally update the wrong value in the model", you're going into
>something which the framework developers are there to worry about.
Framework developers don't care about the Model. Will Zend_Db or Rails ActiveRecord make sure your Car has at least four wheels? Or that you can't tell the database a Car has one wheel? Such logic ruling data safety and integrity is entirely in your hands.
>You're delving into writing code for others you do not trust - either that,
>or creating extra loops for yourself to dive into.
>
>This is natural if you're just learning OOP and have read all the books.
>
>I myself have been through: GOF, Refactoring, POEAA, Head First design
>patterns and when you first read it you're full of ideas. Afterward though,
>you realise that half the stuff do not relate to PHP.
Every tiny portion of those books absolutely relate to PHP and every other programming language in the Universe. Even the non-OOP ones! They form the basis of a universal knowledge you can apply everywhere. If you have that, any other programming language is reduced to mere syntactical differences and use cases.
I really encourage you to resist that mindset.
>> Pauls approach is what I would consider good practice when it comes to
>> models, you are breaking OO inheritance by extending your models from
>> Zend_Db_Table. Models should have a has-a not is-a relationship with
>> models.
>
>It is, if you put it the way you have put it and you extend concrete
>classes,
>but what if you're extending Zend_Db_Table_Abstract which is an abstract
>class, it's not "breaking OO inheritance"
>also... what does that mean?
>
>> I recently complained (i.e. ranted) on the topic over at
>> http://blog.astrumfutura.com/archives/373-The-M-in-MVC-Why-Models-are-Misunderstood-and-Unappreciated.html
>
>Beautiful article.
>
>I get where you're coming from Most controller logic belongs to the domain
>model so we created a domain model for this type of stuff, but the standard
>everywhere I looked was to have "control" logic in the controller - what
>about form and form validation etc? This is handled in the controller at the
>moment. If I were to validate forms in the controller and validate data in
>the model ( to keep it skinny), I'd be validating all over the place - so
>I'd move my form into the Domain model.
Why not? <evil grin> ;)
Models are self-aware of their own limits, so they are the perfect place to generate validation rules. Might take extra work and thought since it's poorly documented and regarded in the PHP community's dearth of articles and blogs but it makes it no less a valid approach. Controllers are not Models - why should they know things a Model doesn't?
>Which again works as a proxy... which in this case may not be that bad...
>don't know not going to delve too deep into that one.
>
>RE Views should be able to fetch their own data - I TOTALLY agree with you -
>In the old framework we were using that we had created, the view had access
>to a local model locator which the controller is also free to use.
>
>Model locator knew how to create models and was the gateway to accessing
>models. What about forms? currently forms are fed into the view from the
>controller. Will views be able to fetch their own forms also? if so, does it
>work the same way as the model? being used by the view and the controller?
The way I've done it previously is separating the form generation from the Controller, encasing it in a View Helper, and feeding it the Model to generate forms. You can even create a generic class for creating simple forms from the Model with little involvement. The tricky part (dodgy!) is that Zend_Form couples a few things closely so you also need to reference the form object from within the Model but you view it as a validation process (and part of the Model) it's not so bad. The main block is when you consider it as adding forms to Models (not the precise truth despite being technically correct - we're adding the form merely to access the validation rules).
>> I generally prefer to avoid the inherited-from route. It's appropriate if
>> all you're doing is data > access (not the real use of a Model) but it
>> tightens the coupling between your Models and the
>> underlying framework. Ideally Models are unaware of the framework, the
>> acid test being able > to quickly port them from one framework to another
>> with little to no change.
>
>But say that you've developed the model specifically for use with the
>framework and had simple requirements such as "getList()" - will it still be
>wrong then?
>
>I've always seen the domain model as something to develop toward as your
>requirements increase instead of using it as a starting point.
It's not a universal truth - people have developed from both directions with great success. If you want a real mind bender look for an article by Martin Fowler written about the practice of using Mock Objects. He identifies two popular approaches which equate to outside-in or inside-out. Anybody who preaches one, and doesn't acknowledge the other, is failing to be a good teacher.
>> The has-a relationship works much better and tends to be more suitable for
>> web applications
>> which don't require or need a huge amount of modelling. Since it's outside
>> the Model
>> inheritance tree and included by composition instead (composition over
>> inheritance!), it also
>> makes it simple to Mock when performing testing. Quite useful if you're
>> designing a Model and
>> pushing TO the database level, rather than the common designing Models
>> FROM an existing
>> database schema.
>
>Yeah composition over inheritance... but these ideas need to be applied
>wisely instead of blindly being plastered onto anything that inherits
>something from somewhere.
True, but I said I use Mock Objects. My development approach is based on TDD and BDD where mocking from the external API into additional APIs (uncovered by Mocks - and sometimes called groping in the dark for something you just know is there...somewhere :)) is pretty common. I blame that on my past experience - PHP unfortunately has a problem in that the only real Mocking feature out there is in SimpleTest (PHPUnit's pretty much sucks so badly it's embarrasing). I had an idea about an independent mocking library but I haven't persued it beyond a concept library I wrote alongside (another concept library) called PHPMock.
If you want to justify it mentally - If I develop a Car Model, why would it inherit from a data access class? Maybe I want it to inherit from a Vehicle class instead? If that's the case, where does the data access go???
This is why composition works - it's more flexible and removes one limiting factor on Models which are powered by Model Inheritance trees. Almost any Model can have subtypes which are difficult to manage if everything is bound to one specific table.
>For example, inheriting from a class that is intended to be an abstract
>class - Zend_Db_Table_Abstract, while tying you into the framework, provides
>you with convenience.
>
>You do know that you need to create a concrete child of the Zend_Db_Table
>class to be able to use it right? it's an abstract class - so your TDG is
>going to be inherited anyway - this is practically a point where a principle
>like "composition over inheritance" does not apply too much unless of course
>you intend to immediately apply domain model pattern which I think is
>overkill for most web apps which just need to read the database and like I
>said work as a proxy for the data source.
>
>Anyway, we're straying a little here - I'm really interested in the reasons
>why you guys have decided to shift to where you've shifted mainly because
>I've made the decision to move away from the exact same thing. While Pad's
>post somewhat gave me his angle as to why, I'm just really trying to
>understand other peoples reasons.
>
>Look forward to your replies.
Hope the replies made sense. :) Don't take it as raining on your parade - there are practices which are overkill for web applications in many scenarios. They just don't immediately make everything else pointless and without reason.
Best regards,
Paddy
Pádraic Brady
http://blog.astrumfutura.com
http://www.patternsforphp.com
OpenID Europe Foundation Member-Subscriber
From: rvdavid <rvdavid@devproducts.com>
To: fw-mvc@lists.zend.com
Sent: Tuesday, December 9, 2008 8:38:01 PM
Subject: Re: [fw-mvc] Another Model Design Thread
Hey guys,
I just wanted to get some more information on some things you've been saying
and get a feel from the angle you are coming from.
See I've covered and developed this type of model architecture (domain
model) on a framework we had developed in house and it just seemed too much
work, somewhat bloated and at the end it was confusing.
We had a domain model, which through the use of a TableDataGateway locator,
acquired instances of Table Data Gateways (some models needed more than one
TDGs and different models would be required in a process).
We saw a lot of:
public function save($data) {
$this->_table->save($data);
}
public function add($data) {
$this->_table->insert($data);
}
public function delete($data) {
$this->_table->delete($data);
}
After a while it makes you sick and think, well, why didn't we just make the
Table Data Gateway itself the model instead of being a proxy to the Table
Data Gateway?
We reassured ourselves by telling each other that it was because we wanted
to make the application be able to handle more than one data source and less
coupling which "stinks" there's also the old "What if we wanted to use
another data source? like the file system for instance?" (ahh right...
yes... best to stay flexible)
So off we went into our merry way with our "proxy" domain model.
As Zend came about and matured, we decided to adopt it and tried out the
extend Zend_Db_Table_ABSTRACT class - this time, we tried just using the
Table Data Gateway
as the model itself.
At this point in time, we really can't see any downsides. Less code, less
indirection. Room to refactor into bigger and better model layers... We feel
it's a win/win so far.
What I want to know is why you have decided to move away from this type of
model and shift to how we were doing it?
My team and I are pretty much pragmatic and are always open to reasonable
best practice, so it would be good to get your angle on it.
> I am not so keen on this method anymore. This is how I have done it up
> until now, but what you are returning from getList() are instances of
> Zend_Db_Table_Row_Abstract. Which means that other parts of the code
> could theoretically do something like:-
> $user_one->id = 0;
> $user_one->save();
Say that we make it so that the records produced by "getList()" is a read
only array?
Say that we decided to use setFetchModel(Zend_Db::FETCH_ASSOC); to produce
more generic array output?
Would it still be invalid?
> If we assume that "id" is an auto_increment primary key, what business
> does any other part of the application have changing that id?
Models work with Controllers... so... controllers have the right to morph
model, right?
Models are read only to views and controllers can change the model as
required.
> Instead what I am working on at the moment, is based around the idea
> that my models will "use" Zend_Db(_Table/_Row) not extend them. This
> means that the database access is locked away from the rest of the
> program, so if you are working with a team of developers, there is
> much less chance of someone making a mistake like the one above.
I know what you're saying, but is it really a mistake? I don't understand.
Controller uses the model and there are strict rules in dev teams for views
not to change the model. For instance, the team I lead know better than to
have
model morphing functionality where they do not belong.
> It also means that your models should match your application closer,
> and expose less public code. This makes your application more
> decoupled and should make it easier to maintain.
It could also bloat your model and over complicate things.
> I came up with something like:-
> class User {
> protected _table;
> protected _id;
> protected _name;
>
> public function getId(){ return $this->_id; }
>
> public function getName(){ return $this->_name; }
> public function setName( $value ){ $this->_name = $value; }
>
> public function setTableHandler( Zend_Db_Table_Abstract $table )
> { $this->_table = $table; }
> public function __construct( ){ }
>
> public function save(){
> // Use $this->_table to save the row.
> }
>
> public function load(){
> // Use $this->_table to load the row.
> }
>}
> At first, this may seem like you would be needlessly creating a lot of
> get and set methods, but a good IDE will be able to make snippets for
> you to reduce the typing, and if you are doing something like test
> driven development, then is only a small increase in the grand scheme
> of things.
Uhk! see this is why we decided to steer away from this type of model.
There's too much sh!t! How is this better than using Zend_Table data gateway
as the model?
What I'm seeing here is that you're using the Zend TDG as a data source for
your data source. but TDG already has a data source - (the table)
As for relying on a good IDE, code templates and phing can only get you so
far.
> Also, whose job is it to make sure your data values are in correct
> ranges? For arguments sake, lets say we are modelling a car. We might
> have something like:-
> class Car {
> protected $_num_gears;
> protected $_current_gear;
>
> public function __construct( $gears ){
> $this->_num_gears = $gears;
> $this->_gear = 0; // neutral (-1 could be reverse! )
> }
>
> public function ChangeUpGear(){
> $this->_current_gear++;
> }
> public function ChangeDownGear(){
> $this->_current_gear--;
> }
> public function SelectGear( $gear ){
> $this->_current_gear = $gear;
> }
> }
> Now it's pretty obvious where you would add extra code to make sure
>that your gear selections are within the allowed ranges. For example,
>if I tried to SelectGear(6) in a 5 gear car, I could throw an
>exception. Then if any other parts of my code attempted to do it, I
>would know right away - if I were using the models return from
> Zend_Db_Table->fetchAll(), I would not!
I see this and I think that it's obvious that the validation logic would
fall upon the controller, no?
To me I see it as models being dumb and returning data from the data source.
Controller layer handle requests, which includes validation.
> $user->loadFromArray( array('id' => 0) );
> I am thinking I am going to move towards putting the loadFromArray()
> functionality so that it is protected and you have to pass the array
> of data to the constructor. This would make it much harder to
> accidentally update the wrong value in the model.
This may be over engineering things. By thinking in the way of "This would
make it much harder to
accidentally update the wrong value in the model", you're going into
something which the framework developers are there to worry about.
You're delving into writing code for others you do not trust - either that,
or creating extra loops for yourself to dive into.
This is natural if you're just learning OOP and have read all the books.
I myself have been through: GOF, Refactoring, POEAA, Head First design
patterns and when you first read it you're full of ideas. Afterward though,
you realise that half the stuff do not relate to PHP.
> Pauls approach is what I would consider good practice when it comes to
> models, you are breaking OO inheritance by extending your models from
> Zend_Db_Table. Models should have a has-a not is-a relationship with
> models.
It is, if you put it the way you have put it and you extend concrete
classes,
but what if you're extending Zend_Db_Table_Abstract which is an abstract
class, it's not "breaking OO inheritance"
also... what does that mean?
> I recently complained (i.e. ranted) on the topic over at
> http://blog.astrumfutura.com/archives/373-The-M-in-MVC-Why-Models-are-Misunderstood-and-Unappreciated.html
Beautiful article.
I get where you're coming from Most controller logic belongs to the domain
model so we created a domain model for this type of stuff, but the standard
everywhere I looked was to have "control" logic in the controller - what
about form and form validation etc? This is handled in the controller at the
moment. If I were to validate forms in the controller and validate data in
the model ( to keep it skinny), I'd be validating all over the place - so
I'd move my form into the Domain model.
Which again works as a proxy... which in this case may not be that bad...
don't know not going to delve too deep into that one.
RE Views should be able to fetch their own data - I TOTALLY agree with you -
In the old framework we were using that we had created, the view had access
to a local model locator which the controller is also free to use.
Model locator knew how to create models and was the gateway to accessing
models. What about forms? currently forms are fed into the view from the
controller. Will views be able to fetch their own forms also? if so, does it
work the same way as the model? being used by the view and the controller?
> I generally prefer to avoid the inherited-from route. It's appropriate if
> all you're doing is data > access (not the real use of a Model) but it
> tightens the coupling between your Models and the
> underlying framework. Ideally Models are unaware of the framework, the
> acid test being able > to quickly port them from one framework to another
> with little to no change.
But say that you've developed the model specifically for use with the
framework and had simple requirements such as "getList()" - will it still be
wrong then?
I've always seen the domain model as something to develop toward as your
requirements increase instead of using it as a starting point.
> The has-a relationship works much better and tends to be more suitable for
> web applications
> which don't require or need a huge amount of modelling. Since it's outside
> the Model
> inheritance tree and included by composition instead (composition over
> inheritance!), it also
> makes it simple to Mock when performing testing. Quite useful if you're
> designing a Model and
> pushing TO the database level, rather than the common designing Models
> FROM an existing
> database schema.
Yeah composition over inheritance... but these ideas need to be applied
wisely instead of blindly being plastered onto anything that inherits
something from somewhere.
For example, inheriting from a class that is intended to be an abstract
class - Zend_Db_Table_Abstract, while tying you into the framework, provides
you with convenience.
You do know that you need to create a concrete child of the Zend_Db_Table
class to be able to use it right? it's an abstract class - so your TDG is
going to be inherited anyway - this is practically a point where a principle
like "composition over inheritance" does not apply too much unless of course
you intend to immediately apply domain model pattern which I think is
overkill for most web apps which just need to read the database and like I
said work as a proxy for the data source.
Anyway, we're straying a little here - I'm really interested in the reasons
why you guys have decided to shift to where you've shifted mainly because
I've made the decision to move away from the exact same thing. While Pad's
post somewhat gave me his angle as to why, I'm just really trying to
understand other peoples reasons.
Look forward to your replies.
regards,
-----
R. Villar David
Lead Developer, DevProducts Pty Ltd
p: +61 2 9648 3777 f: +61 2 9648 6988
w: http://www.devproducts.com
--
View this message in context: http://www.nabble.com/Another-Model-Design-Thread-tp20909700p20922870.html
Sent from the Zend MVC mailing list archive at Nabble.com.
>I just wanted to get some more information on some things you've been saying
>and get a feel from the angle you are coming from.
>
>See I've covered and developed this type of model architecture (domain
>model) on a framework we had developed in house and it just seemed too much
>work, somewhat bloated and at the end it was confusing.
>
>We had a domain model, which through the use of a TableDataGateway locator,
>acquired instances of Table Data Gateways (some models needed more than one
>TDGs and different models would be required in a process).
>
>We saw a lot of:
>
>public function save($data) {
> $this->_table->save($data);
>}
>
>public function add($data) {
> $this->_table->insert($data);
>}
>
>public function delete($data) {
> $this->_table->delete($data);
>}
>
>After a while it makes you sick and think, well, why didn't we just make the
>Table Data Gateway itself the model instead of being a proxy to the Table
>Data Gateway?
Inheritable magic methods ;). If you use a specific mapping convention, you can create a __call() method among other things to proxy calls to a proxied layer of the Model (i.e. the data access object). Why duplicate a zillion methods when you can just filter incoming calls for matching proxy calls and divert them internally to where its appropriate?
>We reassured ourselves by telling each other that it was because we wanted
>to make the application be able to handle more than one data source and less
>coupling which "stinks" there's also the old "What if we wanted to use
>another data source? like the file system for instance?" (ahh right...
>yes... best to stay flexible)
Do be careful though - in a round about way using the multiple source excuse won't fly in reality. Will you really really really use a different data source?
>So off we went into our merry way with our "proxy" domain model.
>
>As Zend came about and matured, we decided to adopt it and tried out the
>extend Zend_Db_Table_ABSTRACT class - this time, we tried just using the
>Table Data Gateway
>as the model itself.
Here's the problem though - it couples you to the data access structure binding each Model to a specific table. That's why Zend_Db will never fully replace a true ORM. I get the feeling your main difficulty was in ORM can do on the fly, mapping. Zend_Db (indirectly) presumes a 1:1 relationship between Models and database tables which limits the directions your Model can take, which hamstrings them when applying Model design from the outside-in (starting with Model API and working back to the database).
>At this point in time, we really can't see any downsides. Less code, less
>indirection. Room to refactor into bigger and better model layers... We feel
>it's a win/win so far.
Not to misunderstand me, if your Model is truly that simple than work away. I don't preach everlasting loyalty and obsessive worship when practical reality determines a simple solution. Complexity for complexity's sake rarely pays well :).
>What I want to know is why you have decided to move away from this type of
>model and shift to how we were doing it?
Probably because of my environment - we work on enterprise applications where the Model is like the sand beneath your feet. It's always shifting, it's broad and complex, and simple table mapping just doesn't work very well. A Model can conceivably pull and push from a lot of database tables (and other sources in this day and age). Instead you end up looking down towards the database, rather working up from it. So you develop your Model, constantly mocking out data access (since the business rules must be carefully and exhaustively tested) and then worry about how to fit the bugger in a database structure (as indicated by the Mocked out interfaces you happen to develop alongside everything else). It sounds messy, but if you use short iterations and constantly apply refactoring it's not as crazy a process as you might think. Mainly it just requires patience and a little faith. My best buddy in the last year for explaining the process is Behaviour-Driven Design. Calling a Unit Test a Test in TDD disguises that it's intent is to explore, understand and specify behaviour, not verify that "Stuff Works".
>My team and I are pretty much pragmatic and are always open to reasonable
>best practice, so it would be good to get your angle on it.
>
>> I am not so keen on this method anymore. This is how I have done it up
>> until now, but what you are returning from getList() are instances of
>> Zend_Db_Table_Row_Abstract. Which means that other parts of the code
>> could theoretically do something like:-
>
>> $user_one->id = 0;
>> $user_one->save();
>
>Say that we make it so that the records produced by "getList()" is a read
>only array?
>Say that we decided to use setFetchModel(Zend_Db::FETCH_ASSOC); to produce
>more generic array output?
>Would it still be invalid?
>
>> If we assume that "id" is an auto_increment primary key, what business
>> does any other part of the application have changing that id?
>
>Models work with Controllers... so... controllers have the right to morph
>model, right?
Controllers map user intent to Models. In a weird way, only Models alter Models :). Controllers are ignorant, stupid, lowly translators of intent into a form the Model can use (typically just other Model calls!). For example, a user might submit an Order with a payload of data. The Controller picks up that it's a newly submitted Order, locates the Order Model, and tells it to do it's thing for a new Order with the following data. What the Model does after that is a mystery to the Controller - it's completed its function by translating the HTTP request into a Model action.
That was the main message of my article - we're over reliant on Controllers and leaving behind stripped down Models. In my method, I can run a battery of new Order tests on the Model directly; under the other alternative I'd have to test via the Controller which is...not exactly pretty. Ever tried to apply TDD to a Controller? It's not worth the pain until you get as far as needing acceptance tests when your View is more finalised.
>Models are read only to views and controllers can change the model as
>required.
>
>> Instead what I am working on at the moment, is based around the idea
>> that my models will "use" Zend_Db(_Table/_Row) not extend them. This
>> means that the database access is locked away from the rest of the
>> program, so if you are working with a team of developers, there is
>> much less chance of someone making a mistake like the one above.
>
>I know what you're saying, but is it really a mistake? I don't understand.
>Controller uses the model and there are strict rules in dev teams for views
>not to change the model. For instance, the team I lead know better than to
>have
>model morphing functionality where they do not belong.
By the same logic we could do away with type hinting, APIs, and indeed classes :). It's sort of an accepted idea that if you leave the window open, some scoundral will climb through and leave your house in a bit of a mess. It's better to enforce a specific API and be as closed and narrow as possible to discourage undocumented dependencies that will play havoc when you go to refactor and realise much later than these untested access points are really used, and are now thoroughly broken.
If you want direct data access through the Model then fine, but expose it in a controlled tested way.
>> It also means that your models should match your application closer,
>> and expose less public code. This makes your application more
>> decoupled and should make it easier to maintain.
>
>It could also bloat your model and over complicate things.
Sure, it could. It's a judgement call like every other facet of programming. There are applications where needing a Model (in the theoretical sense) is borderline silly. If all your application does is redisplay data from a database - does it need a horrible mess? Probably not. Domain modelling and using fully decoupled Models is not a universal law - it's an generally advisable solution not the rule of law. I promise - I won't hunt you down and execute anyone! :)
>> I came up with something like:-
>
>> class User {
>> protected _table;
>> protected _id;
>> protected _name;
>>
>> public function getId(){ return $this->_id; }
>>
>> public function getName(){ return $this->_name; }
>> public function setName( $value ){ $this->_name = $value; }
>>
>> public function setTableHandler( Zend_Db_Table_Abstract $table )
>> { $this->_table = $table; }
>
>> public function __construct( ){ }
>>
>> public function save(){
>> // Use $this->_table to save the row.
>> }
>>
>> public function load(){
>> // Use $this->_table to load the row.
>> }
>>}
>
>> At first, this may seem like you would be needlessly creating a lot of
>> get and set methods, but a good IDE will be able to make snippets for
>> you to reduce the typing, and if you are doing something like test
>> driven development, then is only a small increase in the grand scheme
>> of things.
>
>Uhk! see this is why we decided to steer away from this type of model.
>There's too much sh!t! How is this better than using Zend_Table data gateway
>as the model?
It could use a more efficient proxy, but in the right Model it makes sense. Who says load() maps to one table only? It could be aggregating from a dozen. Or two. Either way the matching of proxy methods is a simple exercise in isolating the data access which makes adding additional tasks to those methods far easier than being forced to extend/adapt the existing Zend_Db methods. It looks silly in a really simple Model matching just one table - that's not always the case.
>What I'm seeing here is that you're using the Zend TDG as a data source for
>your data source. but TDG already has a data source - (the table)
It's using TDG as a general access API to the datasource - you could use pure ext/mysqli (nothing wrong with that either). TDG automates a lot of the CRUD however instead of building it from scratch. Models generally don't give a toss where the data comes from and how - so long as it has access to something else which does.
>As for relying on a good IDE, code templates and phing can only get you so
>far.
Far enough in my opinion. Painful repetition begs for automation ;).
>> Also, whose job is it to make sure your data values are in correct
>> ranges? For arguments sake, lets say we are modelling a car. We might
>> have something like:-
>
>> class Car {
>> protected $_num_gears;
>> protected $_current_gear;
>>
>> public function __construct( $gears ){
>> $this->_num_gears = $gears;
>> $this->_gear = 0; // neutral (-1 could be reverse! )
>> }
>>
>> public function ChangeUpGear(){
>> $this->_current_gear++;
>> }
>> public function ChangeDownGear(){
>> $this->_current_gear--;
>> }
>> public function SelectGear( $gear ){
>> $this->_current_gear = $gear;
>> }
>> }
>
>> Now it's pretty obvious where you would add extra code to make sure
>>that your gear selections are within the allowed ranges. For example,
>>if I tried to SelectGear(6) in a 5 gear car, I could throw an
>>exception. Then if any other parts of my code attempted to do it, I
>>would know right away - if I were using the models return from
>> Zend_Db_Table->fetchAll(), I would not!
>
>I see this and I think that it's obvious that the validation logic would
>fall upon the controller, no?
If you're Modelling a Car, it might be a good idea to let the Model know the Car only has 4 gears. It wouldn't be a very useful Model if you had to keep telling it that minor detail :). So the argument can be made that Models should be self-validating. Why would a user-intent-translator be the only one to know?
>To me I see it as models being dumb and returning data from the data source.
I suggest calling them data access classes then. A Model is called a "Model" because it presents a behavioural model of some system.
>Controller layer handle requests, which includes validation.
>
>> $user->loadFromArray( array('id' => 0) );
>
>> I am thinking I am going to move towards putting the loadFromArray()
>> functionality so that it is protected and you have to pass the array
>> of data to the constructor. This would make it much harder to
>> accidentally update the wrong value in the model.
>
>This may be over engineering things. By thinking in the way of "This would
>make it much harder to
>accidentally update the wrong value in the model", you're going into
>something which the framework developers are there to worry about.
Framework developers don't care about the Model. Will Zend_Db or Rails ActiveRecord make sure your Car has at least four wheels? Or that you can't tell the database a Car has one wheel? Such logic ruling data safety and integrity is entirely in your hands.
>You're delving into writing code for others you do not trust - either that,
>or creating extra loops for yourself to dive into.
>
>This is natural if you're just learning OOP and have read all the books.
>
>I myself have been through: GOF, Refactoring, POEAA, Head First design
>patterns and when you first read it you're full of ideas. Afterward though,
>you realise that half the stuff do not relate to PHP.
Every tiny portion of those books absolutely relate to PHP and every other programming language in the Universe. Even the non-OOP ones! They form the basis of a universal knowledge you can apply everywhere. If you have that, any other programming language is reduced to mere syntactical differences and use cases.
I really encourage you to resist that mindset.
>> Pauls approach is what I would consider good practice when it comes to
>> models, you are breaking OO inheritance by extending your models from
>> Zend_Db_Table. Models should have a has-a not is-a relationship with
>> models.
>
>It is, if you put it the way you have put it and you extend concrete
>classes,
>but what if you're extending Zend_Db_Table_Abstract which is an abstract
>class, it's not "breaking OO inheritance"
>also... what does that mean?
>
>> I recently complained (i.e. ranted) on the topic over at
>> http://blog.astrumfutura.com/archives/373-The-M-in-MVC-Why-Models-are-Misunderstood-and-Unappreciated.html
>
>Beautiful article.
>
>I get where you're coming from Most controller logic belongs to the domain
>model so we created a domain model for this type of stuff, but the standard
>everywhere I looked was to have "control" logic in the controller - what
>about form and form validation etc? This is handled in the controller at the
>moment. If I were to validate forms in the controller and validate data in
>the model ( to keep it skinny), I'd be validating all over the place - so
>I'd move my form into the Domain model.
Why not? <evil grin> ;)
Models are self-aware of their own limits, so they are the perfect place to generate validation rules. Might take extra work and thought since it's poorly documented and regarded in the PHP community's dearth of articles and blogs but it makes it no less a valid approach. Controllers are not Models - why should they know things a Model doesn't?
>Which again works as a proxy... which in this case may not be that bad...
>don't know not going to delve too deep into that one.
>
>RE Views should be able to fetch their own data - I TOTALLY agree with you -
>In the old framework we were using that we had created, the view had access
>to a local model locator which the controller is also free to use.
>
>Model locator knew how to create models and was the gateway to accessing
>models. What about forms? currently forms are fed into the view from the
>controller. Will views be able to fetch their own forms also? if so, does it
>work the same way as the model? being used by the view and the controller?
The way I've done it previously is separating the form generation from the Controller, encasing it in a View Helper, and feeding it the Model to generate forms. You can even create a generic class for creating simple forms from the Model with little involvement. The tricky part (dodgy!) is that Zend_Form couples a few things closely so you also need to reference the form object from within the Model but you view it as a validation process (and part of the Model) it's not so bad. The main block is when you consider it as adding forms to Models (not the precise truth despite being technically correct - we're adding the form merely to access the validation rules).
>> I generally prefer to avoid the inherited-from route. It's appropriate if
>> all you're doing is data > access (not the real use of a Model) but it
>> tightens the coupling between your Models and the
>> underlying framework. Ideally Models are unaware of the framework, the
>> acid test being able > to quickly port them from one framework to another
>> with little to no change.
>
>But say that you've developed the model specifically for use with the
>framework and had simple requirements such as "getList()" - will it still be
>wrong then?
>
>I've always seen the domain model as something to develop toward as your
>requirements increase instead of using it as a starting point.
It's not a universal truth - people have developed from both directions with great success. If you want a real mind bender look for an article by Martin Fowler written about the practice of using Mock Objects. He identifies two popular approaches which equate to outside-in or inside-out. Anybody who preaches one, and doesn't acknowledge the other, is failing to be a good teacher.
>> The has-a relationship works much better and tends to be more suitable for
>> web applications
>> which don't require or need a huge amount of modelling. Since it's outside
>> the Model
>> inheritance tree and included by composition instead (composition over
>> inheritance!), it also
>> makes it simple to Mock when performing testing. Quite useful if you're
>> designing a Model and
>> pushing TO the database level, rather than the common designing Models
>> FROM an existing
>> database schema.
>
>Yeah composition over inheritance... but these ideas need to be applied
>wisely instead of blindly being plastered onto anything that inherits
>something from somewhere.
True, but I said I use Mock Objects. My development approach is based on TDD and BDD where mocking from the external API into additional APIs (uncovered by Mocks - and sometimes called groping in the dark for something you just know is there...somewhere :)) is pretty common. I blame that on my past experience - PHP unfortunately has a problem in that the only real Mocking feature out there is in SimpleTest (PHPUnit's pretty much sucks so badly it's embarrasing). I had an idea about an independent mocking library but I haven't persued it beyond a concept library I wrote alongside (another concept library) called PHPMock.
If you want to justify it mentally - If I develop a Car Model, why would it inherit from a data access class? Maybe I want it to inherit from a Vehicle class instead? If that's the case, where does the data access go???
This is why composition works - it's more flexible and removes one limiting factor on Models which are powered by Model Inheritance trees. Almost any Model can have subtypes which are difficult to manage if everything is bound to one specific table.
>For example, inheriting from a class that is intended to be an abstract
>class - Zend_Db_Table_Abstract, while tying you into the framework, provides
>you with convenience.
>
>You do know that you need to create a concrete child of the Zend_Db_Table
>class to be able to use it right? it's an abstract class - so your TDG is
>going to be inherited anyway - this is practically a point where a principle
>like "composition over inheritance" does not apply too much unless of course
>you intend to immediately apply domain model pattern which I think is
>overkill for most web apps which just need to read the database and like I
>said work as a proxy for the data source.
>
>Anyway, we're straying a little here - I'm really interested in the reasons
>why you guys have decided to shift to where you've shifted mainly because
>I've made the decision to move away from the exact same thing. While Pad's
>post somewhat gave me his angle as to why, I'm just really trying to
>understand other peoples reasons.
>
>Look forward to your replies.
Hope the replies made sense. :) Don't take it as raining on your parade - there are practices which are overkill for web applications in many scenarios. They just don't immediately make everything else pointless and without reason.
Best regards,
Paddy
http://blog.astrumfutura.com
http://www.patternsforphp.com
OpenID Europe Foundation Member-Subscriber
From: rvdavid <rvdavid@devproducts.com>
To: fw-mvc@lists.zend.com
Sent: Tuesday, December 9, 2008 8:38:01 PM
Subject: Re: [fw-mvc] Another Model Design Thread
Hey guys,
I just wanted to get some more information on some things you've been saying
and get a feel from the angle you are coming from.
See I've covered and developed this type of model architecture (domain
model) on a framework we had developed in house and it just seemed too much
work, somewhat bloated and at the end it was confusing.
We had a domain model, which through the use of a TableDataGateway locator,
acquired instances of Table Data Gateways (some models needed more than one
TDGs and different models would be required in a process).
We saw a lot of:
public function save($data) {
$this->_table->save($data);
}
public function add($data) {
$this->_table->insert($data);
}
public function delete($data) {
$this->_table->delete($data);
}
After a while it makes you sick and think, well, why didn't we just make the
Table Data Gateway itself the model instead of being a proxy to the Table
Data Gateway?
We reassured ourselves by telling each other that it was because we wanted
to make the application be able to handle more than one data source and less
coupling which "stinks" there's also the old "What if we wanted to use
another data source? like the file system for instance?" (ahh right...
yes... best to stay flexible)
So off we went into our merry way with our "proxy" domain model.
As Zend came about and matured, we decided to adopt it and tried out the
extend Zend_Db_Table_ABSTRACT class - this time, we tried just using the
Table Data Gateway
as the model itself.
At this point in time, we really can't see any downsides. Less code, less
indirection. Room to refactor into bigger and better model layers... We feel
it's a win/win so far.
What I want to know is why you have decided to move away from this type of
model and shift to how we were doing it?
My team and I are pretty much pragmatic and are always open to reasonable
best practice, so it would be good to get your angle on it.
> I am not so keen on this method anymore. This is how I have done it up
> until now, but what you are returning from getList() are instances of
> Zend_Db_Table_Row_Abstract. Which means that other parts of the code
> could theoretically do something like:-
> $user_one->id = 0;
> $user_one->save();
Say that we make it so that the records produced by "getList()" is a read
only array?
Say that we decided to use setFetchModel(Zend_Db::FETCH_ASSOC); to produce
more generic array output?
Would it still be invalid?
> If we assume that "id" is an auto_increment primary key, what business
> does any other part of the application have changing that id?
Models work with Controllers... so... controllers have the right to morph
model, right?
Models are read only to views and controllers can change the model as
required.
> Instead what I am working on at the moment, is based around the idea
> that my models will "use" Zend_Db(_Table/_Row) not extend them. This
> means that the database access is locked away from the rest of the
> program, so if you are working with a team of developers, there is
> much less chance of someone making a mistake like the one above.
I know what you're saying, but is it really a mistake? I don't understand.
Controller uses the model and there are strict rules in dev teams for views
not to change the model. For instance, the team I lead know better than to
have
model morphing functionality where they do not belong.
> It also means that your models should match your application closer,
> and expose less public code. This makes your application more
> decoupled and should make it easier to maintain.
It could also bloat your model and over complicate things.
> I came up with something like:-
> class User {
> protected _table;
> protected _id;
> protected _name;
>
> public function getId(){ return $this->_id; }
>
> public function getName(){ return $this->_name; }
> public function setName( $value ){ $this->_name = $value; }
>
> public function setTableHandler( Zend_Db_Table_Abstract $table )
> { $this->_table = $table; }
> public function __construct( ){ }
>
> public function save(){
> // Use $this->_table to save the row.
> }
>
> public function load(){
> // Use $this->_table to load the row.
> }
>}
> At first, this may seem like you would be needlessly creating a lot of
> get and set methods, but a good IDE will be able to make snippets for
> you to reduce the typing, and if you are doing something like test
> driven development, then is only a small increase in the grand scheme
> of things.
Uhk! see this is why we decided to steer away from this type of model.
There's too much sh!t! How is this better than using Zend_Table data gateway
as the model?
What I'm seeing here is that you're using the Zend TDG as a data source for
your data source. but TDG already has a data source - (the table)
As for relying on a good IDE, code templates and phing can only get you so
far.
> Also, whose job is it to make sure your data values are in correct
> ranges? For arguments sake, lets say we are modelling a car. We might
> have something like:-
> class Car {
> protected $_num_gears;
> protected $_current_gear;
>
> public function __construct( $gears ){
> $this->_num_gears = $gears;
> $this->_gear = 0; // neutral (-1 could be reverse! )
> }
>
> public function ChangeUpGear(){
> $this->_current_gear++;
> }
> public function ChangeDownGear(){
> $this->_current_gear--;
> }
> public function SelectGear( $gear ){
> $this->_current_gear = $gear;
> }
> }
> Now it's pretty obvious where you would add extra code to make sure
>that your gear selections are within the allowed ranges. For example,
>if I tried to SelectGear(6) in a 5 gear car, I could throw an
>exception. Then if any other parts of my code attempted to do it, I
>would know right away - if I were using the models return from
> Zend_Db_Table->fetchAll(), I would not!
I see this and I think that it's obvious that the validation logic would
fall upon the controller, no?
To me I see it as models being dumb and returning data from the data source.
Controller layer handle requests, which includes validation.
> $user->loadFromArray( array('id' => 0) );
> I am thinking I am going to move towards putting the loadFromArray()
> functionality so that it is protected and you have to pass the array
> of data to the constructor. This would make it much harder to
> accidentally update the wrong value in the model.
This may be over engineering things. By thinking in the way of "This would
make it much harder to
accidentally update the wrong value in the model", you're going into
something which the framework developers are there to worry about.
You're delving into writing code for others you do not trust - either that,
or creating extra loops for yourself to dive into.
This is natural if you're just learning OOP and have read all the books.
I myself have been through: GOF, Refactoring, POEAA, Head First design
patterns and when you first read it you're full of ideas. Afterward though,
you realise that half the stuff do not relate to PHP.
> Pauls approach is what I would consider good practice when it comes to
> models, you are breaking OO inheritance by extending your models from
> Zend_Db_Table. Models should have a has-a not is-a relationship with
> models.
It is, if you put it the way you have put it and you extend concrete
classes,
but what if you're extending Zend_Db_Table_Abstract which is an abstract
class, it's not "breaking OO inheritance"
also... what does that mean?
> I recently complained (i.e. ranted) on the topic over at
> http://blog.astrumfutura.com/archives/373-The-M-in-MVC-Why-Models-are-Misunderstood-and-Unappreciated.html
Beautiful article.
I get where you're coming from Most controller logic belongs to the domain
model so we created a domain model for this type of stuff, but the standard
everywhere I looked was to have "control" logic in the controller - what
about form and form validation etc? This is handled in the controller at the
moment. If I were to validate forms in the controller and validate data in
the model ( to keep it skinny), I'd be validating all over the place - so
I'd move my form into the Domain model.
Which again works as a proxy... which in this case may not be that bad...
don't know not going to delve too deep into that one.
RE Views should be able to fetch their own data - I TOTALLY agree with you -
In the old framework we were using that we had created, the view had access
to a local model locator which the controller is also free to use.
Model locator knew how to create models and was the gateway to accessing
models. What about forms? currently forms are fed into the view from the
controller. Will views be able to fetch their own forms also? if so, does it
work the same way as the model? being used by the view and the controller?
> I generally prefer to avoid the inherited-from route. It's appropriate if
> all you're doing is data > access (not the real use of a Model) but it
> tightens the coupling between your Models and the
> underlying framework. Ideally Models are unaware of the framework, the
> acid test being able > to quickly port them from one framework to another
> with little to no change.
But say that you've developed the model specifically for use with the
framework and had simple requirements such as "getList()" - will it still be
wrong then?
I've always seen the domain model as something to develop toward as your
requirements increase instead of using it as a starting point.
> The has-a relationship works much better and tends to be more suitable for
> web applications
> which don't require or need a huge amount of modelling. Since it's outside
> the Model
> inheritance tree and included by composition instead (composition over
> inheritance!), it also
> makes it simple to Mock when performing testing. Quite useful if you're
> designing a Model and
> pushing TO the database level, rather than the common designing Models
> FROM an existing
> database schema.
Yeah composition over inheritance... but these ideas need to be applied
wisely instead of blindly being plastered onto anything that inherits
something from somewhere.
For example, inheriting from a class that is intended to be an abstract
class - Zend_Db_Table_Abstract, while tying you into the framework, provides
you with convenience.
You do know that you need to create a concrete child of the Zend_Db_Table
class to be able to use it right? it's an abstract class - so your TDG is
going to be inherited anyway - this is practically a point where a principle
like "composition over inheritance" does not apply too much unless of course
you intend to immediately apply domain model pattern which I think is
overkill for most web apps which just need to read the database and like I
said work as a proxy for the data source.
Anyway, we're straying a little here - I'm really interested in the reasons
why you guys have decided to shift to where you've shifted mainly because
I've made the decision to move away from the exact same thing. While Pad's
post somewhat gave me his angle as to why, I'm just really trying to
understand other peoples reasons.
Look forward to your replies.
regards,
-----
R. Villar David
Lead Developer, DevProducts Pty Ltd
p: +61 2 9648 3777 f: +61 2 9648 6988
w: http://www.devproducts.com
--
View this message in context: http://www.nabble.com/Another-Model-Design-Thread-tp20909700p20922870.html
Sent from the Zend MVC mailing list archive at Nabble.com.
没有评论:
发表评论