Aggregating Plans

Posted by yrashk

As you may know, I blog on GTD-related topics from time to time

I was trying to use various planning tools to organize my work—Basecamp, iCal.app, Highrise, Google Calendar, DEVONthink Pro Office, and plenty of others. Each tool has its benefits and downsides but no one is a silver bullet (yea, I know, there is no silver bullet). Using few tools is a workaround that may work for someone, but not for me. I just losing focus, forgetting about one or another tool, getting tired when I should not be, etc.

What if someone will try to not to create a new shiny planning tool, but rather an aggregator for existing? Some kind of tool, that will be able to sync multiple icals, feeds and propriertary formats, and what is also important, being able to post events to the respective sources. Getting all this stuff in one place will make my planning much more perfect and will save me time. I’d personally would love to pay for it.

Basically, it could be even a desktop (OSX ;) app. I’d like to not to stop planning and going through the plan while I’m not online. Just some simple synchronization with servers when internet is back available and voila! I’m happy.

P.S. I’ve opened Xcode after writing this post. Let’s see what I can do to help myself.

MissingBDD

Posted by yrashk

I’ve created a small umbrella project for BDD implementations I’m playing with (Common Lisp and Erlang by now).

Erlang BDD

Posted by yrashk

I’m definitely a BDD maniac. Recently I’ve created a quick-n-dirty Common Lisp BDD primitives and today I’ve hacked BDD primitives for Erlang. Just like Lisp version, it still lacks lots of BDD stuff, but only expectations. Here you are bdd.erl:

 
-module(bdd).

%%
%% Exported Functions
%%
-export([should/5,should_not/5,equal/2,be/2,raise/2,match/2,run/1]).

%%
%% Expectations
%%
should(Matcher,Args,Expr,File,Line) ->
    case apply(?MODULE,Matcher,[Args,Expr]) of
        false -> exit({expectation_not_met,{File,Line,Expr,should,Matcher,Args}});
        _ -> ok
    end.    

should_not(Matcher,Args,Expr,File,Line) ->
    case apply(?MODULE,Matcher,[Args,Expr]) of
        true -> exit({expectation_not_met,{File,Line,Expr,should_not,Matcher,Args}});
        _ -> ok
    end.    

%%
%% Matchers
%%

equal(Args,Expr) ->
  case Expr of
      Args -> true;
      _ -> false
  end.          

be([H|T],Expr) ->
  be(H,Expr,T);

be(Predicate, Expr) ->
  be(Predicate,Expr, []).  

be(Predicate,Expr,Args) ->
  Pred = list_to_atom("is_" ++ atom_to_list(Predicate)),
  case (catch apply(Pred,[Expr] ++ Args)) of
      {'EXIT',_} -> 
          % is it a bif?
          D = (catch apply(erlang,Pred,[Expr] ++ Args)),
          case (catch apply(erlang,Pred,[Expr] ++ Args)) of
              {'EXIT',_} ->
                  % last idea
                  apply(erlang,Predicate,[Expr] ++ Args);
              Result -> Result
          end;             
      Result -> Result
  end.    

raise(Args, Expr) ->
   case Expr of
        {'EXIT',{Args,_}} -> true;
        {'EXIT',Args} -> true;          
        _ -> false
   end.           

match(Args, Expr) ->
   not raise({badmatch,Expr},(catch Args=Expr)).        

run([M|Modules]) ->
    run(M) ++ run(Modules);

run([]) ->
    [];

run(M) ->
    Context = get_from_module(attributes,M,context),
    io:format("~s~n",[Context]),
    Fun = fun(Spec) ->
        case Spec of
            module_info -> skipped; 
            setup -> skipped;
            teardown -> skipped;
            context_setup -> skipped;
            context_teardown -> skipped;
            _ ->
            (catch M:setup()),
            io:format(" - ~s",[atom_to_list(Spec)]),
            case (catch apply(M,Spec,[])) of
                {'EXIT',{expectation_not_met,Value}} -> io:format(" (FAILED)~n",[]), {Spec,failed,Value};
                {'EXIT',Value} -> io:format(" (ERROR)~n",[]), {Spec,error,Value};
                _ -> (catch M:teardown()), io:format("~n",[]),{Spec,ok}
            end    
         end
    end,
    (catch M:context_setup()),
    R =lists:filter(fun(TestResult) -> not (TestResult =:= skipped) end, lists:map(fun(Item) -> hd(tuple_to_list(Item)) end,lists:keymap(Fun,1,M:module_info(exports)))),
    (catch M:context_teardown()),
    R.

get_from_module(Kind,Module,Name) ->
    {value, {Name, Val}} = lists:keysearch(Name,1,Module:module_info(Kind)),
    Val.
 

and bdd.hrl:

 
-define(bdd(Expr,Expectation,Matcher,Args),
        apply(bdd,Expectation,[Matcher,Args,(catch Expr),?FILE,?LINE])).
 

Now you can check various expectations:

 
test() ->
  ?bdd(1,should,equal,1),
  ?bdd(1,should_not,equal,2),
  ?bdd(1,should,be,integer),
  ?bdd(1,should_not,be,list),
  ?bdd(1,should,be,['>',0]),
  ?bdd(1,should,be,['>=',1]),
  ?bdd(1=2,should,raise,{badmatch,2}),
  ?bdd(1=1,should_not,raise,{badmatch,2}),
  ?bdd({ok,1+2},should,match,{ok,3}),
  ?bdd({error,-1},should_not,match,{ok,3}),
  ?bdd(#state{},should,be,[record,state]).
 

and create contexts with specifications as modules:

 
-module(empty_list_spec).
-context("Empty list").
%%
%% Include files
%%

-include("bdd.hrl").

%%
%% Exported Functions
%%
-export([setup/0,'should have zero length'/0]).

setup() ->
    put(empty_list,[]).

%%
%% Specifications
%%

'should have zero length'() ->
    ?bdd(length(get(empty_list)),should,equal,0).

%%
%% Local Functions
%%

 

Now just run it:

> bdd:run(empty_list_spec)
% or
> bdd:run([empty_list_spec])
Empty list
 - should have zero length
[{'should have zero length',ok}]

Just an Idea for Erlang

Posted by yrashk

I was using Erlang from time to time from 2000 or 2001. I’ve even done some commerical trading-related system in it. It’s definitely a good language for certain domains, and it has bright past and may be even brighter future. I was experimenting with some ideas in Erlang today, after long period of not using it and I should say that fairly speaking Erlang is far away from being a friendly language in terms of syntax.

What if Erlang could be considered a kind of “assembly” language for high-performance and distributed programming? What if we can use Lisp macro or Ruby metaprogramming capabilities to code generate Erlang? Taking in account the fact that Erlang code could be changed without a stop, why not generating source code on the fly and passing it to Erlang VM?

Ok, just as a nighty idea.

Another Simple Action Protocol

Posted by yrashk

“We (developers, people) have need in quite various planning and action tracking tools. No one tool could fit everyone’s needs. The real problem, as I perceive it, is that there are no widely accepted (as RSS or HTML or whatever) format for plan and action tracking. Given such representation, we can develop various tools from little unix-type to behemots (if someone really needs them nowdays) that allow to do exactly what we need from them now. But…. No accepted model – no solutions what simply plug in. Would be glad to know that I’m wrong.”

— Andrey Khavryuchenko, in the comments to an article about nagging issue tracking

That’s a good idea. No, really. It is a very bright idea. We all have different mindsets, visions and needs. We need different ways of working with planning software.

But we have one in common: we need to plan and to take an action, avoiding procrastination, missed deadlines or forgotten tasks. We all need not to waste our time.

I’ve decided to think more about it. What if I will try to analyze requirements to such a format (protocol)? Let me try.

Planned Action

First major part of such protocol is planning actions. What properties are essential for a planned action?

  • description and payload
  • tag information (like arbitrary tags, context, aspect, etc.)
  • participants
  • when action should be taken? (i.e. when work on action should be started)
  • when is a deadline for this action?

Let me go through these items in details:

Description and Payload

Each action should have a description that makes it meaningful for a human. It should answer to a question “What should be done?”. It could be either short few words text (like “Have a lunch”) or more or less complete and detailed action description. I imagine description is a variable length text.

What is a payload? Payload is an arbitrary number of binary files referenced. It could be WordOpenOffice documents, arbitrary URLs, text notes. In my understanding, payload should be a set of URLs, each having textual description of each one.

Tag Information

Each action should be able to be tagged with either arbitrary tags (like “interesting”,”exciting”) or special kind of tags (like “context:home”, “context:office”, “aspect:book keeping”, etc.). In order to make this system as flexible as it is possible, I’d suggest that tag value could also be a URL. What for? Well, it could be a proper way of specificating such things like context. Each person’s context is different, even it has the same name. “home” for John is not equal to “home” for Yurii. So if each one will refer own contexts: http://john.name/asap/context/home, http://rashkovskii.com/asap/context/home. Also these URLs could lead to some data stored on their servers, for example, textual context definition.

Participants

Participant is a set of URLs, each of which refers to a participant of an action. Each URL has an attached textual description, which may be used for naming participants or their roles.

When Action Should be Taken?

It is one of the most important properties of an action. It describes on which conditions action executed should be started. I envision following ways of describing it:

  • Datetime with an optional order of magnitude (minutes, hours, days, weeks, months, years). I.E. You could specify something very specific like “Jan 1, 2008 11:30AM” or you can say something like “Jan 1, 2008 first 12 hours”, “Jan 1, 2008 anytime this day”, “Jan 1, 2008 to Jan 4, 2008”, “Jan 1, 2008 or any day this week”, “Jan 1, 2008 or any day this month”, “Jan 2, 2008 or any day this year”. Of course, this way should be specificated quite precisely. I see no problem with it, but it just needs to be detailed and well-thought.
  • Consequent execution (dependent action). Action could be dependent on a number of another actions. Once that actions are completed, you can start on this action.
  • Someday. No specific date, no specific condition to start execution of this action.
  • Never. Action that will be never planned for an execution.

When is a Deadline for this Action?

This property describes when this action should be completed. I envision following options:

  • Datetime with an optional order of magnitude (minutes, hours, days, weeks, months, years). I.E. You could specify something very specific like “Jan 1, 2008 11:30AM” or you can say something like “Jan 1, 2008 first 12 hours”, “Jan 1, 2008 anytime this day”, “Jan 1, 2008 to Jan 4, 2008”, “Jan 1, 2008 or any day this week”, “Jan 1, 2008 or any day this month”, “Jan 2, 2008 or any day this year”. Of course, this way should be specificated quite precisely. I see no problem with it, but it just needs to be detailed and well-thought.
  • Relative datetime, with an optional order of magnitude.
  • Someday. No specific date for a deadline
  • Never. It is planned that action will be never done.

Take Action

Which Action?

In order to take action, we need first to be aware of its existence. We need to have a protocol or format that will deliver a schedule or a list of actions that require execution. This format should be able to describe events that take an arbitrary length in calendar (like “Sep 1, 2007 7:00AM”, “Sep 1, 2007 7AM-9AM”, “Sep 1, 2007”, “Sep 1-7, 2007” or “September 2007” or a whole calendar).

Action should occupy Calendar form its first day (“when action should be taken?”) till its deadline. If action has no specific date of start (like consequent, dependent action), it should be calculated indirectly (in case of dependent action, it should be a date right after latest required action deadline).

Take it!

Protocol should provide a capability to tell that action is really has been taken and is in progress. It should store exact datetime of when it was taken.

Release

Release is an opposite function to “Take it!”. It tells that action focusing has been stopped. It should store exact datetime of when it was happened. It will allow to track time spent on an action.

Also this function should have a “completes” boolean attribute. If true, this means that action is actually completed and needs no further attention (should be reflected in a respective action).


I realize that currently this draft is very raw. It could be much better if I will return and improve it. It could be better if you will propose how to improve it.

I’m publishing this to review it once (I said once? much more!) again, to have some feedback and then I will move further to analyzing which existent technology solutions could be used to accomplish this protocol or whether we need to have some new simplistic format/protocol; or both. I have some ideas, but I want them to be polished.

I will be really glad to hear if something already exists (because this means that I will be happy with my planning and taking action very soon). I will be very glad if I will get some feedback from readers.

I’m looking forward to have a good technology stack for planning and taking actions.

I’m also interested to hear whether all this stuff I wrote above is a bullshit :)

Common Lisp respond-to?

Posted by yrashk

Few days ago I’ve hacked a simplistic BDD for Common Lisp. I’m still having fun improving it. Here you are an improved respond-to? that supports generics much better.

 
  (defun respond-to? (o method &rest args)
  (restart-case
      (handler-bind ((undefined-function #'(lambda (c)
                         (declare (ignore c))
                         (invoke-restart 'no)))
             (simple-error #'(lambda (c)
                       (declare (ignore c))
                       (invoke-restart 'no))))
    (let ((sf (symbol-function method))
          (cpl (sb-pcl::class-precedence-list (class-of o))))
      (typecase sf
        (standard-generic-function
         (find t 
           (mapcar #'(lambda (klass)
                   (not (null
                     (find-method sf '() 
                          (cons klass
                            (mapcar #'(lambda (c) (declare (ignore c)) t) args)) nil))))
               cpl)))
        (function t))))
    (no (&optional v)
      nil)))
 

Though for non-generic functions there seems to be no way to check if actually object “responds” to function without actually evaluating it.

Anyway, it’s quite funny!

Common Lisp Behavior Driven Development

Posted by yrashk

Yesterday and today I’ve spent few hours playing with an idea of BDD for Common Lisp. What for? Well, lets say “just for fun”. I’ve developed quick-and-dirty implementation of few bits of BDD, in the way similar to RSpec

Here you are:

 
;; Utilities
(defmethod obj->string ((s string))
  s)

(defmethod obj->string ((s symbol))
  (string s))

(defun concat-symbol (&rest args)
  (intern (apply #'concatenate 'string 
         (mapcar #'string-upcase (mapcar #'obj->string args)))))

(defun respond-to? (o method &rest args)
  (restart-case
      (handler-bind ((undefined-function #'(lambda (c)
                         (declare (ignore c))
                         (invoke-restart 'no)))
             (simple-error #'(lambda (c)
                       (declare (ignore c))
                       (invoke-restart 'no))))
    (symbol-function method)
    t)
    (no (&optional v)
      nil)))

;; Conditions

(define-condition expectation-not-met ()
  ())

;; Expectations
(defclass expectation ()
  ((expr :initarg :expr :reader expression-of)
   (args :initarg :args :reader args-of)))

(defclass should (expectation)
  ())

(defgeneric fulfills? (expectation))

(defmethod fulfills? ((e should))
  (flet ((match (matcher-class args expr)
       (restart-case
           (handler-bind ((simple-error #'(lambda (c)
                        (declare (ignore c))
                        (invoke-restart 'fun))))
         (matches? (make-instance matcher-class :args args) expr))
         (fun (&optional v)
           (apply matcher-class (append (list (eval expr)) args))))))
    (with-slots (args expr) e
      (if (equal (car args) 'not)
      (not (match (cadr args) (cddr args) expr))
      (match (car args) (cdr args) expr)))))

;; Matchers

(defclass matcher ()
  ((args :initarg :args :reader args-of)))

(defclass be (matcher)
  ())

(defmethod initialize-instance :after ((matcher be) &rest initargs)
  (declare (ignore initargs))
  (with-slots (args) matcher
    (when (equal (car args) 'a)
      (pop args))))

(defgeneric matches? (matcher expr))

(defmethod matches? ((matcher be) expr)
  (with-slots (args) matcher
    (let* ((arguments (cdr args))
       (message-forms (mapcar #'(lambda (suffix)
                      (concat-symbol (car args) suffix)) '("" "p" "-p" "?"))))
      (when (equal (car arguments) 'of)
    (pop arguments)) ;; am I crazy?
      (dolist (form message-forms)
    (when (respond-to? expr form arguments)
      (return (eval `(,form ,expr ,@arguments))))))))

(defclass raise (matcher)
  ())

(defmethod matches? ((matcher raise) expr)
  (with-slots (args) matcher
    (restart-case
    (handler-bind ((t #'(lambda (c)
                  (declare (ignore c))
                  (if (equal (class-of c) (find-class (car args)))
                      (invoke-restart 'raises)
                      (invoke-restart 'donot)))))
      (eval `(progn
           (eval ,expr)))
      nil)
      (raises (&optional v) t)
      (donot (&optional v) nil))))

;; 
(defmacro => (form &rest specification)
  (let ((expectation-class (car specification))
    (args (cdr specification)))
    `(let* ((result ',form)
        (expectation (make-instance ',expectation-class
                      :expr result
                      :args ',args)))
       (unless (fulfills? expectation)
     (error (make-instance 'expectation-not-met)))
       result)))

;; Grouping
(defmacro define-with-spec-grouping (name)
  (let ((with-grouping (concat-symbol "with-" name ))
    (spec-groupings (concat-symbol "*spec-" name "s*"))
    (spec-grouping (concat-symbol "*spec-" name "*")))
    `(defmacro ,with-grouping (grouping-name &body body)
       `(progn
      (unless (and (boundp ',',spec-groupings) (listp ,',spec-groupings))
        (defvar ,',spec-groupings nil))
      (let* ((,',spec-groupings (cons ,grouping-name ,',spec-groupings))
         (,',spec-grouping (car ,',spec-groupings)))
        ,@body)))))

(define-with-spec-grouping context)
(define-with-spec-grouping aspect)

(defmacro specify (name &body body)
  `(let ((*spec-specification* ,name))
     ,@body))

It allows me to write constructs like:

 
 CL-USER> (=> (1+ 1) should = 2)
 2
 CL-USER> (=> (1+ 1) should not be zero)
 2
 CL-USER> (=> 0 should not be zero)
 ; Exception raised
 CL-USER> (=> (+ 2 2) should = 5)
 ; Exception raised
 CL-USER> (=> 1 should be a member of '(1 2 3))
 1
 CL-USER> (=> 0 should be a member of '(1 2 3))
 ; Exception raised
 CL-USER> (=> (=> 1 should = 0) should raise expectation-not-met)
 (=> 1 SHOULD = 0)
 CL-USER> (=> (=> 1 should = 1) should not raise expectation-not-met)
 (=> 1 SHOULD = 1) 
 CL-USER> (=> (=> 1 should = 1) should raise expectation-not-met)
 ; Exception raised

and play with contexts, aspects and specifications.

It was funny.

RSpec Simple Specifications

Posted by yrashk

Copied from Railsware#blog

What I also like in RSpec is that it constructs a name for simplistics specifications, like:

 
 context "Random number in 0..100 range" do 

  setup do
    @random_number = rand(100)
  end

  specify do
    @random_number.should < 100
  end

  specify do
    @random_number.should >= 0
  end

  specify do
    @random_number.should_not be_nil
  end

end

Random number in 0..100 range
- should < 100
- should >= 0
- should not be nil

Update:

I’ve played around matchers to make generated names work properly for be_ matchers (like be_between): http://blog.railsware.com/2007/3/2/rspec-generated-spec-name-for-be (and it’s accepted in rspec trunk now)