5 ms·
Lots of good points. I gotta blame my Elixir tutorial (Dave Thomas) for some bad habits: over-reliance on pipes and pattern-matching in function args. He hates
by msie 5y ago
Lots of good points. I gotta blame my Elixir tutorial (Dave Thomas) for some bad habits: over-reliance on pipes and pattern-matching in function args. He hates if-then in a function. He would take an if-then in a function and split both clauses out into their own function. Seemed fishy to me. Trying too hard to be elegant.
- macintux 5y agoI agree with Dave on the pattern matching in function heads, at least from your description. Garrett Smith’s blog post on tiny functions[0] has heavily influence my Erlang. [0]: http://www.gar1t.com/blog/solving-embarrassingly-obvious-problems-in-erlang.html http://www.gar1t.com/blog/solving-embarrassingly-obvious-pro...
- ludamad 5y agoI notice he says the result needs less testing; to me such a rewrite amounts to an audit of the code and thus leaves one with more confidence, definitely. I'd just buy it more perhaps with stringent static types, but I've become a 'gradual typing purist' in a way (in this process, if you're not littering types everywhere you are missing a lot of value)
- nivertech 5y agoThere are lots of contradicting advice in the Erlang/Elixir land. Garret Smith likes microfunctions, while Saša Jurić avoids them. Same with "tagged with statement" pattern - Saša Jurić prefers it over Ecto.Multi in transactions, while this post discourages it's use at all.
- nemetroid 5y agoThe author uses the word "religion" in a jocular manner, which seems appropriate, but probably not in the way he intended. This particular style often seems to get applied as a dogmatic pattern. The underlying principles are good, but the author should have stopped halfway. For example, the article has this: handle_db_create_msg(Msg, State) -> log_operation(db_create, Msg), handle_db_create_result(create_db(create_db_args(Msg)), Msg, State). create_db_args(Msg) -> [create_db_arg(Arg, Msg) || Arg <- [name, user, password, options]]. create_db_arg(name, Msg) -> db_name(Msg); create_db_arg(user, Msg) -> db_user(Msg); create_db_arg(password, Msg) -> db_password(Msg); create_db_arg(options, Msg) -> db_create_options(Msg). create_db(Name, User, Password, Options) -> stax_mysql_controller:create_database(Name, User, Password, Options). There is no shared logic between the different cases in create_db_arg() (creating a false sense of abstraction where there is none). create_db() has to take its arguments as a list* in order for the design to work, but the use of a list suggests homogeneity between the elements, which is not the case. It would have been much better to stop at this point: handle_db_create_msg(Msg, State) -> log_operation(db_create, Msg), Name = db_name(Msg), User = db_user(Msg), Password = db_password(Msg), Options = db_create_options(Msg), Result = stax_mysql_controller:create_database(Name, User, Password, Options), handle_db_create_result(Result, Msg, State). *: which the author also forgot when making the final listing at the end of the blog post.
- derefr 5y agoMind you, when some of the Elixir books were written, the `with` syntax didn't exist yet.
- ConanRus 5y agoThis is a standard Erlang pattern and what's make it so great. And Erlang VM is optimized for that.
- matt_s 5y agoHaving lots of gnarly if-elsif-else blocks of code elsewhere where the logic conditions are varying in number it is nice to encapsulate that in a pattern match function. For me, it doesn't mean "thou shalt not use if-then ever" just that if you have enough conditionals and logic needed, pattern matching is better suited for those cases (sorry for the pun).
- msie 5y agoGood to hear all the opinions. I'm an Elixir newbie and I appreciate them.
- brightball 5y agoI came out of that Dave Thomas classes with a lot more good habits than bad. I don't follow everything he does, but the vast majority of it made a lot of sense to me and results in much cleaner code.
- innocentoldguy 5y agoI started my Elixir journey with Dave Thomas, too, and I agree with your commentary. I think most of Dave Thomas' style is highly organized and readable. One of my favorite Dave Thomas tidbits was writing private functions like this: defp _private_function(params) do # Do something end Whenever I see a function that starts with an underscore, I KNOW it is a private function in the current module. I don't have to go looking for it or wonder where it came from. I know at a glance that it is a private function. Readability and organization are so important in code and I felt that Dave Thomas helped me get off to a great start in this regard.
- ofrzeta 5y agopattern-matching in arguments means that the picking the function according to its signature is the actual decision process? If you have a function that doesn't contain a decision it is easier to unit test, isn't it?
- innocentoldguy 5y agoNo. It's the same. If you have a function with a large if statement in it, you'd want to test all conditions within that if statement to make sure it was working, right? You'd do the exact same thing if you were testing a series of pattern-matched functions. The tests would be unchanged either way.
- jkhdigital 5y agoI think it makes it easier to tick off the list of cases that need to be tested: one for each head.
- ofrzeta 5y agoYou'd have the number of tests broadly but they are simpler because they don't need to handle the cases hidden in the functions themselves. Maybe in the end it's the same or a matter of taste but it recently occurred to me that unit testing becomes "cleaner" that way.