SlideShare una empresa de Scribd logo
1 de 64
Dealing with Obese Models A 5 Step Guide to Getting your models in shape Ryan Brunner, Influitive @ryanbrunner
The Problem My Models scare me. They’re too big and hard to deal with. Usually, when I run into a structural problem with Rails, there’s one place I can turn to.
CONVENTIONS
Conventions
Your folders should look like this.
Your views should look like this.
Your controllers should look like this.
Your stylesheetsshould look like this.
Your javascriptshould apparently look like this.
So why is this ok for your models?Is there a Rails convention to deal with this?
SKINNY CONTROLLERS FAT MODELS
Maybe fat models aren’t the solution…
SKINNY CONTROLLERS FAT MODELS REASONABLY HEALTHY MODELS
EXAMPLE TIME! Let’s build a person model!
Person Attributes
Person Attributes Associations
Person Attributes Associations Validation
Attributes Associations Validation Scopes for searching Person
Attributes Associations Validation Scopes for searching Scopes for authorization Person
Attributes Associations Validation Scopes for searching Scopes for authorization State Machine Person
Attributes Associations Validation Scopes for searching Scopes for authorization State Machine Location / GeoTagging Stuff Person
Attributes Associations Validation Scopes for searching Scopes for authorization State Machine Location / GeoTagging Stuff Leaderboard Person
Attributes Associations Validation Scopes for searching Scopes for authorization State Machine Location / GeoTagging Stuff Leaderboard Relationship helper methods Person
Attributes Associations Validation Scopes for searching Scopes for authorization State Machine Location / GeoTagging Stuff Leaderboard Relationship helper methods Formatting methods Person
WHAT HAPPENED?
OBESITY It’s not just for Texas anymore.
Let’s get our model back in shape!
Step 1:Organization
Big, Beautiful Models should be organized.
Big, Beautiful Models should be organized. Whitespace is your friend.
Big, Beautiful Models should be organized. Whitespace is your friend. Don’t be afraid of comments.
Big, Beautiful Models should be organized. Whitespace is your friend. Don’t be afraid of comments. Play around with indenting.
Step 2:Relocating
Look for code that’s Too interested in another model. person.rb
Look for code that’s too interested in another model. person.rb person.rb It might make more sense to move it there. feedback.rb
Look for code that’s too interested in another model. person.rb person.rb It might make more sense to move it there. feedback.rb Fatness isn’t just about LOC.
Step 3:Abstracting common behaviour
Sometimes things aren’t central to your model.
Sometimes things aren’t central to your model. Build your own framework.
Sometimes things aren’t central to your model. Build your own framework. Even if you only do it once.
Step 4:PRESENTATION LOGIC
Watch for Presentation Logic in your Models Consider HTML Harmful. Models shouldn’t format data. If you’re returning something other than models, be careful..
The Traditional Rails Solution - Helpers
But..Helpers suck when you depend on state.
Decorators Like Helpers, but don’t suck.
Delegates methods to the subjectof the decorator. Provides additional methods for presentation logic. Use them like you’d use the model, but feel free to add presentation logic.  Anatomy of a decorator
Decorators are a way to extend your models to Add Presentation Logic
All the delegation work is done for you. https://github.com/jcasimir/rails_decorators
Step 5:Presenters
EXAMPLE TIME! Relationship Viewer
We needed this interface. It needs to interact with Filtered relationships in a lot of different ways
All we need is methods for: ,[object Object]
Counts of all connections filtered by customer type.
Lists of relationships by relationship type.
Whether the user has submitted feedback.
How many users are currently in the system.
Content linked to those users.,[object Object]
Attempt #1 Let’s fatten up some models.
relationship.rb
relationships_controller.rb
Let’s add a Presenter!
prospect_match_presenter.rb
prospect_match_controller.rb
CLEAN, Wonderful views

Más contenido relacionado

Similar a Dealing with Obese Models

10 Object-Oriented Design Heuristics for Rubyists
10 Object-Oriented Design Heuristics for Rubyists10 Object-Oriented Design Heuristics for Rubyists
10 Object-Oriented Design Heuristics for RubyistsBill Eisenhauer
 
Design Patterns For 70% Of Programmers In The World
Design Patterns For 70% Of Programmers In The WorldDesign Patterns For 70% Of Programmers In The World
Design Patterns For 70% Of Programmers In The WorldSaurabh Moody
 
Accuracy-Constrained Privacy-Preserving Access Control Mechanism for Relation...
Accuracy-Constrained Privacy-Preserving Access Control Mechanism for Relation...Accuracy-Constrained Privacy-Preserving Access Control Mechanism for Relation...
Accuracy-Constrained Privacy-Preserving Access Control Mechanism for Relation...Sudhir Kumar
 
SOFLUX Meetup - Landing on your dream job
SOFLUX Meetup - Landing on your dream jobSOFLUX Meetup - Landing on your dream job
SOFLUX Meetup - Landing on your dream jobMarta Guerra
 
Beautiful Models in PHP
Beautiful Models in PHPBeautiful Models in PHP
Beautiful Models in PHPbrandonsavage
 
Learning Web Development with Ruby on Rails Launch
Learning Web Development with Ruby on Rails LaunchLearning Web Development with Ruby on Rails Launch
Learning Web Development with Ruby on Rails LaunchThiam Hock Ng
 
Unit No 6 Design Patterns.pptx
Unit No 6 Design Patterns.pptxUnit No 6 Design Patterns.pptx
Unit No 6 Design Patterns.pptxDrYogeshDeshmukh1
 
Turning Passion Into Words
Turning Passion Into WordsTurning Passion Into Words
Turning Passion Into WordsBrian Hogan
 
Design Principles to design Patterns
Design Principles to design PatternsDesign Principles to design Patterns
Design Principles to design PatternsFaizan Haider
 
Developing for the unknown lavacon
Developing for the unknown   lavaconDeveloping for the unknown   lavacon
Developing for the unknown lavaconNeil Perlin
 
Developing for the unknown lavacon
Developing for the unknown   lavaconDeveloping for the unknown   lavacon
Developing for the unknown lavaconNeil Perlin
 
How we make websites (IWMW2009)
How we make websites (IWMW2009)How we make websites (IWMW2009)
How we make websites (IWMW2009)fantasticlife
 
Modeling Requirements Narrated2
Modeling Requirements Narrated2Modeling Requirements Narrated2
Modeling Requirements Narrated2Daniel Brookshier
 
Modeling Requirements with SysML
Modeling Requirements with SysML Modeling Requirements with SysML
Modeling Requirements with SysML Daniel Brookshier
 
Efficient Rails Test Driven Development (class 4) by Wolfram Arnold
Efficient Rails Test Driven Development (class 4) by Wolfram ArnoldEfficient Rails Test Driven Development (class 4) by Wolfram Arnold
Efficient Rails Test Driven Development (class 4) by Wolfram ArnoldMarakana Inc.
 
Single sourcing to the max
Single sourcing to the maxSingle sourcing to the max
Single sourcing to the maxNeil Perlin
 

Similar a Dealing with Obese Models (20)

10 Object-Oriented Design Heuristics for Rubyists
10 Object-Oriented Design Heuristics for Rubyists10 Object-Oriented Design Heuristics for Rubyists
10 Object-Oriented Design Heuristics for Rubyists
 
Design Patterns For 70% Of Programmers In The World
Design Patterns For 70% Of Programmers In The WorldDesign Patterns For 70% Of Programmers In The World
Design Patterns For 70% Of Programmers In The World
 
Accuracy-Constrained Privacy-Preserving Access Control Mechanism for Relation...
Accuracy-Constrained Privacy-Preserving Access Control Mechanism for Relation...Accuracy-Constrained Privacy-Preserving Access Control Mechanism for Relation...
Accuracy-Constrained Privacy-Preserving Access Control Mechanism for Relation...
 
SOFLUX Meetup - Landing on your dream job
SOFLUX Meetup - Landing on your dream jobSOFLUX Meetup - Landing on your dream job
SOFLUX Meetup - Landing on your dream job
 
Beautiful Models in PHP
Beautiful Models in PHPBeautiful Models in PHP
Beautiful Models in PHP
 
Learning Web Development with Ruby on Rails Launch
Learning Web Development with Ruby on Rails LaunchLearning Web Development with Ruby on Rails Launch
Learning Web Development with Ruby on Rails Launch
 
Unit No 6 Design Patterns.pptx
Unit No 6 Design Patterns.pptxUnit No 6 Design Patterns.pptx
Unit No 6 Design Patterns.pptx
 
Turning Passion Into Words
Turning Passion Into WordsTurning Passion Into Words
Turning Passion Into Words
 
Design Principles to design Patterns
Design Principles to design PatternsDesign Principles to design Patterns
Design Principles to design Patterns
 
Developing for the unknown lavacon
Developing for the unknown   lavaconDeveloping for the unknown   lavacon
Developing for the unknown lavacon
 
Developing for the unknown lavacon
Developing for the unknown   lavaconDeveloping for the unknown   lavacon
Developing for the unknown lavacon
 
Template pattern
Template patternTemplate pattern
Template pattern
 
How we make websites (IWMW2009)
How we make websites (IWMW2009)How we make websites (IWMW2009)
How we make websites (IWMW2009)
 
The Modlet Pattern
The Modlet PatternThe Modlet Pattern
The Modlet Pattern
 
Data modeling
Data modelingData modeling
Data modeling
 
Design pattern - part 1
Design pattern - part 1Design pattern - part 1
Design pattern - part 1
 
Modeling Requirements Narrated2
Modeling Requirements Narrated2Modeling Requirements Narrated2
Modeling Requirements Narrated2
 
Modeling Requirements with SysML
Modeling Requirements with SysML Modeling Requirements with SysML
Modeling Requirements with SysML
 
Efficient Rails Test Driven Development (class 4) by Wolfram Arnold
Efficient Rails Test Driven Development (class 4) by Wolfram ArnoldEfficient Rails Test Driven Development (class 4) by Wolfram Arnold
Efficient Rails Test Driven Development (class 4) by Wolfram Arnold
 
Single sourcing to the max
Single sourcing to the maxSingle sourcing to the max
Single sourcing to the max
 

Último

What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?Antenna Manufacturer Coco
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessPixlogix Infotech
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 

Último (20)

What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your Business
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 

Dealing with Obese Models

Notas del editor

  1. Hi, I'm Ryan from Influitive. Today I’d like to talk to you about keeping your models in shape.
  2. So what's this all about? I wanted to talk today about a problem that I've been facing more and more often in my own codebase, one that perhaps you're seeing too, that doesn't get enough attention as a problem in Rails development. My models scare me. Each individual method is small and understandable, but the whole model is just a scary amount of code. Usually, when I run into a structural problem with Rails, there’s one place I can turn to.
  3. Conventions.
  4. Rails loves conventions. It’s one of the nicest things about working with Rails. With very few exceptions, when you’re structuring your code, you can find a pithy little statement about the proper way to do things. For example, in Rails:
  5. Your folders should look like this.
  6. Your views should look like this.
  7. Your controllers should look like this.
  8. Your stylesheets should look like this.
  9. Your javascript should apparently look like this.
  10. But there’s no catchy catch-phrase to prevent your models looking like this. We talk about keeping methods small and organizing things better, but models still have a tendency to bloat up over time.
  11. What we do hear nowadays is “Skinny Controllers, Fat Models”. And it’s not a bad catchphrase to follow. Bloated controllers are hard to test, hard to understand, and overall just ugly to deal with.
  12. But is this really a good alternative? Doesn’t just looking at this model feel like a punch in the gut? I actually have two confessions to make – one – that this model is actually from our codebase, and two – that it’s actually a couple pages longer – I couldn’t figure out how to make it fit on one slide.So while I agree with the “skinny controllers” part of the argument, I’m going to propose that we make one modification to our rule.
  13. Skinny controllers are great. Writing a one-liner controller method just feels awesome. That doesn’t mean that we should dump everything onto the models plate. The worst part is, unlike controllers, where bloat usually looks like seriously hairy methods, model bloat can be subtle – a whole lot of small, compact methods slowly bloating the model until you’re left with an incomprehensible mess.
  14. Imagine that you’re working on a person model for your new, shiny app. You’re a pro Ruby developer, so you know all about how your controllers and views need to be as compact as possible. You’re going to make sure that the hard stuff is all done inside the models. Let’s get started.
  15. Our person model starts innocently enough, just a few attributes. If anything, it’s looking a little thin. Let’s make this model do something useful.
  16. We’ll add some associations to related models..
  17. Validations to ensure that we’re not passing in invalid data.
  18. Maybe we create some scopes to clean up some controller search logic in our index action.
  19. Maybe we want to prevent some users from seeing certain people. We can create some scopes to handle that as well.
  20. The feature requests are rolling in now. Let’s wrap our person in a state machine to reflect whether they’ve been invited into the system.
  21. Also, we need to add some support for geotagging.
  22. Bob the sales guy just asked for leaderboard functionality.
  23. We’ve got some hairy logic dealing with relationships between people – let’s add some more methods.
  24. Finally, let’s add some methods to help calculate and format things they way we expect them and get some logic out of our views.
  25. Suddenly, our model isn’t looking so svelte anymore. It’s hard to point to any one particular feature as the thing that drove our poor little Person model over the edge, but bit by bit he’s bloated into something that’s difficult to understand, hard to maintain, and evokes that painful feeling every time we open person.rb.
  26. Our model is now obese. It wasn’t as big of a problem when he was pleasantly plump, but now every developer dreads modifying anything about people.Today, I’m going to go through a 5-step program to get our poor little person back into shape. We’re going to go through some quick wins, as well as some more involved stuff that will help when dealing with complicated models.
  27. Our model is now obese. It wasn’t as big of a problem when he was pleasantly plump, but now every developer dreads modifying anything about people.Today, I’m going to go through a 5-step program to get our poor little person back into shape. We’re going to go through some quick wins, as well as some more involved stuff that will help when dealing with complicated models.
  28. Step 1: OrganizationWhen you want to lose weight, the first thing you do is start logging everything you eat, so you can figure out where making changes would be most effective. That’s a good first step for your models as well.
  29. Start by taking your model, and organizing it into manageable chunks. Keep like things together, and avoid the temptation to group things with names like “methods”. Categorize your code by what it is doing, not what it is.
  30. Don’t be afraid to use whitespace in your model. Fatness isn’t about lines of code, it’s about density. Give your code some room to breathe and it starts to look a lot less daunting. You want your model to be scannable by a developer reading it, so they can find where they need to go without reading through each individual line.
  31. Use comments. I know, ruby is beautiful, and readable, and ought to not need comments, but we’re already dealing with a complicated situation, and a bit of extra description might be worth the extra cruft and maintenance. Focus on why the code is doing what it’s doing, rather than what.
  32. Don’t be afraid to play around with conventions around indenting a bit. If you look at my categories, they technically should be indented to align with the code, but bringing them back one level really goes a long way towards making the categories stand out.Watch out for things that you find difficult to categorize, or don’t seem to fit well with the rest of the model. These are probably your prime candidates for refactoring.So now we have a model that is at least organized, although it’s probably even bigger in terms of line count than when we started. But we’re in a good place to start implementing some real changes in the model.
  33. The second thing we should look at is moving some logic to another model if it’s appropriate.
  34. It’s a pretty common occurrence that methods in models will spend most of their time talking to another model – usually an associated one. This is bad for a few reasons – first – it’s unnecessarily bloating our model – and more importantly, it is implementing business logic that it shouldn’t be responsible for.One telltale sign of this is interacting with ActiveRecord a lot on a particular association – this is usually a sign that you can push some of that logic into the appropriate association class.
  35. And here it is after a quick fix. We’ve reduced the method on contacts to be a single line and have delegated nearly all the business logic to the Feedback model. Most importantly, Feedback is now responsible for it’s own rules – when feedback is completed, and what constitutes “recent” feedback. This will help a lot if we ever need to modify these rules.
  36. One interesting thing to note here is that we’ve actually added lines of code here. Don’t be afraid to do that. Designing an application isn’t the same as playing code golf – you aren’t judged on writing the fewest lines of code. We’ve made everything much more modular and testable, and even though there’s more lines overall, it feels more thin and flexible.
  37. Another common source of model bloat is with functionality that the model uses, but isn’t really core to what the model is about. Let’s look at an example.
  38. So here’s a good example of some code, which, while readable and somewhat compact, really isn’t core to the concept of a person. If you’re curious, this code adds a new attribute that isn’t stored in the database for our person class that stores an external image file. When a person is saved, if it’s set, we set the image property (which is using paperclip), and we can easily support both file uploads and references to external images. Awesome, right?But if we take a look, it hardly depends on the state of the person at all, outside of the attribute we’ve defined here and the image property included on the contact. What’s more, all of this code isn’t really about people. People have an image – the concept of uploading external urls to populate those images isn’t core to personhood. So what’s the solution?
  39. Abstract it away. Move all of that code to your lib directory, and include it into your model. Now the person class is way less involved with the particulars of how to upload files, and just cares about the fact that it has an image, and it’s a file, and it can be remotely downloaded in some way.One key concept to take out of this is that you should be developing the framework around your app. Rails is great, and does many amazing things, but it won’t do everything. Once your application gets to a particular size, you’ve built a framework, whether you like it or not, and the only thing left to decide is whether it’s a clean framework or a messy one.
  40. And don’t worry if no other model in the application remotely downloads images. What’s important is that the model cares about what it needs to care about, and the remote image downloader knows how to download images.
  41. So we’ve made a few pretty big steps in cleaning up our model. Things that don’t rightly belong to the model are more or less taken away now. Let’s focus next on what the model should be concerned with.Presentation logic is almost certainly not one of those things.
  42. Watch out whenever you seem to have logic in your models that looks like it’s ripped out of a view somewhere. Your models should act as if they don’t have any idea what this new-fangled “HTML” is.
  43. Now, there’s a pretty standard way to address this in Rails. There’s this little known folder called app/helpers, which is supposed to store all of this presentation logic stuff. You get access to methods like you would in the views, and everything seems like a clean fit, save for one problem.
  44. Helpers are kinda crappy. Working in helpers feels like you’ve abandoned object oriented programming for procedural programming. Everything needs to take arguments, and dealing with model state is a pain.
  45. But there’s actually a pretty good solution to this problem – decorators
  46. . Basically, the idea behind a decorator is to wrap the model that you’re working on, delegating calls to the model when you don’t need to implement custom logic, but adding new methods or supplying your own implementations when you need presentation specific code. This is similar to, but not quite the same, as the tradition Design Patterns definition of a decorator.Let’s take a look at how a decorator works.
  47. So in the context of a decorator, we can write code just as if we were actually in the person class, but we still maintain a tight seperation between model logic and presentation logic. Our model isn’t cluttered up with unnecessary presentation junk, and we don’t have to switch over to the procedural mindset of helpers. Since I started using decorators, I’ve almost completely abandoned class-based helper files.
  48. Fortunately, all of the messy delegation logic as well as including some helpers from ActionView is packaged up in a neat little gem called RailsDecorators. It’s super simple to use and takes nearly no time to get working, so I’d highly advise using it.
  49. So now we’re on to the ugliest cases of model bloat, the stuff that makes you feel dirty even while you’re writing it.
  50. I think the best way to go over this is with an example. I’m actually going to use a widget that we are currently working on at Influitive to demonstrate how these tricky sources of model bloat can happen.
  51. So we recently worked on an interface that plugs into external systems and gives an overview of how a particular person was related to other people in our database.
  52. Because it needed to fit within a few hundred pixels, and provide a lot of at-a-glance information, this particular interface had a lot of responsibilities. It had to:Check whether the current user is connected.Get counts filtered by customer type.Get detailed lists of relationships by relationship type.See whether the current user has provided feedback before.List how many users are currently in the system.Check for any content linked to those users.
  53. Um, yeah. There’s an awful lot here for one controller action to do.
  54. So let’s try doing this in the “Rails-approved”, fat models approach.
  55. First off, we’re going to need to extend our model to support all of the different types of data that we’re going to need to grab, so we don’t leave it up to the controller to implement what ended up being some pretty hairy activerecord calls. This logic alone, with all the code, added about 50 lines to the model we were working with. And we’re constantly tossing variables like the prospect in question, and what type of relationships we’re working with. Seems a bit brittle.
  56. Our controller really isn’t a much better story. This controller seems to know an awful lot, even if it’s delegating most of it’s responsibility to the model. And passing around that many instance variables seems a bit smelly and un-RESTful. You’ll notice that this is a custom, non-REST action on top of all that.
  57. Enter presenters. Presenters can really be thought of as a way to wrap logic that deals with multiple models in convoluted ways into a neat, organized package. With the old logic, our controller was really talking about 5 or 6 vaguely related things at once. But if you think about it, it really was only talking about one thing – a summary of the relationships of the prospect. The problem is, that’s not a model in our system, nor should it be. With a presenter, your controllers will be returning the presenter itself rather than a bunch of small, unrelated things.
  58. So here’s what our presenter ended up looking like. Let’s go over how the logic behind a presenter works.First off, you initialize presenters based on the information that you’re dependent on. In this case, we need to know what user is accessing the widget and which prospect we’re looking at. From there, define an interface to your presenter to match exactly what you’re doing in the view. It’s actually pretty useful to start writing your view before your presenter, and to just write whatever you would want the presenter to provide you with. From there, you can implement the presenter logic.Notice that the prospect and user variables are completely private to the view – the idea behind a presenter is you are constructing an interface for the view to work against – your view shouldn’t be able to access your models unless negotiated through the presenter.
  59. That complicated controller logic has been pushed down into the presenter itself, and we’re now talking about one thing, rather than 5 tangentially related things.
  60. So the benefits of presenters are pretty obvious – our views, controllers, and models are now far cleaner, and dealing with only their concerns, rather than being tightly tied to each other. The presenter serves as the glue connecting all of these things together, rather than delegating all of the cruft onto the model and controller. And your model isn’t implementing a lot of logic just to support one particular view.
  61. You should use presenters if you detect any of these smells in your app:Your view is talking to more than one model in a non-trivial way. Iterating over associations is probably OK. If you’re doing anything else though, you could probably benefit from a presenter.Your controller is setting a lot of instance variables. This creates brittleness between the controller and the view, and is pretty unREST-ful. Try to make controller actions talk about one thing, even if that thing is a presenter and not a model.Your model is doing a lot of things involving other models it isn’t related to, or doesn’t have a simple relationship to. If you find yourself passing in parameters really often to model methods, that might be a sign that your model is being a little too smart.
  62. Hopefully, by applying our 5-step program, your model is back to it’s old, trim, fit self.
  63. So, in summary, a few hints and tips to keeping your models clean.Start with the easy stuff. In a lot of cases, you don’t need to get into huge refactorings if there’s some obvious quick wins that you can take.Always start with organization. An organized model is way easier to refactor, and even a large organized model is easier to deal with than a small mess of spaghetti code.A good rule of thumb is to ensure that models only know about themselves – specifically what they are and what they do. Models shouldn’t know much about other models, save that they are associated to them.If you have some complicated scenarios, presenters and decorators are powerful tools.