Just my opinion, but `module_function` is intended for a different situation; it's used when you have a genuine mixin module that appears to contain some free-standing methods that might be useful outside the content of the receiving class.
As a result, it ends up creating an additional method for each method you pass it: it creates a copy that it it injects into the module's metaclass.
`extend self` basically takes the module and moves it's content up a level: what were instance methods become class methods.
To see one of the differences, try creating a module with one method, then a `private` line, and then another method. Finally add `module_function :a, :b`. Outside the module, you can call both M.an and M.b.
Now do the same thing, but use `extend self` instead of `module_function`. You'll find that M.a works, but M.b reports "NoMethodError: private method `b' called for module M (NoMethodError)"
In retrospect (which is an easy position to comment from), Ruby is wrong to use modules for two totally different things: it really needs namespaces _and_ mixins, and not modules.
If I may first ask about something off topic, I found a PDF of Yourdon's 1978 Structured Programming book and searched it for "unit test" and I found four instances of the phrase but no description of what he wanted it to mean to his readers. Do you have any idea of what a unit test was at that time? I think that in the 80s I had a college class that used that book and I have no idea.
Returning to the topic, I think there is an OO programming heuristic that simply says "add another class". I thought came from Reil's OO Design Heuristics book but I can't find it. Many design patterns rely on the addition of new classes so, it isn't wrong but, is it in the general case? When I long ago mentioned the heuristic to a popular Java architect, he objected, "You can't just say that". I asked that if after he assisted a programmer with his code were there more or fewer classes in the resulting code and to his dismay, his answer agreed with the heuristic. Do you see any value in the heuristic?
This article reminds me that Alan Kay wished he had called it Message Oriented Programming.
I can't tell you what Yourdon meant, but I'm guessing it was something similar to its meaning today.
You say "Many design patterns rely on the addition of new classes so, it isn't wrong".
Design patterns are not a good guide to what is right or wrong. The original GoF book is both dated and very specific to C++. Many if not most of those pattern are just not needed in many modern languages.
"Add another class" is like telling someone with an eating disorder to "have another donut".
Dave, how would you change controller and get rid of inheritance then? In your example with point and slope it looks simple and good, but it’s hard to map it to real life controller or to service which validates request params, does some 2 actions and in the end sends email.
Why would it be difficult? The request parameters are in the request, so you extract them and validate them just as you do now. The actions are just functions you can call. Sending email is presumably a service: you'd queue up a job to send it.
There are a bunch of web frameworks that work something like this. Phoenix, for example, is written in a (mostly) functional language, Elixir, and it's controller actions take a connection structure and the request.
Interested in your thoughts on using `extend self` over `module_function`
Just my opinion, but `module_function` is intended for a different situation; it's used when you have a genuine mixin module that appears to contain some free-standing methods that might be useful outside the content of the receiving class.
As a result, it ends up creating an additional method for each method you pass it: it creates a copy that it it injects into the module's metaclass.
`extend self` basically takes the module and moves it's content up a level: what were instance methods become class methods.
To see one of the differences, try creating a module with one method, then a `private` line, and then another method. Finally add `module_function :a, :b`. Outside the module, you can call both M.an and M.b.
Now do the same thing, but use `extend self` instead of `module_function`. You'll find that M.a works, but M.b reports "NoMethodError: private method `b' called for module M (NoMethodError)"
In retrospect (which is an easy position to comment from), Ruby is wrong to use modules for two totally different things: it really needs namespaces _and_ mixins, and not modules.
If I may first ask about something off topic, I found a PDF of Yourdon's 1978 Structured Programming book and searched it for "unit test" and I found four instances of the phrase but no description of what he wanted it to mean to his readers. Do you have any idea of what a unit test was at that time? I think that in the 80s I had a college class that used that book and I have no idea.
Returning to the topic, I think there is an OO programming heuristic that simply says "add another class". I thought came from Reil's OO Design Heuristics book but I can't find it. Many design patterns rely on the addition of new classes so, it isn't wrong but, is it in the general case? When I long ago mentioned the heuristic to a popular Java architect, he objected, "You can't just say that". I asked that if after he assisted a programmer with his code were there more or fewer classes in the resulting code and to his dismay, his answer agreed with the heuristic. Do you see any value in the heuristic?
This article reminds me that Alan Kay wished he had called it Message Oriented Programming.
I can't tell you what Yourdon meant, but I'm guessing it was something similar to its meaning today.
You say "Many design patterns rely on the addition of new classes so, it isn't wrong".
Design patterns are not a good guide to what is right or wrong. The original GoF book is both dated and very specific to C++. Many if not most of those pattern are just not needed in many modern languages.
"Add another class" is like telling someone with an eating disorder to "have another donut".
Add another method it is then.
Really interesting and I agree on your suggestions :)
Small error: I think you are using the wrong screenshot under
> Our services are then subclasses of ApplicationService
(you show the controller and not the service)
Dave, how would you change controller and get rid of inheritance then? In your example with point and slope it looks simple and good, but it’s hard to map it to real life controller or to service which validates request params, does some 2 actions and in the end sends email.
Why would it be difficult? The request parameters are in the request, so you extract them and validate them just as you do now. The actions are just functions you can call. Sending email is presumably a service: you'd queue up a job to send it.
There are a bunch of web frameworks that work something like this. Phoenix, for example, is written in a (mostly) functional language, Elixir, and it's controller actions take a connection structure and the request.