4 ms·
I agree. As an example having to create a class for bags of methods that don't fit naturally anywhere is bad. I also despise all the manager, factory, service,
by pmontra 4y ago
I agree. As an example having to create a class for bags of methods that don't fit naturally anywhere is bad. I also despise all the manager, factory, service, command things that emerge more often in OOP projects than in functional ones. I know that they denote well known patterns (if used in that way) but it's clutter, boilerplate, noise around the code that does the job. However functional only is not necessarily better in my experience.
Some context. I'm sure I'm biased by a number of factors. One is that I started programming a long time ago in C and I was passing around structs with data and function pointers, so objects. Another one is that I used a number of different languages, currently Elixir, Python, Ruby, some JavaScript, often in the same week for different customers: I like easy to understand code because I this kind of projects with sparse teams is easier to maintain than layer over layer of heavily engineered one (so factories, metaprogramming, etc.) Third, I end up using a minimum common denominator of all those languages plus inescapable and/or great features: I wish all languages had Elixir's pattern matching. This approach works and it reduces the context switch between projects.
So, when I'm coding in Elixir sometimes I have to create large data structures and pass them around, piping them to Module1.fn1, Module2.fn2, etc. It's more or less the same than composing methods in OOP, just different syntax. Sometimes those modules become bags of functions too. What's more difficult to do in OOP is to engineer a class to accept arbitrary meaningful methods. In Ruby I often code methods that return a hash (Python dict, JS object) and create a pipeline of .map.map.map in their caller, like a |> pipeline in Elixir.
I prefer mixed paradigm approaches, where one can create the few classes needed to represent the few data types that are objects (Elixir's and Erlang's GenServer) and code everything else as functions. I have a couple of Django projects where the only classes are the mandatory database models and management commands. Everything else is functions in modules. That would be much more pleasant to code in Elixir (if it had classes instead of those noisy and uninformative handle_call, handle_cast, start_link.) Ruby has modules too but for some reason customers really like to create classes for everything, even two method ones like
class Command
def initialize(args)
...
end
def run
...
end
end
Command.new(args).run
which are quite funny to look at. That should be
command(args)
- Tainnor 4y ago> Ruby has modules too but for some reason customers really like to create classes for everything, even two method ones like [...] Encapsulation and extraction of complex functionality (yes, you should not do it for trivial one-liners). In Ruby, classes get used a lot for this because, uh, why not, but you might as well just have a module method - it's just that the way modules are used in Ruby makes this slightly awkward because Ruby is after all biased towards "everything is an object". But in, say, Haskell I might write instead: module Command run :: [String] -> IO () run = ... -- some other file import qualified Command ... Command.run args (not that "Command.run" looks like super idiomatic code in Haskell or anything like that, probably you'd structure your code differently, but it's the general principle)