This is a perfect example of something that looks good in a demo but fails in a real product. Business logic and 'packages' are never this clean or simple. Putting this kind of type-based 'magic' in the code is a bad decision that will bite you very soon. It optimizes for being 'cute' rather than being clear and maintainable, and that's a trade-off that almost never pays off.
Friendly attributes pattern in Ruby
11–20 of 78 posts
Re: Friendly attributes pattern in Ruby
#12This is a perfect example of something that looks good in a demo but fails in a real product. Business logic and 'packages' are never this clean or simple. Putting this kind of type-based 'magic' in the code is a bad decision that will bite you very soon. It optimizes for being 'cute' rather than being clear and maintainable, and that's a trade-off that almost never pays off.
They do say they use this in their real production code.
Re: Friendly attributes pattern in Ruby
#13Yikes. This means that you’ll have 1000 micro-DSLs sprinkled all over your codebase, which will become unreadable and lead to confusion/accidents. Better to stick with good ol’ key-value labelling.
This is a philosophy. One which many people that write Ruby subscribe to. The fundamental idea is: create a DSL that makes it very easy to implement your application. It is what made Rails different when it was created: it is a DSL that makes expressing web applications easy. I don't know its history well enough, but it seems to originate from Lisp. PG wrote about it before [1]. It can result in code that is extremel…
If there is a DSL such as Rails’ URL routing, which will be the same in every app—this is also fine.
When one makes 100s of micro-DSLs for object creation, that are only ever used in one or two places—this is pure madness.
Re: Friendly attributes pattern in Ruby
#14Or, as Patrick McKenzie used to tell us over and over, “charge more”.
(Yes, yes, I know some situations, customers, product, thinking, etc are different. But with broad brushstrokes, my advice is to not even entertain such a low price.)
Re: Friendly attributes pattern in Ruby
#15This way of handling attributes is monumentally less efficient than just using keyword attributes, which are optimized by the runtime.
Unfortunately you’ll find this is every Ruby code base: tiny readability improvements that are performing allocations and wasting cycles for no real reason other than looking better.
I’ve certainly done that and it’s expected, efficient code looks “weird”. A regular “each” loop that looks complicated will be transformed into multiple array method chaining, allocating the same array many times. If you don’t do it someone else will.
Re: Friendly attributes pattern in Ruby
#16When I say Ruby is inefficient it’s not just the language, it’s stuff like this. I don’t fault the author but this kind of stuff is endemic. This way of handling attributes is monumentally less efficient than just using keyword attributes, which are optimized by the runtime. Unfortunately you’ll find this is every Ruby code base: tiny readability improvements that are performing allocations and wasting cycles for no…
Let's take this example from the article:
Billing::Plan.find_or_create_all_by_attrs!(
1.month => {standard: 10, pro: 50, enterprise: 100},
1.year => {standard: 100, pro: 500, enterprise: 1000}
)
This ensures six billing plans are created. That means 6 DB queries and 6 Stripe API queries, at a minimum.Re: Friendly attributes pattern in Ruby
#17This is a perfect example of something that looks good in a demo but fails in a real product. Business logic and 'packages' are never this clean or simple. Putting this kind of type-based 'magic' in the code is a bad decision that will bite you very soon. It optimizes for being 'cute' rather than being clear and maintainable, and that's a trade-off that almost never pays off.
Here's the example that runs in hundreds of integration tests:
expect(billing_pricing_plans).to eq billing_plans(
1.month => [:free, :premium, :pro, :enterprise],
1.year => [:free, :premium, :pro, :enterprise]
)
It asserts what plans the customers see on the pricing page.Re: Friendly attributes pattern in Ruby
#18When I say Ruby is inefficient it’s not just the language, it’s stuff like this. I don’t fault the author but this kind of stuff is endemic. This way of handling attributes is monumentally less efficient than just using keyword attributes, which are optimized by the runtime. Unfortunately you’ll find this is every Ruby code base: tiny readability improvements that are performing allocations and wasting cycles for no…
The usual response to this complaint in the Ruby/Rails community is that optimizing for nanoseconds, or even milliseconds doesn't matter when the same operation also involves multiple database queries or API calls. Let's take this example from the article: Billing::Plan.find_or_create_all_by_attrs!( 1.month => {standard: 10, pro: 50, enterprise: 100}, 1.year => {standard: 100, pro: 500, enterprise: 1000} ) This ensur…
The problem with that logic is that it’s pervasive: people have that same attitude everywhere even if no IO is being done. That’s how we get multi gigabyte processes.
The whole language (and Rails) also pushes you towards a less efficient path. For instance you’re probably iterating over those six plans and inserting them individually in the DB. Another approach would’ve been to accumulate all of them in memory then build and perform a single query. That’s not something people really consider because it’s “micro” optimization and makes the code look worse. But if you miss out on hundreds of these micro optimizations then you get a worse system.
In a general sense optimizing Ruby is indeed futile: any optimization is dwarfed by just choosing a different language.
I say all this as someone who has worked with it for two decades, I like the language, it’s just laughably inefficient.
Re: Friendly attributes pattern in Ruby
#19This is a perfect example of something that looks good in a demo but fails in a real product. Business logic and 'packages' are never this clean or simple. Putting this kind of type-based 'magic' in the code is a bad decision that will bite you very soon. It optimizes for being 'cute' rather than being clear and maintainable, and that's a trade-off that almost never pays off.
Hi, I'm the author of the article and the software library. I confirm I actually do use the examples from the article in my code. Here's the example that runs in hundreds of integration tests: expect(billing_pricing_plans).to eq billing_plans( 1.month => [:free, :premium, :pro, :enterprise], 1.year => [:free, :premium, :pro, :enterprise] ) It asserts what plans the customers see on the pricing page.
Re: Friendly attributes pattern in Ruby
#20I don't really like the API design. Perhaps in the rails-world this makes sense, but it looks really strange to me. Billing::Plan::Factory.find_or_create_by!( name: :pro, interval: 1.month, amount: 50 ) It is not only the verbosity or use of trailing '!' in a method for no real reason, IMO, but also things such as "1.month". I understand that rails thrives as a DSL, but to me having a method such as .month on an Inte…
Ruby itself mostly uses it for mutating methods (e.g. #gsub("a", "b") replaces the character a with b in a string and returns a new string, but #gsub!("a", "b") mutates the original.