• The REPL: Issue 75 - November 2020

    Why Ruby Class Methods Resist Refactoring

    Sasha Rezvina explores why class methods in Ruby are hard to refactor. They tend to accumulate lots of logic. I prefer limiting class methods to “builder” methods that instantiate new objects, like .initialize.

    Verbal Expressions: Ruby Regular Expressions made easy

    This looks like a fantastic library. It provides a way to “verbally” construct regular expressions:

    tester = VerEx.new do
      start_of_line
      find 'http'
      maybe 's'
      find '://'
      maybe 'www.'
      anything_but ' '
      end_of_line
    end
    
    tester =~ "https://www.google.com"
    

    It supports string replacement, and capture groups too!

    Moving my serverless project to Ruby on Rails

    This article illustrates one of my worries about the server-less trend: Each lambda function might be simple, but there interactions are not, and that is hard to reason about (and deploy!).

    When the building blocks are too simple, the complexity moves into the interaction between the blocks.

    Read on →

  • The REPL: Issue 74 - October 2020

    Introduction to the Zettelkasten Method

    The Zettelkasten method is a sort of personal note-taking method. This articles explains why the method is interesting in the first place, it’s principles and a few possible ways of using it. I’ve been gravitating in the last few years to a similar method, which doesn’t quite adhere to all the principles. I’ve long known that writing things down helps clarify your thoughts; having to articulate your thoughts, makes you a better thinker. It also helps with knowledge retention. What struck me most as I read this article is that there is another level of value that comes from the effect of capturing more things and linking thoughts together. That is what turns facts into knowledge: Knowing how it relates to other thoughts.

    As I was reading, I noticed that I often capture thoughts in my daily note. That is better than not capturing at all, but it doesn’t make it discoverable in the future. Since reading the article, I’ve started creating separate notes for each individual “thought” and tagging it. I am also making an effort to link – at the time of writing – with other notes.

    The Pyramid Principle

    Shiva Prabhakaran at Models HQ writes about the Pyramid Principle, which recommends that you start communicating with your answer/hypothesis first and then support it with arguments and data.

    My natural instinct when speaking, is to do something similar to this recommendation (but not quite): Start with the answer, and then add context. This recommendation goes a bit further: Answer, summary, and then supporting arguments.

    When writing, my instinct is more to start from the context, walk through the rationale and arguments, and then get to the conclusion. That follows my train of thought, which I expect my readers to follow. This article explains why it might be better to start in the other direction.

    The recommendation comes from consulting companies and their communication with executives. Its applicability might be limited.

    Rbspy

    This week I found myself working on optimizing the performance of a refactored Rails endpoint. I found rbspy:

    rbspy lets you profile Ruby processes that are already running. You give it a PID, and it starts profiling. It’s a sampling profiler, which means it’s low overhead and safe to run in production.

    rbspy lets you record profiling data, save the raw profiling data to disk, and then analyze it in a variety of different ways later on.

    This made it painless to get data on a running process without much fuzz. It even generates flamegraphs.

    Read on →

  • The REPL: Issue 73 - September 2020

    Under Deconstruction: The State of Shopify’s Monolith

    The engineering team at Shopify discuss the state of their Rails monolith, how it has evolved over time, the lessons they’ve learned and what is in store for the future. Most of the information is relevant for Rails developers working in large systems, with large teams.

    As part of their efforts to make their monolith more effective, they are introducing a newly-open sourced tool: Packwerk. The objective is to enforce modularity, through the use of static analysis.

    Writing a book: is it worth it?

    Martin Kleppmann discusses openly the economics of writing his book: Designing Data-Intensive Applications. The book has been one of my favorite technical books. The book has generated almost $500,000. It involved working on it for years – one of them without any other income, speaking at more than 50 conferences promoting the book, and was helped in no small part because of Kleppmann’s well deserved presence and reputation in the field.

    Read on →

  • The REPL: Issue 72 - August 2020

    Error handling with Monads in Ruby

    Vitaly Pushkar goes over error handling in programming languages and the reasoning for using monads for error handling. I’ve been experimenting with that at work record with very positive results – albeit in a limited portion of our code.

    There is a section where the author talks about the “pyramid of doom” – much like the dry-monads documentation. The “do notation” is presented as a solution. Maybe it’s my lack of familiarity with that notation, but I think that there is a simpler solution, which I call “railway oriented”.

    Pyramid of Doom:

    def call(fields)
      validate_fields(fields).bind do |fields|
        validate_email(fields['email']).bind do |email|
          find_user(fields['id']).bind do |user|
            update_user(user, {name: fields['name'], email: fields['email']}).bind do |user|
              send_email(user, :profile_updated).bind do |sent|
                Success(user)
              end
            end
          end
        end
      end
    end
    

    Do notation:

    def call(fields)
      fields = yield validate_fields(fields)
      email = yield validate_email(fields['email'])
      user = yield find_user(fields['id'])
      user = yield update_user(user, {name: fields['name'], email: fields['email']})
      sent = yield send_email(user, :profile_updated)
    
      Success(user)
    end
    

    Note that the yield in the above solution differs from the standard Ruby meaning. It doesn’t yield to the block passed to #call but rather binds the Result and halts execution of the method on failures.

    My “railway oriented” solution:

    def call(fields)
      validate_fields(fields).
        bind { |fields| validate_email(fields['email']) }.
        bind { |_email| find_user(fields['id']) }.
        bind { |user| update_user(user, {name: fields['name'], email: fields['email']}) }.
        bind { |user| send_email(user, :profile_updated) }
    end
    

    The “pyramid of doom” is avoided, without having to change the Ruby semantics.

    How to stop procrastinating by using the Fogg Behavior Model

    The Fogg Behavior Model is a new concept for me. It presents a mental model in which:

    Behaviour = Motivation + Ability + Trigger
    

    A lack in any of the three factors can prevent behavior from occurring. The articles then talks about different strategies to boost each factor. For example, blocking time in your calendar can serve as a trigger to start working on a particular task. I’ve been very successful with that technique lately.

    Read on →

  • The REPL: Issue 71 - July 2020

    Simple Made Easy

    This talk is not new, but it is new to me. I’ve seen reference to this talk in many places, but hadn’t watched until recently.

    Rich Hickey emphasizes simplicity’s virtues over easiness’, showing that while many choose easiness they may end up with complexity, and the better way is to choose easiness along the simplicity path.

    This is a fantastic talk! It describes how software that is simple is the ultimate goal. Simple is achievable, but it is not the same as easy. It goes hand-in-hand with choosing the correct abstractions and planning beforehand. It’s not about hiding complexity, it’s about abstracting it away. It reminds me of something that I distilled from somewhere else as:

    An abstraction removes from your mental load. Indirection adds to it.

    An abstraction lets you forget about the details and allows higher order thinking. Indirection forces you to think about the details constantly.

    Result Objects - Errors Without Exceptions

    Tom Dalling of Ruby Pigeon introduces his library Resonad. It aims at dealing with error handling without exceptions. The article gives a good overview why and when to use result objects. There are other libraries in the Ruby ecosystem (like dry-monads). As the author points out, it doesn’t actually take a lot to build your own. I did so recently and was pleasantly surprised how far a very simple implementation can take you:

    class Failure
      attr_reader :error
    
      def initialize(error)
        @error = error
      end
    
      def successful?
        false
      end
    
      def failure?
        true
      end
    
      def and_then
        self
      end
    end
    
    class Success
      attr_reader :value
    
      def initialize(value)
        @value = value
      end
    
      def successful?
        true
      end
    
      def failure?
        false
      end
    
      def and_then
        yield(value)
      end
    end
    
    Success.
      new(1).
      and_then { |v| Success.new(1 + 1) }.
      and_then { |v| Failure.new(:boom) }.
      and_then { |v| Success.new(1 + 1) }
    # => #<Failure:0x00007f9eda02f280 @error=:boom>
    

    At work, I am evaluating the usage of result monads as part of some work to better encapsulate domain logic. I am expecting it will be very beneficial in how we handle errors.

    Read on →