14

I am using codeigniter, and have found myself in a similar situation where I have repeated Model methods. I am creating a Model per Controller. But I would creating a Model per database table be considered good practice? That way methods aren't written twice.

Instead of Model per Controller or Several small Models that are shared.

Example if I have a model method get_user($user_id) I could write it on users_models.php ...

One of the downsides I see of this is that I might have to call several models, rather than just controllername_models.php .

Could loading several models where several methods might not be used from a controller affect performance and speed? What could be the best way to tackle this down?

Note: There are similar question, but they do not cover the ground of Model per database table.

Howard Steff
  • 141
  • 1
  • 1
  • 3

3 Answers3

10

In general you should create your models not per table or per controller but per business object. Sometimes it maybe a 1:1 relationship with your tables structure or with your controllers, but not necessary.

In your example you may have one users_model class that is called from several controllers. This is fine and sometimes even desirable. However in most cases the users_model class will get its data from several tables.
For example, last_login_date property of the users_model class can (not must) be obtained from a separate user_audit table that has one-to-many relationship with the main users table.

And I would say if you have one SQL table per business object then it is most likely that your database structure is not normalized.

ozz
  • 8,322
  • 2
  • 29
  • 62
Dime
  • 295
  • 1
  • 6
8

I's say that a model per table is just recreating your database in a class structure. It is known as a anemic model and considered an anti-pattern. That is because classes are intended to have both data and behaviour. If you restrict your models to a single table, where do you put the code (behaviour) that needs to deal with data and behaviour from multiple tables? Your controllers would then need models that use one or more of these "table" models... So, apart from in the most basic of apps, you gain little if anything from this approach.

Marjan Venema
  • 8,151
  • 3
  • 32
  • 35
  • Just a bit of an addendum - it's considered an anti-pattern by Martin Fowler. Fullstop here. He has some insight on this case, but that doesn't mean that it's _bad_ - differently from God Object, that is almost always bad, a structure like this is sometimes incredible useful and easily maitenable. I don't consider this an anti-pattern at all. – T. Sar Mar 03 '16 at 18:55
  • 1
    As an example, the "anemic model" is SOLID compliant - is it really bad to have an object with a single purpose (store data)? While I do respect a lot of things that Mr. Fowler says, this one was bullshit. – T. Sar Mar 03 '16 at 20:05
5

I mostly agree with Dime's answer that you want to create your models per business object - the problems that the business is trying to solve should drive how you create the model classes. In practice, I've found that creating one model per table is a good place to start. A properly designed schema is likely to mimic the business processes that you need to model in application code - also called the Domain Model.

Using an Object/Relational Mapping layer is useful so your Domain Model contains the same relationships as the database schema without the need for repetitive calls to a data access layer. Check out Eloquent for PHP as an example. Both the schema and the Domain Model should be designed to support the business processes.

This leads into the first part of Marjan Venema's answer:

I's say that a model per table is just recreating your database in a class structure. It is known as a anemic model and considered an anti-pattern.

An Anemic Domain Model is an anti-pattern. A "model per table" as Venema suggests could be seen as "recreating your database," however it is absolutely incorrect to say this alone is an Anemic Domain Model.

From Martin Fowler:

The basic symptom of an Anemic Domain Model is that at first blush it looks like the real thing. There are objects, many named after the nouns in the domain space, and these objects are connected with the rich relationships and structure that true domain models have. The catch comes when you look at the behavior, and you realize that there is hardly any behavior on these objects, making them little more than bags of getters and setters.

(emphasis, mine)

The key factor in an anemic domain model is a lack of behavior, or methods, on the Domain Model classes.

That is because classes are intended to have both data and behaviour. If you restrict your models to a single table, where do you put the code (behaviour) that needs to deal with data and behaviour from multiple tables?

Again, you can, and should, put behavior in your Domain Models, even if they only map to one table. Behavior that affects multiple tables really affects multiple objects that happen to map to multiple tables. Domain Driven Design is an approach to precisely the same problem Venema mentioned: "where do you put the code (behaviour) that needs to deal with data and behaviour from multiple tables?"

And the answer is an Aggregate Root. Martin Fowler states:

Aggregate is a pattern in Domain-Driven Design. A DDD aggregate is a cluster of domain objects that can be treated as a single unit. An example may be an order and its line-items, these will be separate objects, but it's useful to treat the order (together with its line items) as a single aggregate.

(emphasis, mine)

A "cluster of domain objects" can also be viewed as "Domain Models that map to multiple tables." Behavior that affects multiple tables should be defined on the Aggregate Root - A class that encapsulates the "thing" that affects multiple tables or objects:

Again, from Martin Fowler:

An aggregate will often contain mutliple collections, together with simple fields.

To answer the OP's original question:

... would creating a Model per database table be considered good practice? That way methods aren't written twice.

I would say this is a good place to start, but be aware that your schema and object model do not have to match 100%. The object model should be more concerned with implementing and enforcing business rules. The schema should be more focused on storing business data in a modular and scalable way.

A model per controller would not be good practice, although there is a variation of model called a View Model that does fit into the Controller layer. A View Model is a reorganization of the Domain Model to fit a certain kind of display, be it a web page or form in a GUI application.

Greg Burghardt
  • 34,276
  • 8
  • 63
  • 114