A Procedure

2011/06/11

The sucker’s choice. Did it happen to you that you need to perform a task and you face a choice of how to do it. You can do it slowly, squeezing out every step and every possibility. Or you can try to do it very quickly, but the outcome may be unsatisfactory. Let me share with you how it happens to me.

An example. From time to time I come up with idea to install some program to my computer. I might be quite impatient to experience the improvement. Then I just search Google, find the first suitable program and start using it. Typically I become frustrated with the software very quickly, because it does not do exactly what i want and I switch back to an old low-tech approach. In another case I may decide to find really good software. So I would find, install and try to use many different popular programs, read related articles on the Internet on topic, several times change decision which one to use. Eventually I might end up reading or doing something unrelated. So again I’m disappointed, but this time because of how much time is wasted.

The mistakes. In the above example I can see at least two my mistakes.

An unclear objective. Without a clear goal it’s difficult to sort out good options from bad ones. I had to try everything hoping that the best choice will eventually become obvious. Sometimes it works, but it’s quite counterproductive.

Overlooked a repeating pattern as an opportunity for productivity improvement. It might look as overkill to spend time on a goal setting, planning and optimizing such trivial process like searching software in Google. Especially if you are not used to planning. But if a task repeats regularly, the time invested in the improvement of productivity will inevitably pay for itself.

A solution for the example. Few months ago I became very enthusiastic about improving efficiency of everyday tasks. So i decided to reflect on what I’m typically doing while searching for a new program and to define a reusable plan of how to do that. The idea was to develop a procedure that allows me to complete the task much quicker than usually.

The procedure steps are following:

  1. Understand the usage scenario (to clarify the requirements);
  2. Write down the required features, order them by priority;
  3. Search programs on a single site, e.g. download.cnet.com: identify the category i need; apply filters to the list; judge features by screen-shots and short descriptions;
  4. Open browser tabs for more or less satisfactory programs, but don’t download them;
  5. Download, install and evaluate only a program that matches all important requirements;
  6. If it’s ok, stop search;
  7. Update the procedure;

Steps 2-6 are necessary to minimize the time spent on evaluating each candidate, as there may be 100 of them. Initially the steps were a bit different. But I updated them after applying the procedure as I understood better what are the needs and opportunities for improvement.

A generalized approach. The take-away from this story is to take notice of your repeating activities, write them down and optimize. Here is my step-by-step guidance for the approach.

  1. Notice a task or an activity that you perform regularly and which needs some optimization. The good candidate is the one for which you have to choose either to do it quickly or to do it properly. Decide to do it quickly and properly.
  2. Write down the procedure step-by-step. Don’t waste time on making the procedure perfect. Just make a draft, some starting step for codifying your experience. Still it may be very useful to add to the procedure a step for clarifying a goal of the activity and a step that reminds to update the procedure. I suggest saving procedure descriptions on your computer, so that you can easily read or update them.
  3. When you need to perform the task, try to follow the procedure. While performing the task, pay attention at which step of the procedure you are right now.
  4. Reflect on your execution. After finishing the task or a step in the procedure, look through the plan and compare with your actual actions. Notice the unnecessary or missing steps in the procedure. Reflect on what was done well, what was done poorly and where an improvement is possible.
  5. Update the procedure accordingly. Updating the plan is a key component here. Experience of performing the task may be not enough to create a good plan. Experience of following the plan is
    what will give sufficient information for creating the good plan.

Pros. Improved focus. Following a well-defined procedure improves an ability to focus in two ways. Firstly you have to deal with a smaller number of aspects of the task. You’ve already done some planning, decision-making and optimization work, so your attention is less distributed between different aspects of the work. Moreover, after several updates of the procedure you clearly know what you should do during the task and what you shouldn’t. So you gain better awareness if you are distracted by a related activity or not.
Better quality. As you stay focused, you notice more details that enable to do better job. Also you easily reuse improvements that you learned while updating the procedure previous times.
E.g. only when i was updating the procedure, i realized that i may examine screen-shorts at cnet.com to avoid time-consuming download-install-uninstall step.

Reduce resistance and procrastination. When I have to do an activity i don’t like to do or don’t know how to do, I tend to resist and procrastinate doing it. On the other hand, when the required steps are clear, at least partially, it’s much easier to overcome internal resistance and dive into the activity. E.g. I stopped resisting to plan the day in the morning after I defined a ‘morning routine’ procedure. I don’t decide if I need to do planning. I just do it as the 5th thing after waking up.

Saved time. You avoid unnecessary or inefficient actions. You do actions in more habitual way. You take decisions just few times as you update the procedure, not every time you do the task. All that contributes to reducing time spent on the task.

More bonuses. Additionally you train you planning skill, you procedural memory and you understand better how to include the task into wider activities.

Cons. Time overhead. Yes. It requires extra time. So if you encounter a new task, it’s might be more efficient just to do it somehow rather than spend a lot of time deliberating about the steps in the plan. Only after you’ve repeated the task a couple of times you might see a benefit from formalizing the process.

Misconceptions. As I used to have, you may have some counterproductive beliefs and attitudes towards formalized procedures. Maybe the following two paragraphs will help you to identify some of them.

Procedures are restricting. I was often resisting standard procedures of doing things. They looked like an unnecessary job, and something that limits my creativity. It happened because either I didn’t understand the reason why a procedure looked like that, or I felt that it’s ignores my interests and my preferred style of work, or the procedure was created by people who don’t understand clearly how the activity should be performed. As you define the routine yourself and update it according your experience and needs you’ll easily avoid all this problems.

A procedure dumbs down a task. Sometimes I perceive a predefine procedure as a way to make a task less intellectually demanding. Thus it limits a person’s intellectual development. In really planning is about effective reusing of an experience. Accordingly it is a learning tool and positively influence creativity repertoire.

Finally. I hope you’ll give a try to planning your routine that need improving of productivity. It definitely will not be wasted time.

Advertisements

Decorators In Ruby

2009/07/15

Few months ago I was really suprised to find out that Ruby doesn’t have any “official” feature similar to Java’s annotations or C#’s attributes or Python’s decorators. And recently I discovered the reason for that: it’s simple to implement them with already available Ruby features. In this article I’ll describe how to mimic Python’s delegates.

So what we want is to put some simple “declarative” construct before method definition and this construct should somehow “enhance” the method: attach to it additional behaviour, annotate it with some meta-data, make advice to a framework to use it as an event handler for some event or whatever. Ruby syntax should look like this:

some_decorator(decorator_arguments)
def some_method(method_arguments)
    method_body
end

Unfortunately, the syntax doesn’t give a cue that this is not an ordinary static method call, but exactly decorator. If it helps you, put it into [brackets] to make it look like C# attributes 🙂

As starting point let’s pick a decorator that will just happily print in the console that he got access to the target method. The decorator should subscribe for a notification about method definitions, notify that he got access to the method, unsubscribe and invoke a next subscriber if any. To accomplish this we need just two main ingredients: method_added and define_singleton_method methods. method_added is called whenever a method is defined. define_singleton_method is new method in ruby 1.9, that allows defining class methods. It’s possible to implement it in version 1.8 also. So our decorator should look somehow like this:

class X
    def self.log_defined(prefix="")
        next_subs = self.method(:method_added)

        define_singleton_method(:method_added) {|name|
            define_singleton_method(:method_added, &next_subs)
            print "#{prefix}method defined: #{name}\n"
            method_added(name) if next_subs
        }
    end

    log_defined "1st decorator: "
    log_defined "2nd decorator: "
    def f; end
end

Output:
2nd decorator: method defined: f
1st decorator: method defined: f

Notice that the decorators are applied in reverse order. It’s exactly what we wanted to emulate Python’s syntax.

Now let’s do a bit more complex thing. We will make a decorator that will print a message to console before and after each call of the target method.

class Y
    def self.log_called(prefix="")
        next_subs = method(:method_added)
        define_singleton_method(:method_added) {|name|
            to_decorate = instance_method(name)
            define_singleton_method(:method_added, &next_subs)
            define_method(name) {|*args, &block|
                print "#{prefix}before call: #{name}\n"
                begin
                    to_decorate.bind(self).call(*args, &block)
                ensure
                    print "#{prefix}after call: #{name}\n"
                end
            }
        }
    end

    log_called "1st decorator: "
    log_called "2nd decorator: "
    def f(*args); [*args, yield] end
end
Y.new.f(:first, :second) { :yield } 

Output:
1st decorator: before call: f
2nd decorator: before call: f
2nd decorator: after call: f
1st decorator: after call: f

Here we use instance_method to get UnboundMethod of our target method. We cannot call it directly like in Python. Instead we have to bind it to some instance of the class before calling. Despite Ruby is dynamic language we can only bind method to the same class or to its subclass. Also notice that most of the code is evaluated in the context of the current class. But the block that is passed to define_method is evaluated in the context of an instance of the class. We use it to define new implementation of the method.

Actually I don’t like actual decorator code is mixed with calls to Ruby API for method defining. Let’s extract the common part for typical decorators into the following helper method:

module Decorators
    def decorate_next_def(&block)
        next_subs = self.method(:method_added)

        define_singleton_method(:method_added) {|name|
            define_singleton_method(:method_added, &next_subs)

            to_decorate = instance_method(name)
            case decorated = block[name, to_decorate]
            when to_decorate
                method_added(name) if next_subs
            when Proc, Method
                define_method(name, &decorated)
            else raise "unsupported decorated value. Should be Proc, Method, or original unbound method"
            end
        }
    end

end

module MyDecorators
    include Decorators
    def log_defined prefix=""
        decorate_next_def {|name, to_decorate|
            print "#{prefix}method defined: #{name}\n"
            to_decorate
        }
    end

    def log_called prefix=""
        decorate_next_def {|name, to_decorate|
            proc {|*args, &block|
                print "#{prefix}before call: #{name}\n"
                begin
                    to_decorate.bind(self)[*args, &block]
                ensure
                    print "#{prefix}after call: #{name}\n"
                end
            }
        }
    end
end

Good. Now we have a tool helping to define decorators. Let’s check how simple it is to define a decorator in Ruby comparing to Python. PEP- 318  – the porposal for decorators for Python defined here. Let’s take the longest decorator example described there and “port” it to ruby. I think the longest and most interesting is “accept” decorator. It performs type checking for function arguments.

module MyDecorators
    def accepts(*types)
        decorate_next_def{|name, f|
            types.count == f.arity or raise
            proc{|*args, &block|
                for a, t in args.zip(types)
                    a.is_a?(t) or raise "arg class #{a.class} does not match #{t}"
                end
                f.bind(self)[*args, &block]
            }
        }
    end
end

class T
    extend MyDecorators

    accepts(Numeric, String)
    def f(n, s)
        p([n, s])
    end
end

T.new.f(1, "s")
T.new.f("1", "s")

Output:
[1, "s"]
snippet4.rb:9:in `block (3 levels) in accepts': arg class String does not match Numeric (RuntimeError)
        from snippet4.rb:8:in `each'
        from snippet4.rb:8:in `block (2 levels) in accepts'
        from snippet4.rb:27:in `<main>'

You see it’s quite similar to original python implementation and has the same number of lines. So you can freely borrow syntatic solutions exploiting decorators from Python (or Groovy/Scala/Java/C#) for you framework/DSL/library implemented in Ruby. And you can consider the decorators as good alternative to explicit blocks for several cases of declarative definition of classes.

P.S. Implementation of define_singleton_method:

class Object
    def self.define_singleton_method(name, &block)
        class_eval {
            extend Module.new {
                define_method(name, &block)
            }
        }
    end
end

P.P.S.
After I published the post I found another one published 4 days earlier about the same topic 🙂