Is it appropriate to repeat data in models to satisfy using law of demeter in collections?

早过忘川 提交于 2019-12-19 10:28:09

问题


This is a contrived example, say I want to list the population of a country that a person has a friend in, here are two setups below. Would it be best to repeat data in the models?

I've been told that the Law of Demeter is important to follow, the example is you tell a dog to walk, it is folly to command his legs to walk.

In my wealth of inexperience (noob) I have found that the query would be much easier to do when the models repeat data, People.where(:country => friend.country), vs collections where there are chained associations (which have been impossible thus far): People.where(:city => { :county => { :region => { :country => friend.city.county.region.country }}}) (It would really help this noob here understand the concept if you could imagine the correct contrived LoD setup and syntax, I really hope I didn't use an example that has nothing to do with the Law of Demeter) I've tried applying LoD via delegate and was told I'm still chaining (which I am), the only solution I can think of is to repeat data that could be accessible via associations.

But I hate repeating data! This is due to following DHH's Rails tutuorial where we re-create twitter, he showed how great it is to create relationships vs repeating data.

Should repeating data be appropriate to get the associations less chained?

Models, repeating data

class Country < ActiveRecord::Base    
  has_many :regions    
  has_many :counties    
  has_many :cities    
  has_many :people
end

class Region < ActiveRecord::Base
  has_one :country
  has_many :counties
  has_many :cities    
  has_many :people
end

class County < ActiveRecord::Base
  has_one :country
  has_one :region
  has_many :cities    
  has_many :people
end

class City < ActiveRecord::Base
  has_one :country
  has_one :region
  has_one :county    
  has_many :people
end

class Person < ActiveRecord::Base
  has_one :country
  has_one :region
  has_one :county    
  has_one :city
  has_many :relationships
  has_many :friends, :through => :relationships
end

vs models with chained associations

class Country < ActiveRecord::Base    
  has_many :regions   
end

class Region < ActiveRecord::Base
  belongs_to :country
  has_many :counties
end

class County < ActiveRecord::Base
  belongs_to :region
  has_many :cities
end

class City < ActiveRecord::Base
  belongs_to :county
end

class Person < ActiveRecord::Base
  belongs_to :city
end

回答1:


This does not seem to be an issue of law of demeter as much as it is an issue of Database design and Data Integrity. The first option should be ruled out because it creates a database that definitely violates Third Normal-Form (3NF):

In your first example, if a Country HM cities, what happens if say, you update that city to belong to a different region that no longer belongs to the Country? -> Bam! Data Integrity Gone! Of course, it is unlikely that a city will move to a different country but like you said, this is a contrived example and i'm talking about the general case

You should google Database Normalization and Third Normal Form for more.

Also, in this case, you're violating 3NF only because you think you can 'improve performance' by doing so. This is a case of pre-optimization and a bad practice. While in some cases de-normalization is a managed risk, Here be dragons, and if you're just starting an app in rails, this is definitely not the case. Let your DB worry about fetching the data quickly. you can help it by providing good indexes.

Also, I think that what you're looking for is a way to create a nested has many through relationship. You want to it to be the case that:

a Country HM Counties THROUGH Regions

and that,

a Country HM Cities THROUGH Counties

this will be standard in 3.1 if you're on 3.0, then you can use the

https://github.com/ianwhite/nested_has_many_through

gem, which i am currently using, and am quite happy with.




回答2:


Ahh, the "occasionally useful suggestion of Demeter". (Martin Fowler.)

I think DIE/DRY and normalization are more fundamental principles, but it's ultimately going to be a contest between conflicting guidelines that you will need to apply common sense to.

The "law" applied to object classes in one specific project and does have obvious value as a class hierarchy design model.

But there is controversy over Demeter's application specifically with respect to Rails views. By definition they are a report, and so it is questionable whether the Suggestion of Demeter is applicable.




回答3:


In my opinion you should avoid repition of data where you can. However, you can create aggregate objects which allow you to combine data. So you can keep your core entities clean but then have additional supporting entities which agreggate objects.

If you use the example of a View in SQL, you can retrieve a result which is the combination of many entities. This result could be the agreggate entity and is a perfectly legitimate means of 'repeating' data.



来源:https://stackoverflow.com/questions/6404354/is-it-appropriate-to-repeat-data-in-models-to-satisfy-using-law-of-demeter-in-co

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!