Live data from Hacker News

Rails – The Missing Parts

eng.joingrouper.com

131–140 of 173 posts

Re: Rails – The Missing Parts

#132
post #48

Earlier quoted context omitted.

Coulda, woulda, damn shoulda. You're future coding with your "what ifs". Most controller actions are not reused. The time to extract for reuse is when you need to reuse. Not crystal balling about that you probably will be in the future. Because when the reuse case actually arrives, you might find that you need to reuse some, but not all of the action. If you're literally doing the exact same thing for both web and ap…

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 playing Stupid Metrics Games, like that espoused by Code Climate.

Re: Rails – The Missing Parts

#133
post #120

Earlier quoted context omitted.

I hope I am not sticking my head into the lion's mouth here, but here ( https://gist.github.com/BiggerNoise/9334673 ) is a link to a gist of some code in one of our apps. Cases have Tasks and Activities. Activities are always associated with a case, and may be associated with a task. In the controller, when assigning a case, one would type: AssignCaseCommand.new(params).execute! The command class implements the Comma…

I think it's great that you stick your head into the lion's mouth, even if he chewed it clean off it's a great contribution :) I think the main problem with your command pattern approach is that you didn't implement the full command pattern. At least, I assume you didn't, you didn't actually show the controller. The command pattern has one extra class, the invoker. The invoker takes commands, and invokes them. A grea…

Honestly, I was disappointed in his response. With all his harrumphing about real examples, I would have expected him to make an effort to understand a real example. But, as I said elsewhere, the downside of real examples is that they require quite a bit more effort to grasp than contrived ones.

To address your comments:

While it is true that one of the great features (and frequent motivations) for using the Command pattern is the separation of the creation and invocation, it is not the only motivation. The two big payoffs that we are getting are:

- Separation of invocation from the knowledge of how it is carried out

- Composition of complex commands from smaller, simpler commands

There's no requirement that the invoker is never the same as the creator. It's just that most often it isn't, particularly (as you noted) in a worker queue system. That's really just a feature of the implementation that the command readily enables rather than a fundamental property of the pattern. For us, sometimes it is, sometimes it isn't; that's not the primary payoff that we're going for.

I can't support the characterization of this as an Adapter. This is fundamentally behavioral. I have a class that represents an action that I want to have happen. All of the places that want this action do not need to know what is involved, they only need to create the command and hand it off/invoke it.

FWIW - I have five different places in my software that create an AssignCaseCommand. - One controller

- Three commands that can create this as a sub command

- A utility job

Plus that simple concept is available to any custom implementation code that we write.

Re: Rails – The Missing Parts

#134
post #121

Earlier quoted context omitted.

Oh I insist. "If they were, the persistence would be handled elsewhere." Persistance is handled elsewhere, it's handled in the superclass. If you think that's not a good idea, you shouldn't be using ActiveRecord, because that's the way it works. You could argue there's not enough abstraction from the DB in AR, but that's a different discussion. Here we discussed if the persistance callbacks were an appropriate tool f…

Jesus christ. You aren't seriously arguing that handling it in a parent class removes it from the AR object's responsibilities, are you? In point of fact, that inheritance pattern is a bad idea, and I don't use it when I'm implementing an actual domain model, but that's seriously irrelevant. 1) I did argue exactly that; 2) it follows from (1) that an evented mechanism based on the database lifecycle of such objects i…

No. I was not arguing anything about it, but the fact that it is a proper abstraction.

The persistence is part of the domain. You need to know about when your objects are persisted and when they are not, this can be an intrinsic part of some of your business logic. Thus the events are relevant to your domain.

Of course not all your business logic needs to be aware of persistence, and nowhere do you see me arguing that all business logic should be in concerns included into the AR class.

Don't put words in my mouth, and don't assume I am stupid. You are arguing in a rather ad-hominem way, and it is diminutive to your arguments.

Re: Rails – The Missing Parts

#135
post #127

Earlier quoted context omitted.

To be fair, Rails does have concerns which let you easily compose your models out of modules, rather than having big god-object models, and it is easy to load other arbitrary collections of code too. So it is not really limited to MVC. For beginners, I'm not sure it would be helpful to introduce a whole load of named patterns, as it just leads to cargo-culting and overuse of patterns without understanding whether the…

The problem with concerns is that they don't actually break down the god classes, they just separate the pieces of the god class into different files and combine them at runtime. The important metric here isn't "wc -l app/models/god.rb", it's "God.public_instance_methods.length".

You don't have to use them for that, you can use them for composing models out of shared bits of functionality, for example 5 of your models have a status - put all the code about statuses in one place in a concern and include Status in your models, and possibly similar for controllers - this cuts code duplication.

There is also an argument for making models smaller by splitting some of their functionality into modules too (what you're talking about), but I think that's a weaker case - better to use concerns for shared code.

Re: Rails – The Missing Parts

#136

Earlier quoted context omitted.

Perhaps that's why the OP used a simple example. Complex examples are pretty hard to get your head around at first glance; even sane systems can be perceived as a 'hot mess' upon a quick read without any context. I disagree that re-assigning a case belongs in the case model. It is a complex interaction between several models. Extracting it to a command object allows all of the rules to be easily understood.

It's a model, all right—but it may not be part of the “Case” model. It might be part of a CaseAssignment model that is (for lack of a better word) a virtual model. Or it's part of the controller that does the changes. It mostly depends on how your code gets used and where it gets used from. When I did something similar[1], I implemented it as a “virtual” model and applied validations to make sure that the PlanChange…

Although I would never call that a model, I think that we're doing similar things for similar reasons.

Command, Virtual Model, Verb Model, Interaction. If I were working on your team I am sure we could agree that one of those would do for a name.

Re: Rails – The Missing Parts

#137
post #134

Earlier quoted context omitted.

Jesus christ. You aren't seriously arguing that handling it in a parent class removes it from the AR object's responsibilities, are you? In point of fact, that inheritance pattern is a bad idea, and I don't use it when I'm implementing an actual domain model, but that's seriously irrelevant. 1) I did argue exactly that; 2) it follows from (1) that an evented mechanism based on the database lifecycle of such objects i…

No. I was not arguing anything about it, but the fact that it is a proper abstraction. The persistence is part of the domain. You need to know about when your objects are persisted and when they are not, this can be an intrinsic part of some of your business logic. Thus the events are relevant to your domain. Of course not all your business logic needs to be aware of persistence, and nowhere do you see me arguing tha…

Fair enough—I was being a bit of an asshole. However, when you start your contribution to the thread by insinuating DHH is above reproach, I'm not filled with sympathy. Especially when his architectural hipsterism is IMHO responsible for ruining a couple microgenerations of developers who learned to code through rails.

I can't be the first guy who's put his head through a wall upon hearing you say persistence is part of the domain. The only time persistence is domain is when your domain is the data store. "But AR is the database"—totally correct. the domain of AR is the database. But that is almost never the same as your business domain, and trying to mix the two creates a great deal of incidental complexity.

Re: Rails – The Missing Parts

#138
post #76
post #54

Earlier quoted context omitted.

Yes, rewriting a system after it's already settled and designed can indeed bring a cleaner code base about. But don't confuse that with "better architecture". Don't even get me started on the hand-wavy "loosely coupled". If this is a poor example, pick a good example. I'll be happy to code ping pong you whatever example you choose. One way to spend hundreds of thousands of LOC on an application is to stuff it with ne…

> POROs are great, though. Our app/models is full of them. We even added app/services too. The trouble I have is with people who, like you, fall in love with the flawed notion that their application is such a special snowflake that it deserves "advanced techniques". The main difference I see between the Rails philosophy and most of these "Use SRP and Interactors and things!" blog posts are that Rails is way more inte…

"ONE TRUE WAY is overrated. I'd rather use whatever works given the context." That's it.

Re: Rails – The Missing Parts

#139
How about just "features"?

Maybe there are some "user" features (login, logout, change name) and "cart" features (add/remove item in cart).

These features would all live horizontally, be able to call each other (design your object graph wisely!) and would never be able to inspect or elaborate on implementation details!

These features may or may not talk to some database for its own persistence, but that's up to the functions.

And the features are pure functions in your language of choice. They have no knowledge of the web, or requests, they're perfectly transient. They act on a "state" object that you pass around to them, which in tests is just a blob of memory and in production is a real database or wherever else you store state.

It's simple, yet so powerful. This is how we do it, and it's scaling very nicely.

Re: Rails – The Missing Parts

#140
post #134

Earlier quoted context omitted.

No. I was not arguing anything about it, but the fact that it is a proper abstraction. The persistence is part of the domain. You need to know about when your objects are persisted and when they are not, this can be an intrinsic part of some of your business logic. Thus the events are relevant to your domain. Of course not all your business logic needs to be aware of persistence, and nowhere do you see me arguing tha…

Fair enough—I was being a bit of an asshole. However, when you start your contribution to the thread by insinuating DHH is above reproach, I'm not filled with sympathy. Especially when his architectural hipsterism is IMHO responsible for ruining a couple microgenerations of developers who learned to code through rails. I can't be the first guy who's put his head through a wall upon hearing you say persistence is part…

Yup. Hence "services", as soon as your domain starts to get complicated. You need an abstraction layer between your application flow control (controllers) and your persistence layer (AR, or whatever). At least, that's what I'm given to understand about this. Does that sound right?
Post reply on HN