<div dir="ltr">And speaking of antipatterns commonly encountered when using Rails, there's the God Object.<div><br></div><div>The way I usually find God Objects is by running this from the root of my Rails project:</div>
<div><br></div><div>$ find app/models -name '*.rb' | xargs wc -l | sort | tail</div><div><br></div><div>When I do this, I almost always see app/models/user.rb, along with the names of the two or three objects that are central to the app's domain. In one memorable project, the last file on the list was about 3,500 lines—but when I added in line counts from all of the modules that had been mixed in to the class, the total was pushing 10K. o_O</div>
<div><br></div><div>The only solution I was able to come up with (other than working in a strictly quarantined subpath of the app and pretending the rest of it wasn't there) was to employ this pattern when adding new methods that had to touch the God Object:</div>
<div><br></div><div>class BigHonkingModel < ActiveRecord::Base</div><div> # ... loads of code</div><div><br></div><div> def my_new_feature(*args, &block)</div><div> MyNewFeatureCollaborator.new(self).call(*args, &block)</div>
<div> end</div><div><div>end<br></div></div><div><br></div><div>This accomplishes three things:</div><div><br></div><div>1) It helps me not be the jackass who finally pushes the line count above 10K (I only added four lines, including the load-bearing whitespace!).</div>
<div>2) It puts all of the new logic into a collaborator object that gets its primary dependency injected at initialization time—which makes it much, much easier to write fast tests for everything that collaborator does. (And here you thought I was going off topic...)</div>
<div>3) Because my collaborator's logic is in a separate class, it's limited* to calling public methods of BigHonkingModel. My fast test setup injects a double, and the pain of having to mock the public methods that will be called on that double helps keep my collaborator's responsibilities relatively focused.</div>
<div><br></div><div>* (Well, I say "limited". It's still Ruby, so you can #send all you want. As long as you can still sleep at night. You monster.)</div><div><br></div><div>By no means am I suggesting that this is a "best practice". For starters, I'm continuing to violate SRP by adding yet another method to a model that's already got far too many of them. But I suggest that it is, at least, a "less awful practice" that helps you slow your descent into madness while you condition your customers to accept longer delivery times so you can start making installment payments on your tech debt.</div>
<div><br></div><div>-Sam</div><div class="gmail_extra"><br><br><div class="gmail_quote">On Wed, Dec 4, 2013 at 2:20 PM, Mr Jaba <span dir="ltr"><<a href="mailto:the.jaba@gmail.com" target="_blank">the.jaba@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr">Hi Everyone, <div><br></div><div>I've recently taken ownership of a new project with a large test suite (2000ish tests), and the overall run time is around 30 minutes which is certainly less than ideal! </div>
<div><br></div><div>Now I know the general approach to "Fast Rails Tests" but taking the time to refactor the whole test suite is a bit too much right now. I'm wondering if anyone has experience of transforming a test suite of this magnitude to something a bit speedier? If so how did you go about it? What tips, tricks and techniques can you share? </div>
<div><br></div><div>A bit more info:</div><div><br></div><div>- Test::Unit tests, moving to Minitest</div><div>- Rails 3.2.16</div><div>- Running parallel_tests shaved 5 mins off the time</div><div>- Using Spring to reduce Rails load time. </div>
<div><br></div><div>Any advice gratefully received!</div><div><br></div><div>Tom</div></div></blockquote></div></div></div>