📘 hkob-astro-notion-blog

これまではてなブログにて情報発信をしていましたが、令和5年3月22日より、こちらでの情報発信を始めました。2019年以前の古い記事は過去の Middleman 時代のものなので、情報が古いです。記録のためだけに残しています。

GTDテンプレートのスプリント移行(2)

1. はじめに

📄 GTDテンプレートのスプリント移行(1) にて、これまでの日時ベースの GTD テンプレートをスプリント移行する記事を書きました。それを Notion 座談会で紹介したところ、スプリントの粒度をもっと荒くする形にした方がいいことがわかりました。今回、以下のように変更しようと思います。

  1. 日単位のスプリントを週単位のスプリントへ
  2. プロジェクトを曜日に
  3. 翌週のカレンダータスクを翌週のスプリントへ

前回の確認したポイントを一つ一つ確認しながら修正していきます。

2. データベースを修正

前回の修正では、日付のタスクをスプリントに変更しました。

1️⃣
次のアクション
  • 現在: 今日の日付のタスクをフィルタで表示
  • スプリント: 現在のスプリントを表示

スプリントは日付ごとに更新する予定でしたが、スプリントの単位を1週間にすることにします。

2.1 Tasks データベース

週を一意に判別するために、Tasks データベースに week_id を用意します。カレンダーを月曜始まりに設定しているので、ww ではなく WW で週文字列を作成しています。

formatDate(prop("Due"), "YYYY-WW")

2.2 Sprints データベース

同様に Sprints データベースにも week_id を用意します。具体的なイメージを掴むために、今年度開始からのスプリントを用意してみました。

スプリントについては、以下のルールで作成します。

  • 日付は月曜日から日曜日までの1週間とします。
  • 日付から作成された week_id を使って、Sprint name を決定します。
  • Next や Feature はスプリント移行直後は上記のように「スプリント 番号」という形になります。
  • Next は Notion API によるスクリプトで、Dates を設定します。それによって生成された week_id を使ってさらに Sprint name を設定します。
2.3 Projects データベース

スプリントが1週間になったので、各曜日を Projects に割り当てることにしました。会議や授業は同一曜日に行われるため、曜日をプロジェクトとしてまとめることで縦串としてタスクを結びつけやすくなります。

プロジェクトについては、以下のルールで作成します。

  • カレンダーを月曜始まりにしているので、月曜日からプロジェクトを開始しています。
  • 年度ごとにプロジェクトを切り替えたいので、日付は当該年度の4/1 から 3/31 までとします。
  • 年度が切り替わったら、1. Monday (2023) のようにして、Status を Done に設定します。

3. カレンダータスクの対応

ここまでの変更を受けて、前回検討していたカレンダータスクの対応を Notion API で実現したいと思います。

3️⃣
カレンダータスク
  • 現在: イベントの日付をタスクの日付に設定、直近1週間のものを閲覧用に表示
  • スプリント: イベントの日付をタスクの日付に設定、直近1週間のものを閲覧用に表示、一日一回、明日のタスクを「Next スプリント」に自動設定するスクリプトを設定
  • 備考: 明日のタスクが「Next スプリント」に入っているので、翌日スプリントを終了して次のスプリントに移動すると自動的にその日のタスクがスプリントに現れてきます。

当初はこの予定でしたが、スプリントの単位を週にしたので、以下のような実装に変更します。

  • 来週を示す Next スプリントを取得し、日付が設定されていなければ来週の月曜日から日曜日を範囲に設定 (これによりスプリント終了時に日付設定をしなくてよくなる)。
  • 日付が設定されると week_id フォーミュラが週番号文字列を自動作成する。この文字列とタイトルが一致しなければ、タイトルをこの文字列に設定する。
  • スプリントが設定されていないタスクでかつ、設定された日付が Next スプリントの最終日以前のものを抽出する。
  • これらのタスクに対して以下の作業を実施する。
    • タスク日付から生成された week_id フォーミュラの週番号文字列を取得する
    • この週番号文字列と一致するスプリントをタスクに結びつける
    • また、日付から曜日番号を取得し、それに対応するプロジェクトをタスクに結びつける

スクリプトはこんな感じ。私以外の人にはあまり有用ではないので、特に解説はせず、自分の記録のためだけに残しておきます。

#!/usr/bin/env ruby
# frozen_string_literal: true

require "notion_ruby_mapping"
require "date"

include NotionRubyMapping

class SetSprint
  PROJECT_IDS = [
    "a4752cbf2c3c41348c75325f38b84606", # Sunday
    "57ca442019da4b58a5c077029df713fd", # Monday
    "b6718070baf140fcbecdca7aafc65c6f", # Tuesday
    "729e599f79c54d76a3bb26994518d8a4", # Wednesday
    "7eaed372da8445fea2d9896f47a022da", # Thursday
    "8d1d0cd4d59c45fbacd8d1f54b03b25a", # Friday
    "96c50c999d2a46b1a7a7fe03bb9a1886", # Saturday
  ]
  TASK_DATABASE_ID = "1fd72fc2a18247e2a9d347b67e5f9cf0"
  SPRINT_DATABASE_ID = "d8a81b250f7348b89639b63970d5871e"

  def initialize
    @sprint_db = Database.find SPRINT_DATABASE_ID
    @task_db = Database.find TASK_DATABASE_ID
    @sprint_hash = {}
  end

  def get_db_sprint(status: nil, title: nil)
    if status
      sp = @sprint_db.properties["Sprint status"]
      @sprint_db.query_database(sp.filter_equals(status)).first
    elsif title
      tp = @sprint_db.properties["Sprint name"]
      @sprint_db.query_database(tp.filter_equals(title)).first
    end
  end

  def get_sprint(status: nil, title: nil)
    if status
      sprint = get_db_sprint(status: status)
      @sprint_hash[sprint.title] = sprint
      sprint
    elsif title
      @sprint_hash[title] ||= get_db_sprint(title: title)
    end
  end

  def update_next_sprint
    nsp = get_sprint(status: "Next")
    dp = nsp.properties["Dates"]
    start_date = dp.start_date
    if start_date.nil?
      wday = today.wday
      start_date = today + (7 - wday) + 1
      end_date = start_date + 6
      dp.start_date = start_date
      dp.end_date = end_date
      nsp.save
    end
    week_id = nsp.properties["week_id"].formula["string"]

    if nsp.title != week_id
      nsp.properties["Sprint name"].text_objects[0].text = week_id
      nsp.save
    end
    @task_end_date = dp.end_date
  end

  def get_unfinished_tasks
    dp = @task_db.properties["Due"]
    spp = @task_db.properties["Sprint"]
    query = dp.filter_on_or_before(@task_end_date)
              .and(spp.filter_is_empty)
    @task_db.query_database(query)
  end

  def project_id(week)
    PROJECT_IDS[week]
  end
end

NotionRubyMapping.configure { |c| c.token = ENV["NOTION_API_KEY"] }
ss = SetSprint.new
ss.update_next_sprint
ss.get_unfinished_tasks.each do |task|
  fp, sp, pp, dp = task.properties.values_at "week_id", "Sprint", "Project", "Due"
  week_id = fp.formula["string"]
  sprint = ss.get_sprint(title: week_id)
  sp.add_relation sprint.id
  project_id = ss.project_id Date.parse(dp.start_date).wday
  pp.add_relation project_id
  task.save
end

4. これまでのタスクの移動

これまでのタスクデータベースに存在していたプロパティのうち、新しい Tasks データベースでも使いたいものを事前に作成しておきました。名前が一致していれば、データベースが異なってもプロパティの中身は自動的に変換してくれます。現状のプロパティはこんな感じです。

実際には11件のプロパティは作業用のものであり、通常はこの程度の表示です。

これらのプロパティを設定した上で、これまでの hkob’s Task から今年度分のタスクを移動しました。全てのスプリントは未設定となっています。この状態で上記のスクリプトを実行しました。一件ずつ処理するので時間はかかりましたが、以下のように各スプリントおよび各プロジェクトに自動的にリレーション設定されました。来週のスプリントも日付が設定されており、Sprint name も正しく設定されています。

このスクリプトを cron で定期的に自動実行するようにすることで、カレンダータスクが自動的にスプリントとプロジェクトに連携する形になりました。

5. これまでのツールの修正

これまでさまざまな API ツールを作成してきましたが、全てこれまでのタスクデータベースに連携されています。以下のツールを全て新しいスプリントベースのタスクデータベースに連携し直す必要があります。基本的にはデータベース ID と「日付」というプロパティ名を修正するだけですみそうです。ここについてはブログにするほどではないので、ここでは省略します。対応予定のものは以下のものです。

  • 声でタスク登録ショートカット
  • Start Stop task ショートカット
  • Google Calender → Notion 連携 GAS
  • Notion → Google calendar ショートカット
  • Text to Notion ショートカット
  • Notion tools Alfred workflows
  • Notion Time Recorder コマンドラインツール

我ながら時と場合に合わせていろいろ使い分けているな。

6. おわりに

この作業にあたり、unique_id プロパティに対応するために、NotionRubyMapping も 0.8.0 にアップデートしました。せっかくなので、これまで作ったツールもきれいに作り直したい気分です。もしかしたらそれらを別途記事にするかもしれません。とりあえず今日はこのくらいで。