1. 4

  2. 3

    I’d say I mostly agree with the author for happy-path code. I don’t use try and other such things there much. Where I tend to use things like that more is in failure handling code. Failures and coding errors in other places can lead to all sorts of errors involving things being of the wrong type, things not being present where they should be, etc. The main code should in fact blow up when things aren’t the way that it expects, but when that happens, you want the failure handling code to not blow up no matter what and log something useful. It’s no fun at all when you’re process keeps dying and you can’t figure out why because the error logging code died too.

    1. 3

      Just use try! instead of try. It returns nil only if receiver is nil, otherwise it raises NoMethodError.

      “Law of Demeter” is a strange cult which I’ve seen followed only by rubyists. How introducing Payment#client_address reduces coupling? This is just virtual flattening of tree-like or graph-like data structures. Should I define method for each property for each sub-object of Payment? Payment and Client are data classes, they shouldn’t be even viewed from OOP viewpoint.

      I once worked on project where everyone tried to enforce “Law of Demeter” on traversing json in Javascript (more precisely, Coffeescript, and backend was in Ruby).

      1. 4

        If you only want to handle real nil you can use &. – no ActiveSupport needed!

        1. 2

          How introducing Payment#client_address reduces coupling?

          He used the phrase “structural coupling”, which doesn’t immediately mean anything to me, but I can hazard a guess.

          A function that operate on thing.client_address is more broadly usable than a function that operates on payment.client.address, since you may also have a function that operates on contract.client.headquarters.address or similar. This is a general problem that one encounters when you have outbound foreign keys, and becomes more pronounced when refactoring introduces additional indirections. In Clojure, which has namespaced keys, I’ve found it extremely useful to flatten structures when processing events or other somewhat implicitly defined heterogenous collections of entities.


          {:artist/name "Artist"
           :track/name "Track"
           :album/name "Album"}

          Is that an Artist object? A Track object? Or an Album object? You can use functions that operate on any of the three!

          Compare to:

          {:track {:name "Track"
                   :album {:name "Album"
                           :artist {:name "Artist"}}}}

          That’s obviously a Track object. If I have a function for formatting a track/artist name pair, I could have used it directly with the flattened structure. However, here, I have to traverse the Album edge. If I later extend my data-model to support multiple artists per album (adding an :artist key to a Track object), I’d have to change my code.

          1. 1

            The “Law of Demeter” is also heavily pushed by Bob Martin and his vision of TDD-based Java development. I want to say I’m a fan, but like so many things it’s all about the right tool or methodology for the right job, and the LoD isn’t always the best for speed or clarity.

          2. 2

            I mean this with no snark - But perhaps the author shouldn’t be using Ruby? The (very) dynamic type system is it’s biggest strength and weakness. And one of those weaknesses is constantly wondering what kind of object you’re dealing with.

            Plus, this might be possible in your own confines, but Ruby is also about the gems. The Law of Demeter is fine, but equally I don’t see it applied in libraries - where idiomatic Ruby* has a lot of “magic”. Expressiveness is favored over correctness and encapsulation - dynamic programming, operator overloading, monkey-patching, DSL-for-everything.

            *I’d be hard pressed to nail it down to be honest.