GTD 入门笔记

虽然时间线拉的比较长,《Getting things done》 总算是看完了。

看完 GTD 之后对 GTD 理论有了更进一步的理解,通过通读,更加清晰了 GTD 四步法:收集清理组织回顾,也明确的四步法与执行的关系,并顺便根据自己的理解将 GTD 这一套理论简化为 4 个原则,以方便执行和安利。

四步法与执行

曾经在知乎看到有人反对在不了解时间管理的情况下直接实践 GTD,而更是推荐番茄工作法之类简单的理论。在看完 GTD 这本书之后对这个观点有些认可,GTD 的执行需要形成一大堆习惯,而作者更是在书中坦言,将 GTD 完全接受并融入自己生活中,可能需要大约两年的摸索。 因此,在正式实践 GTD 之前请确定自己有改变生活的决心与坚持的勇气。

收集

GTD 的启动是从收集开始的,一切事情皆在被收集的清单内(没看错,是一切事物)。书中认为第一次收集一般花费 3-6 个小时,需要将一切事物,桌子上的、抽屉里的、角落里的,所有的东西都放在收集篮,而是只是单纯的放进收集篮子,并不做任何处理,处理这个工作放在后面。

而收集这个动作自 GTD 实践开始,就不会停止,而且实时进行,任何的灵光一闪,任何的想到的事情,都需要收集起来。

我恰好是在工作最混乱的时候启用 GTD 的(17 年 9 月左右),当时并没有完全理解 GTD,而是比着葫芦画瓢,将所有想做的事情扔到收件箱里,并每次做事情的时候从收件箱找找能做的事情。

这是一种非常糟糕的实践,但是却有用,因为我知道我所有要做的事情,开会确定的效果,吃饭时想到的新实现,洗澡时想到的潜在 bug,全在收件箱里,我不怕遗漏,我信任这个系统,因此不会像无头苍蝇不知出路与莫名烦躁。

收集的意义就在于把所有突然想到的事情记录下来,让这件事情在变成事故前完成,这样就可以大量减少救火的情况,而且一个良好的收集系统会让人产生安全感,我可以依赖这个系统,不怕自己遗忘,就像一个外脑。

清理

在收集的时候避免任何进一步思考和执行,而是把思考的阶段放在清理阶段。

清理阶段非常简单,就是把收集阶段的东西进行清理与梳理,当处理一件事情时,可以采取以下的选择:

  1. 该事情没啥意义:扔到垃圾箱
  2. 该事情两分钟内就能做完:立马去做
  3. 该事情两分钟内做不完:推迟、委托他人

要明白为什么这样选择首先要明白两点:

  1. 清理是什么
  2. 两分钟原则

清理是什么?收件箱其实就是一个未处理清单,一堆从没有思考过是什么,怎么做,目标是什么的三无任务清单,清理就是将这堆任务想清楚,要不要做,要做成什么样子,要怎么做,并把收件箱清空。

因此,对于没有意义的事情,应该立即丢弃,而把有用的保留下来。不能让 GTD 系统中存在任何垃圾,毕竟垃圾越多意味着越低效。

两分钟原则是清理阶段的执行方式,如果一件事两分钟就可以解决,那就不要让这件事流入后面的处理阶段,因为一件事在 GTD 中经过的阶段越长,这件事的执行效率越低,一般一件事从收集后,经过清理,组织,回顾需要 3 分钟,而这件事本身不过两分钟就可以完成,那么把这件事在清理阶段就完成的,不要再拖延了。

我曾经疑惑为什么超过两分钟的事情就要 delay 呢?因为 清理 本身就是一件事情,如果在清理的时候就执行非常耗时的任务,就会中断清理,从而进入了不同从收件箱拿任务执行的恶性循环,从而让收件箱里的垃圾越来越多,最后放弃 GTD。因此我们要确保清理这件事情本身能成功完成,而耗时任务以后再说,哪怕是等清理完之后再说。

清理是对事情初步思考的环节,将收件箱里的垃圾丢掉,简单的事情完成,复杂的事情简单思考,那么剩下的事情,就是那些需要好好思考的任务了,而这些任务可以流入下一个环节。

组织

无论是小到写篇关于 GTD 的博客,还是大到计划买一套房,无论是今天下午就要着手做的事情,还是未来两年内完成的事情,只要这件事又完成的意义,就会流入组织环节。

虽然书中使用了 “组织” 一词,不过我认为 “梳理” 更适合。因为组织是在做两件事情:

  1. 梳理清单,分门别类
  2. 梳理任务,想清楚怎么执行

如果这件事近期不需要执行,而且你也不知道什么时候会执行,比如要看到书单,要学一门外语,那么可以把这件事放到 “也许、将来” 清单。如果这些事情需要在家完成,那么可以将这件事归到 “在家” 清单。将事情分门别类,可以方便下一步的执行,比如在家的时候,可以看一下 “在家” 这个清单,而书荒的时候,可以去翻翻看 “也许、将来” 里的书单。

清单的分类一般按照地点或客观条件,比如 “公司”、“在家”、“杂货店”、“需要电脑”,也可能会依赖某个人:“老板”,“女朋友”。这些都可以成为清单的梳理规则,考虑到清单是执行和回顾的依据,可以怎么有利于执行和回顾怎么分类。

除了梳理清单,还有把 “任务” 变为 “项目”,任务指的是我们在收件箱收集的事项,比如:“在卧室中安装空气净化器”。而这种任务完全没有可执行力,因此我们需要 “梳理任务”,想清楚下一步怎么做,比如:“调研有哪些空气净化器性价比高”。

回顾

如果一件事被收集到了 GTD 系统,而这个体系并没有经常更新,从而出现了遗忘的事项,那么你就不会再信任这个系统,从而又一次放弃 GTD。

因此,当一件件事被收集清理组织之后,会产生一个又一个的清单,如果清单没有被更新,这就和我们把要做的随手一记一样,并没有实质改观。因此我们需要定期回顾清单,比如曾经记下:“学习日语”,那么在回顾的时候你会又想起这件事情,说不定这次你就会考虑下怎么去做。

而有的项目因为没有更新,可能已经没有了执行的必要,或者有新的步骤需要添加,这时候在回顾环节可以更新这些项目。

回顾是更新整个系统的重要一环,也是防止整个系统不会落后于现实的保险。而作者建议在最后一个工作日拿出下班前的一到两个小时来回顾,以防止遗忘当周没有完成的事项。

执行

这里的执行分两种,一个是 GTD 整个流程的执行和 GTD 中托管的任务的执行。

GTD 四步走包括:收集,清理,组织,回顾。其中收集是无时无刻执行的,只要想起来就可以向收件箱中添加一项,因为有手机等移动设备,其实只要养成习惯,基本就没有耗时的感觉。而回顾是定期执行的,比如周五下班前,那么我们只需要设定一个闹钟或者提醒事项,提前预留出时间,或者稍微加一下班,也能让这个环节执行完。而 GTD 比较麻烦就是清理和组织。

清理和组织环节是比较消耗时间和脑力的,我们要把事情想清楚并归类,甚至还要想清楚下一步怎么执行,作者说他一般是在出差路上完成的,对于长期出差的商务人士,当然是个不错的选择。而对于打工仔,我一般是在饭间完成的,我更建议能经常拿出时间来清理和组织,尤其是组织,因为组织环节会梳理好下一步清单,而再次审视要执行的下一步清单,往往会产生改进,并获得更优的下一步行动列表。不过要注意的是,这两个环节需要脑力,在不清醒的时候并不适合这样的行动。

在执行任务上,人和计算机最大的不同点是人非常不擅长进程(正在执行的事情)切换,如果有新的事情插进来,往往会花很多事情来回忆(已经完成了啥)和思考(现在要做啥),就和每个进程都有一个上下文一样,任何任务也同样需要整个上下文,而 GTD 的下一步列表其实就是充当上下文的记录的作用。

因此,对于事情的事情就是在下一步清单中找到可以做的事情,并完成它,在执行的时候不应该产生 “我该怎么做”,“我已经做了啥” 这样的疑问,如果有的话可能还需要反省 GTD 的实践。

任务的时间点

在 GTD 中好像没有提到 “每日任务” 这样带有时间点的任务,因为在 GTD 中不建议,或者说反对设定每日任务,因为生活充满变数,人们经常完不成每日任务,而在多次把 “今日完成” 移动到 “明日完成” 之后,人们就会对这个日常管理系统失望并不再信任。

GTD 中认为一件事情分为两种:

  1. ASAP(As Soon As Possible,越快越好)的任务
  2. 有时间点的任务

第一类任务比如:“写一篇博客”,第二类比如:“明天 9 点预约了牙医”。

而 GTD 的下一步清单维护的其实只是第一种,而第二种才应该放在日程表中,这样就可以在指定日期提醒自己这件事在今天必须要做。而且日程表中的任务是比下一步清单中的任务要高的。

GTD 原则

GTD 是一套复杂的实践,我在尝试把它简化(方便执行和安利给别人),总结为:收集习惯下一步清单关注结果定期回顾四个原则。

收集习惯

收集事无巨细,应该养成一种习惯,任何灵光一闪,或者将要提醒自己的事情,都要被收集。

下一步清单

收集的事情要被清理和整理,我们要明确每件事的下一步是什么,并总结出下一步清单,而剩下的就是无脑执行下一步清单里的内容。

关注结果

所有的事情都是可量化的,我们要想清楚这件事我们的目标是什么,想要达成的结果是什么,只有下一步可量化,我们才有执行和推进事情的依据。

定期回顾

定期回顾是保证 GTD 系统是最新有效的保险,定期的回顾非常重要,更新过去的想法,添加新的想法。

总结

作者在最后提到,很多人认为如此繁琐的步骤是浪费时间,只是让行动的效率变得更低下。那是因为还没完全依赖这个系统,毕竟如果考虑到全盘依赖大脑时,每次切换事情都要思考:“我之前做了啥”,“我现在应该做啥”,“我要做到什么程度” 所消耗的时间其实是更多的。

GTD 的一些思想在软件行业好像已经有了广泛应用,这一套收集、清理、组织、回顾,如果我们把 “task” 这个词换为 “user story”,把清单换成泳道是不是仿佛很熟悉。

无论是个人,还是团队,时间管理其实并不能获得更多时间,相反会消耗时间在管理本身上,但这道流程的存在,能防止事情失控,一切尽在掌控之中。


附图一张,在星巴克写了一下午,写完才发现被冷风吹的手脚冰凉。

2018/04/30 19:07 下午 posted in  坏笔记不如好记性

Ansible Config 和 Playbook

Config

Ansible 的配置一般不需要更改,如果需要定制,自定义配置也很简单,在 Ansible 中,寻找配置按照如下顺序:

  • ANSIBLE_CONFIG (一个环境变量)
  • ansible.cfg (位于当前目录中)
  • .ansible.cfg (位于家目录中)
  • /etc/ansible/ansible.cfg

因此只需要按照文档自定义配置即可:http://ansible-tran.readthedocs.io/en/latest/docs/intro_configuration.html

Playbook

为了方便保存执行的操作,Ansible 使用了 Playbook 剧本。剧本使用 yml 格式,来避免成为了一种新语言或者脚本。

Playbook 是有 play 组成的,每个 play 包含了 host,user,tasks。

比如一个 playbook:

---
- hosts: webservers
  vars:
    http_port: 80
    max_clients: 200
  remote_user: root
  tasks:
  - name: ensure apache is at the latest version
    yum: pkg=httpd state=latest
  - name: write the apache config file
    template: src=/srv/httpd.j2 dest=/etc/httpd.conf
    notify:
    - restart apache
  - name: ensure apache is running
    service: name=httpd state=started
  handlers:
    - name: restart apache
      service: name=httpd state=restarted

host 便是指定的 hosts 文件中的主机,可以通过 remote_user 指定在远程使用的用户,也可以用 sudo 为远程操作添加 root 权限。

Task

作为远程部署工具,task 是整个 playbook 的重点。每个 task 都会在指定的所有远程主机执行,如果有执行失败的主机,将会被跳过。

每个 task 目标在于执行一个幂等(moudle)的操作,因此即使是多次执行也会很安全。一个 task 类似于下面的格式:

tasks:
  - name: make sure apache is running
    service: name=httpd state=running

一个 task 包含了名称,model,以及参数。更多的 task 写法见: http://ansible-tran.readthedocs.io/en/latest/docs/playbooks_intro.html

2017/07/26 13:43 下午 posted in  坏笔记不如好记性

Ansible 初体验

记得刚来上海的时候,叶神给了我一本奶牛书:《奔跑吧, Ansible》。时隔一年,我居然有了写 Ansible 脚本的需求。

安装

pip install ansible

配置主机

在安装完 ansible 之后,需要在 /etc 下创建一个 ansible 文件夹,并在里面添加一个 hosts 文件,因为 ansible 会默认在 /etc/ansible/hosts 中寻找主机的配置。

因为 macOS 下 etc 文件夹不能编辑或者因为其他原因,可以通过 -i 指定 hosts 的位置。

可以创建一个 hosts 文件:

[local]
10.8.0.164

[blog]
150.95.155.202 ansible_user=user ansible_port=2222

[] 内为 target, 可以通过 targets 来对主机进行分组管理。

每一行包含一个 ip 或者域名,host 好支持一些表达式。

在每个 ip 后面可以加一些特殊的参数,比如 SSH 用户名,SSH 端口,密钥等。

详细配置可见: http://docs.ansible.com/ansible/latest/intro_inventory.html

配置完 hosts 文件之后便可以进行 ping:

$ ansible -i hosts all -m ping
10.8.0.164 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
150.95.155.202 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

也可以对某一组的主机进行 ping:

$ ansible -i hosts blog -m ping
150.95.155.202 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

执行

当能够连接上主机之后,便能对某个或者某组主机执行命令了:

$ ansible -i hosts local -m service -a "name=docker state=restarted" --become --ask-sudo-pass
SUDO password:
10.8.0.164 | SUCCESS => {
    "changed": true,
    "name": "docker",
    "state": "started"
}

其中 -m 是选择使用的模块, ansible 有大量的模块可以使用, 不同的模块负责管理不同的功能,对 ansible 的学习也就是对这些模块熟悉的过程。

--become 是作为某个用户来执行,如果添加整个参数,或默认尝试使用 root, 如果需要密码的话,还需要输入密码相关的参数, 权限相关的参数见:

  Privilege Escalation Options:
    control how and which user you become as on target hosts

    -s, --sudo          run operations with sudo (nopasswd) (deprecated, use
                        become)
    -U SUDO_USER, --sudo-user=SUDO_USER
                        desired sudo user (default=root) (deprecated, use
                        become)
    -S, --su            run operations with su (deprecated, use become)
    -R SU_USER, --su-user=SU_USER
                        run operations with su as this user (default=root)
                        (deprecated, use become)
    -b, --become        run operations with become (does not imply password
                        prompting)
    --become-method=BECOME_METHOD
                        privilege escalation method to use (default=sudo),
                        valid choices: [ sudo | su | pbrun | pfexec | doas |
                        dzdo | ksu | runas ]
    --become-user=BECOME_USER
                        run operations as this user (default=root)
    --ask-sudo-pass     ask for sudo password (deprecated, use become)
    --ask-su-pass       ask for su password (deprecated, use become)
    -K, --ask-become-pass
                        ask for privilege escalation password

使用 root 用户:

Hypo-MBP:~ hypo$ ansible -i hosts local -a "whoami"
10.8.0.164 | SUCCESS | rc=0 >>
hypo

Hypo-MBP:~ hypo$ ansible -i hosts local -a "whoami" --become --ask-su-pass
SUDO password:
10.8.0.164 | SUCCESS | rc=0 >>
root

Playbook

通过命令行总归不是优雅的姿势,还是需要能存储的固定的脚本,每次部署的时候运行这个脚本,在 ansible 里便是 playbook。

NEXT 见:Ansible Playbook

2017/07/25 12:12 下午 posted in  坏笔记不如好记性

图灵机器人

偶然间发现居然有一家公司提供图灵机器人的 API(http://www.tuling123.com ),突然觉得可以做些好玩的东西,比如接入 DaoVoice。

在之前就在博客上接入 Voice,但是基本上没怎么用过,索性就拿自己的博客做个试验。

获得 API

图灵机器人 注册下,然后创建一个机器人拿到 APIkey:

然后可以使用官方提供的 API,进行简单的对话:

# POST /openapi/api

+ Request (application/json; charset=utf-8)

        {
            "key": "<APIKey>",
            "info": "hello",
            "userid": "<user_id>"
        }

+ Response 200

    + Headers

            Transfer-Encoding: chunked

    + Body

            {"code":100000,"text":"hi"}

这里的 info 就是发送的对话,而 response 里的 text 就是回复。

需要注明的就是这里的 userid,这是一个可以为空的字段,如果填写的话,可以对不同的用户的对话加些区分。

这个 api 可以做很多有趣的事情,不仅仅是简单的对话,还可以提供日常服务,比如问问天气讲个笑话之类的,用法的话可以见官方文档:http://www.tuling123.com/help/h_cent_webapi.jhtml?nav=doc

接入 DaoVoice

对于对话类的接入肯定是需要实时性,那么 Voice 提供的 Webhook 就可以满足需求,而 webhook 的详细内容可以看 Voice 的文档:http://docs.daovoice.io/api/#webhook

比如当收到用户回复的时候,主要关注 conversation_idconversation_parts 里的第一个信息的 body ,前者因为这是调用 Voice 回复 api 时要用的信息,后者是因为 conversation_parts 包含了整个对话,而第一个便是最新的回复。

当拿到这两个信息之后,把 body 里的内容,发给图灵机器人获得回复之后再把回复通过 回复对话API 发送给用户就可以了。

Docker image

因为程序非常简单,就是两个 API 来回倒腾,就几行代码的事情,索性 build 出一个镜像:https://hub.daocloud.io/repos/147ff5fa-dbdd-4f79-a489-546d2fc63e9c

部署

需要几个环境,变量,缺一不可。

KEY VALUE
VOICE_TOKEN DaoVoice 的 access_token
VOICE_API https://api.daovoice.io
VOICE_ADMIN_ID DaoVoice 用来回复的用户 admin_id
REBOT_API http://openapi.tuling123.com/openapi
REBOT_TOKEN 图灵机器人的 APIKey
docker run -d -p 80:4000 -e <上面的环境变量> daocloud.io/ihypo/robot

还有一个选填的环境变量:

KEY VALUE
SAY_HELLO 当用户创建回话的默认回复

使用

这个镜像开放两个 API

ping api,用来检查看有没有还活着:

# GET /_ping

hook api,直接把这个 api 添加到 DaoVoice 的 webhook 里就可以了:

# POST /hook

注意

只保证 tag:latest 能正常工作。

试玩

不用说太多,现在就点下右下角试玩下吧。

2017/01/19 21:57 下午 posted in  坏笔记不如好记性

为 nginx 配置 https

为了给全站加上https,需要先获得一个经过CA签名的证书,恰好startssl提供免费的证书,所以我就有了折腾https的机会。

首先,要在本地生成一个证书:

openssl req -newkey rsa:2048 -keyout yourname.key -out yourname.csr

一定要记好生成key的密码,在启动nginx的时候需要用到,执行完之后就获得了一个csr文件,把这个csr文件上传到startssl,就可以获得被startssl签名的证书:

然后把自己生成的key和在startssl,把这两个文件copy服务器上

cp 1_api.updev.cn_bundle.crt /usr/local/nginx/conf/server.crt
cp api.key /usr/local/nginx/conf/server.key

在nginx的server里配置:

ssl on;
ssl_certificate /usr/local/nginx/conf/server.crt;
ssl_certificate_key /usr/local/nginx/conf/server.key;

并把之前监听80端口改为监听443端口,之后重启nginx,这时会提示输入Enter PEM pass phrase,需要输入之前生成key文件时设置的密码,完成后,nginx重启成功。

这时便完成了https的配置。

然而,在重启nginx的时候却需要输入两次密码,比较蛋疼,而且使用daocloud或七牛的https时,带密码的key是不被支持的,所以我们可以生成一个不带密码的key,这样可以避免每次重启nginx都需要输入密码。而且也可以使用daocloud和七牛的https功能。

我们可以使用 openssl rsa -in server.key -out server.key.unsecure命令来生成一个不带密码的key,然后把server.key.unsecure按照之前的配置就可以了。

而使用daocloud的https时,需要提供startssl签名的crt文件(nginx版)和不带密码的key,这样就可以了。

2016/07/20 12:29 下午 posted in  坏笔记不如好记性