Fighting Fat Models (Богдан Гусев)
-
Upload
fwdays -
Category
Engineering
-
view
209 -
download
2
Transcript of Fighting Fat Models (Богдан Гусев)
![Page 1: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/1.jpg)
FightingwithfatmodelsBogdanGusiev
![Page 2: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/2.jpg)
BogdanG.
is9yearsinIT6yearswithRubyandRails
LongRunRailsContributor
![Page 3: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/3.jpg)
Someofmygemshttp://github.com/bogdan
Datagridjs-routesaccepts_values_forfuri
![Page 4: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/4.jpg)
MyBlog
http://gusiev.com
![Page 5: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/5.jpg)
http://talkable.com
Asmallstartupisagreatplacetomovefrommiddletoseniorandabove
![Page 6: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/6.jpg)
FatModelsWhytheproblemappears?
Allbusinesslogiccodegoestomodelbydefault.
![Page 7: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/7.jpg)
IntheMVC:Whyitshouldnotbeincontrollerorview?
Becausetheyarehardto:
testmaintainreuse
![Page 8: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/8.jpg)
Adefinitionofbeingfat
1000LinesofcodeButitdependson:
DocsWhitespaceComments
![Page 9: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/9.jpg)
$ wc -l app/models/* | sort -n | tail 532 app/models/incentive.rb 540 app/models/person.rb 544 app/models/visitor_offer.rb 550 app/models/reward.rb 571 app/models/web_hook.rb 786 app/models/site.rb 790 app/models/referral.rb 943 app/models/campaign.rb 998 app/models/offer.rb 14924 total
Existingtechniques
![Page 10: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/10.jpg)
Existingtechniques
ServicesSeparatedutilityclass
ConcernsModulesthatgetincludedtomodels
Presenters/WrappersClassesthatwrapexistingmodeltoplugnewmethods
Whatdoweexpect?
![Page 11: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/11.jpg)
Standard:ReusablecodeEasytotestGoodAPI
Advanced:EffectivedatamodelMOREfeaturespersecondDataSafety
GoodAPI
![Page 12: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/12.jpg)
GoodAPIIsauserconnectedtofacebook?
user.connected_to_facebook?# ORFacebookService.connected_to_facebook?(user)# ORFacebookWrapper.new(user) .connected_to_facebook?
TheneedofServices
![Page 13: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/13.jpg)
WhenamountofutilsthatsupportModelgoeshigher
extractthemtoserviceisgoodidea.
Moveclassmethodsbetweenfilesischeap
![Page 14: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/14.jpg)
# move(1) User.create_from_facebook# to(2) UserService.create_from_facebook# or(3) FacebookService.create_user
Organiseservicesbyprocessratherthanobjecttheyoperateon
OtherwiseatsomemomentUserServicewouldnotbeenough
![Page 15: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/15.jpg)
OtherwiseatsomemomentUserServicewouldnotbeenough
TheproblemofservicesServiceisseparatedutilityclass.
module CommentService
![Page 16: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/16.jpg)
module CommentService def self.create(attributes) comment = Comment.create!(attributes) deliver_notification(comment) endend
"Язнаюоткудачтоберется"
Servicesdon't
providedefaultbehavior
![Page 17: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/17.jpg)
providedefaultbehavior
TheNeedofDefaultBehaviorObjectshouldencapsulatebehavior:
DataRulesSetofrulesthatamodelshouldfitattheprogramming
![Page 18: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/18.jpg)
SetofrulesthatamodelshouldfitattheprogramminglevelEx:Acommentshouldhaveanauthor
BusinessRulesSetofrulesthatamodelshouldfittoexistintherealworldEx:Acommentshoulddeliveranemailnotification
Whatisamodel?Themodelisanimitationofrealobject
thatreflectssomeit'sbehaviors
![Page 19: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/19.jpg)
thatwearefocusedon.
Wikipedia
Modelisabestplacefordefaultbehaviour
MVCauthorsmeantthat
![Page 20: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/20.jpg)
ImplementationUsingbuilt-inRailsfeatures:
ActiveRecord::Callbacks
![Page 21: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/21.jpg)
HooksinmodelsWecreatedefaultbehaviorandourdataissafe.
Example:Commentcannotbecreatedwithoutnotification.
class Comment < AR::Base after_create :send_notification
![Page 22: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/22.jpg)
end
APIcomparison
Comment.create# orCommentService.create
![Page 23: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/23.jpg)
SuccessfulProjectstendtodo
onethinginmanydifferentwaysratherthanalotofthings
![Page 24: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/24.jpg)
CommentonawebsiteCommentinnativemobileiOSappCommentinnativemobileAndroidappCommentbyreplyingtoanemailletterAutomaticallygeneratecomments
![Page 25: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/25.jpg)
TeamGrowthProblemHowwouldyoudeliveraknowledgethatcommentshould
bemadelikethisto10people?
CommentService.create(...)
![Page 26: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/26.jpg)
Reimplementotherperson'sAPIhasmorewisdomthaninventnewone.
Comment.create(...)
![Page 27: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/27.jpg)
EdgecasesInallcasesdatacreatedinregularway
Inoneedgecasesspecialrulesapplied
![Page 28: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/28.jpg)
Servicewithoptions
module CommentService def self.create( attrs, skip_notification = false)end
![Page 29: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/29.jpg)
Defaultbehavior
andedgecasesHeymodel,createmycomment.
Ok
Heymodel,whydidyousendthenotification?Becauseyoudidn'tsayyoudon'tneedit
![Page 30: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/30.jpg)
Becauseyoudidn'tsayyoudon'tneedit
Heymodel,createmodelwithoutnotificationOk
Supportparameterinmodelclass Comment < AR::Base attr_accessor :skip_comment_notification after_create do unless self.skip_comment_notification send_notification end endend
![Page 31: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/31.jpg)
end
#skip_comment_notificationisusedonlyinedgecases.
DefaultBehaviourishardtomakeButitsolvescommunicationproblems
thatwillonlyincreaseovertime
![Page 32: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/32.jpg)
Whatisthedifference?
FacebookService.register_user(...)
Comment.after_create :send_notification
Businessrules:UsercouldberegisteredfromfacebookCommentshouldsendanemailnotification
![Page 33: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/33.jpg)
Modelstandsforshould
ServicestandsforcouldPleasedonotconfuseshouldwithmust
![Page 34: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/34.jpg)
Wherearepresenters?
UserPresenter.new(user)# ORclass User include UserPresenterend
TradeanAPIforlessmethodsinobject
![Page 35: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/35.jpg)
Moreeffectivepresenters?
![Page 36: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/36.jpg)
ExampleofServiceimplementationwithwrapperMoreexampleatActiveRecordsourcecode
class StiTools def self.run(from_model, to_model) new(from_model, to_model).perform end
private def initialize(from_model, to_model)
def perform shift_id_info
![Page 37: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/37.jpg)
DatagridGemExampleofcollectionwrapper
https://github.com/bogdan/datagrid
UsersGrid.new( last_request: Date.today, created_at: 1.month.ago..Time.now)
class UsersGrid scope { User }
filter(:created_at, :date, range: true) filter(:last_request_at, :datetime, range: true
![Page 38: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/38.jpg)
WrappingDatahttps://github.com/bogdan/furi
u = Furi.parse( "http://bogdan.github.com/index.html")u.subdomain # => 'bogdan'u.extension # => 'html'u.ssl? # => false
module Furi def self.parse(string)
![Page 39: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/39.jpg)
Serviceusageisinconvinientbecauseofvalidation
Customer.has_many :purchasesPurchase.has_many :ordered_itemsOrderItem.belongs_to :product
ManualOrder.ancestors.include?( ActiveRecord::Base) # => false
order = ManualOrder.new(attributes)if order.valid? order.save_all_those_records_at_once!
![Page 40: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/40.jpg)
Wrappers/PresentersVeryspecificuse
WrapperaroundcollectionParsingserialisedobjectUnder-the-hoodclassinsideaserviceServiceusageisinconvinient
![Page 41: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/41.jpg)
Themodelisstillfat.Whattodo?
UseConcerns
![Page 42: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/42.jpg)
UseConcerns
class Comment < AR::Base include CommentNotification include FeedActivityGeneration include Archivableend
Railsdefault:app/models/concerns/*
Attention!
![Page 43: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/43.jpg)
Attention!Peoplewithhighpressureorpropensitytosuicide
Nextslidecanbeconsideredoffensivetoyourreligion
SingleResponsibilityPrinciple
![Page 44: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/44.jpg)
SUCKSTheprooffollows
ThereisnoasinglethingintheuniversethatfollowstheSRP
![Page 45: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/45.jpg)
intheuniversethatfollowstheSRP
class Proton include Gravitation include ElectroMagnetism include StrongNuclearForce include WeekNuclearForceend
Whymanmadethingsshould?
![Page 46: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/46.jpg)
Whymanmadethingsshould?TheworldisunreasonablycomplexttofollowSRP
Howamodelthatsupposetosimulatethosethingscanhaveasingleresponsibility?
![Page 47: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/47.jpg)
Itcan't!
ModelConcernsareunavoidableifyouwanttohaveagoodmodel
![Page 48: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/48.jpg)
ifyouwanttohaveagoodmodel
ConcernsareVerticalslicingUnlikeMVCwhichishorizontalslicing.
![Page 49: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/49.jpg)
SplitmodelintoConcernsclass User < AR::Base
![Page 50: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/50.jpg)
class User < AR::Base include FacebookProfileend
# Hybrid Concern that provides # instance and class methodsmodule FacebookProfile has_one :facebook_profile # simplified def connected_to_facebook? def self.register_from_facebook(attributes)
Ex.1User+Facebook
has_one :facebook_profile=>Model
#register_user_from_facebook=>Service
![Page 51: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/51.jpg)
#register_user_from_facebook=>Serviceconnect_facebook_profile=>Serviceconnected_to_facebook?=>Model
Everyusershouldknowifitisconnectedtofacebookornot
Ex.2Delivercommentnotification
Comment#send_notification=>ModelDefaultBehaviourEvenifexceptionsexist
![Page 52: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/52.jpg)
Evenifexceptionsexist
Basicapplicationarchitecture
View
Controller
Model
![Page 53: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/53.jpg)
Model
Services Presenters
Concern Concern Concern
ConcernsBaseAttributesAssociations
has_one
![Page 54: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/54.jpg)
has_onehas_manyhas_and_belongs_to_many
Butrarely
LibrariesusingConcerns
ActiveRecordActiveModelDeviseDatagrid
![Page 55: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/55.jpg)
Datagrid
Summary
![Page 56: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/56.jpg)
InjectServicebetweenModelandControllerifyouneedthem
![Page 57: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/57.jpg)
Could?=>Service
Should?=>Model
![Page 58: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/58.jpg)
SRPisamisleadingprincipleItshouldnotinhibityoufromhaving
aBetterApplicationModel
![Page 59: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/59.jpg)
Fatmodels=>ThinConcerns
![Page 60: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/60.jpg)
Reimplementotherperson'sAPIhasmorewisdomthaninventnewone.
![Page 61: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/61.jpg)
Presentersareprettyspecific
Usethemin
Wrappingthecollection"private"classServiceusageisinconvenient
![Page 62: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/62.jpg)
TheEndThanksforyourtime
http://gusiev.com
https://github.com/bogdan
![Page 63: Fighting Fat Models (Богдан Гусев)](https://reader034.fdocuments.in/reader034/viewer/2022042707/58ef21a41a28ab9d668b45fb/html5/thumbnails/63.jpg)