Live data from Hacker News

Rails – The Missing Parts

eng.joingrouper.com

141–150 of 173 posts

Re: Rails – The Missing Parts

#141
I recommend this article from the guys from Code Climate, it is really mind-opening: http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decomp...

The author describes different ways of refactoring fat ActiveRecord models, but most of the ideas can be used outside ActiveRecord, as "best practices".

I have been using some of the patterns described in it and I am really happy with the results. The code becomes more clearly decoupled, is easy to test and results in clean, slim models.

Re: Rails – The Missing Parts

#142

Earlier quoted context omitted.

Regardless of reuse, controller actions can get awfully large if unchecked. What would you say is the maximum LOCs for a public controller method? Callbacks in Controllers and AR::Models tend to make things worse IMO for anything other than authentication; and for intricate actions interactors seem like the best defence. I have had the (mis)fortune to jump into a number of large Rails codebases and I can say with han…

> What would you say is the maximum LOCs for a public controller method? As small as it needs to be in order to get the job done, and as large as it must be to get it done clearly. Sometimes that's zero lines of code; sometimes it's 500. You can usually factor down a 500 line method, but it may be worth asking what the breadth cost is should the code really be single-use. If your metric is anything else, then you're…

Do you have an example of a public controller method larger than even 25 lines that does its job clearly?

Re: Rails – The Missing Parts

#143
post #39

The proof is always in the pudding. While there are good and reasonable times to introduce "interactors", this particular example is poor. The tests presented are anemic, and the code is absolutely not any clearer by being extracted and wrapped. I would indeed have kept all this in the controller. The key point for an "interactor" extraction is imo when you have multiple models being created in symphony, like a Signu…

the example is poor, butI think you're missing the core point here -- slow tests. I don't think this really improves readability or organization much -- but my real world experience with a giant slow rails test suite gives me 100% confidence that patterns like this are the only way to not have a completely intractable giant test suite.

Definitely agree. Would love to see DHH commenting on the slow tests problem.

Re: Rails – The Missing Parts

#145
The first missing part: A language with a sane syntax. For some examples of the multitude of ways in which Ruby syntax is awful, see [1].

The second missing part: Ruby is Rails. Trying to learn Ruby at the same time as a modern web framework with all its moving parts? Forget it.

The third missing part: Tutorials. Okay, I haven't done a rant on this. Google rails tutorial. The first helpful result I get [2], I scroll down. The first meat is "Setting the application home page". I see this:

    Blog::Application.routes.draw do
      get "welcome/index"
Huh? "This is your application's routing file which holds entries in a special DSL (domain-specific language) that tells Rails how to connect incoming requests to controllers and actions." So it's not even Ruby or some recognized Web glue language like HTML or CSS; it's some domain-specific language? Okay, I totally don't get it, so as suggested, for more details, I should refer to "Rails Routing from the Outside In" [3].

This is even more confusing. It says you should do something like this:

    get '/patients/:id', to: 'patients#show'
Huh? What's the deal with the colons and octothorpe? I can guess colon is the signifier for an ID in the URL, but why the pound sign for #show?

    get '/patients/:id', to: 'patients#show', as: 'patient'
And what's the deal with the colons?

I could go on and on. I'm sure that with a few hours of pain and frustration, I would be able to figure out exactly all the oddities of Ruby syntax, or the template language, or the DSL whatever, and understand this example well enough to extend it.

But that's not the point. The point is that, because I have to spend those hours, it means that Ruby/Rails is poorly designed. In Django, by contrast, things are almost always simple and obvious.

[1] https://news.ycombinator.com/item?id=5872899

[2] http://guides.rubyonrails.org/getting_started.html

[3] http://guides.rubyonrails.org/routing.html

Re: Rails – The Missing Parts

#147
post #47
post #39

The proof is always in the pudding. While there are good and reasonable times to introduce "interactors", this particular example is poor. The tests presented are anemic, and the code is absolutely not any clearer by being extracted and wrapped. I would indeed have kept all this in the controller. The key point for an "interactor" extraction is imo when you have multiple models being created in symphony, like a Signu…

I rewrote the code in this example to use the "Beginner's Version" of Rails ( sigh ). You judge which you like better: https://gist.github.com/dhh/9333694

Say you wanted to do the same thing from a Rake task or the console. Wouldn't an interactor be a nice thing to have then?

Re: Rails – The Missing Parts

#148
post #39

The proof is always in the pudding. While there are good and reasonable times to introduce "interactors", this particular example is poor. The tests presented are anemic, and the code is absolutely not any clearer by being extracted and wrapped. I would indeed have kept all this in the controller. The key point for an "interactor" extraction is imo when you have multiple models being created in symphony, like a Signu…

I've only been involved in a couple of Rails projects (at least since the wedding list management app I wrote for my own wedding back in the v1 days), I'm in complete agreement with David. And honestly, Rails already has something that works beautifully for an “interactor” extraction. It's called ActiveModel. Add a bit of other code (include ActiveModel::ForbiddenAttributesProtection, ActiveModel::Validations::Callba…

> And honestly, Rails already has something that works beautifully for an “interactor” extraction. It's called ActiveModel.

The thing which Rails and DHH offer no guidance whatsoever is the separation of persistence from the domain model. The Active Record pattern is itself a conflation of those two things, so this is an opinionated choice, and I respect it as a sane default for a wide variety of applications. It works perfectly fine up to a certain scale but when the business logic reaches a certain complexity and the persistence logic reaches a certain complexity then it makes sense to separate them. A lot of proposed solutions might be overkill, but keep in mind that DHH and the company formerly known as 37signals specialize in minimalist software, so they combat this complexity from the UX down rather than conceiving architectures to support it. I agree with this philosophy insomuch as all else being equal, simpler is better, but the problem is that some applications are necessarily more complex than Basecamp, and sometimes we need more than what Rails provides out of the box. Convincing DHH of this is pointless because he doesn't have to deal with it and he has no incentive to understand anyone else's pain in this regard.

Re: Rails – The Missing Parts

#149
post #145

The first missing part: A language with a sane syntax. For some examples of the multitude of ways in which Ruby syntax is awful, see [1]. The second missing part: Ruby is Rails. Trying to learn Ruby at the same time as a modern web framework with all its moving parts? Forget it. The third missing part: Tutorials. Okay, I haven't done a rant on this. Google rails tutorial. The first helpful result I get [2], I scroll…

Ruby has a sane syntax. It probably seems a little foreign if you're new.

'#' is the standard notation used throughout the Ruby language for instance methods.

Think of it like this:

  Blog::Application.routes.draw do |implicit_self|
    implicit_self.get( '/patients/:id', { to: 'patients#show', as: 'patient' } )
  end

Re: Rails – The Missing Parts

#150

Earlier quoted context omitted.

> What would you say is the maximum LOCs for a public controller method? As small as it needs to be in order to get the job done, and as large as it must be to get it done clearly. Sometimes that's zero lines of code; sometimes it's 500. You can usually factor down a 500 line method, but it may be worth asking what the breadth cost is should the code really be single-use. If your metric is anything else, then you're…

Do you have an example of a public controller method larger than even 25 lines that does its job clearly?

Controller method that I can share? No.

This method in mime-types is reported by Code Climate as a code smell. They're wrong: it's the smallest it can possibly be while still correctly performing the necessary goal; any smaller, and you have to break it into multiple smaller methods that provide no value except keeping Code Climate happy. https://github.com/halostatue/mime-types/blob/master/lib/mim... The method is ~35 lines long. There are other cases I can provide from open source work (https://github.com/halostatue/mime-types/blob/master/lib/mim... is a good example: deprecated code, parser for a file type where splitting into multiple methods only complicates the logic flow).

It is true that the larger a method gets the less readable, understandable, and clear it gets—but that should never translate into the sort of nonsensical request you made, asking about maximum LOC. Asking that paints you as a prescriptivist who doesn't bother understanding the context the code requires.

I've been writing software for a long time, and while I try to write methods as short, clear, composable “paragraphs”, I sometimes will write something much longer than is readable because I can't figure out a meaningful way to break it down. That comes over time and reading and interaction with the code.

The best developers in my experience are pragmatic. They are aware of design patterns, but don't treat them like sewing patterns. They are aware of development practices, but don't treat them like holy writ. The GoF design patterns book is an excellent descriptivist treatise, but then people started treating it like a cookbook and looked for reasons to implement Patterns everywhere, rather than extracting the patterns from their code.

Blog posts like this one (that tell me that I should use an Interactor) pattern are actively dangerous, because they provide dicta without properly explaining the pain that the pattern evolved to solve, or the proper evolution of the pattern.

The current code base I work on shows a lot of evidence of Rails Fads just like this one, and I'm trying to get my team to step back and ask why we do things certain ways and to go back to first principles. Don't just reach for a Presenter because it's what was done before. Don't even reach for an ActiveModel::Serializer because it's what we're preferring now for API representations. Figure out your problem. State it clearly. Write the solution clearly. Find code that works similarly and figure out (a) if and (b) how they can be extracted into common code.

There is a cost to adopting things like Presenters and making smaller methods: your interface becomes larger. You can complain all you like of large files and functions, but code bases that have large numbers of classes whose purpose aren't clear…are harder to navigate and understand. (I have, in the current code base, unextracted code from external classes when that external class is used in one place and it makes the behaviour more understandable. It also provides a better place to understand where similar behaviour may appear later so that we can properly extract code if and when it is necessary later.)

Post reply on HN