閱讀習慣和個人知識管理體系
進入互聯(lián)網時代,知識的獲取成本變得前所未有的低廉饵溅,但是無論再好的知識妨退,若是沒有對個人產生價值的話,那也只不過是一種信息噪音而已蜕企。我在《個人知識管理:知識的三種形態(tài)》這篇文章中使用“材料 -> 資料 -> 知識”這樣的路徑來詮釋信息的流通咬荷,如何方便快捷并且有效地收集材料,再將其整理轉化為有價值的個人知識體系結構轻掩,在這個信息極度碎片化的時代變得尤為重要萍丐。而在《去偽存真的知識管理之路》一文中也詳細闡述了如何將網絡上的碎片化文章納入統(tǒng)一的稍后閱讀體系,比如有時候在朋友圈看到一篇好文章放典,但暫時沒時間直接看,或是這篇文章值得再讀一遍基茵,細讀一遍奋构,那么我就會將其存入稍后閱讀工具即Instapaper當中,諸如此類的還有Pocket拱层、收趣等等弥臼。
稍后閱讀中永遠讀不完的痛點:缺乏追蹤
隨著時間的推移,Instapaper里面的文章將會變得越來越多根灯,就像我們在代碼中所注釋的TODO:可能就變成了Never Do径缅,“稍后讀”也是一樣地被廣為詬病:Read it Later=Read Never烙肺。其實我發(fā)現(xiàn)文章堆積的一個永恒痛點就是沒有有效的方式追蹤自己的閱讀需求與能力纳猪,其核心原因在于閱讀的速度趕不上添加的速度。從而沒辦法可視化的評估閱讀進度桃笙、合理安排閱讀計劃氏堤,也就沒辦法給予自己適當?shù)莫剟睿L此以往必然將失去閱讀的動力搏明。
在之前的一篇文章——《基于GitHub的敏捷學習方法之道與術》鼠锈,其中提到使用GitHub Issue來管理自己的學習計劃,于是就產生了這么一個想法——將我的稍后閱讀列表跟GitHub結合起來星著,使用ZenHub豐富的圖表功能將閱讀體系進行追蹤與可視化购笆。
可視化Cumulative Flow Diagram
首先讓我們直接來看一下最終的具體效果圖,在這里簡單介紹一下CFD(Cumulative Flow Diagram)即累積流圖虚循,這是一種能讓你快速了解項目或產品工作概況的圖表同欠,關注的是價值的流動效率样傍,價值的流動最直接的體現(xiàn)就是需求卡片在各個隊列中的數(shù)量。
里特定律(Little’s law)告訴我們行您,交付時間(Delivery time)依賴于在制品數(shù)量(Work In Progress, WIP)铭乾。WIP是指所有已經初始但還未完成的工作,例如:所有在分析(Analysis)與完成(Done)之間的工作娃循。首先需要留意的就是WIP炕檩,如果WIP增加了,交付日期就會有風險捌斧。ZenHub所提供的Release Report中最有效果的就是預測完成日期笛质,總之就是跟敏捷方法結合起來,使用項目管理的方式來管理自己的閱讀列表捞蚂,雖然我還處在進一步的探索之中妇押,但是每次看到這個走勢圖就能對自己的閱讀列表有更多的掌控和理解,至少減少了因文章堆積而產生的焦慮感姓迅。
IFTTT與Serverless架構
那么這是怎么通過APIs來實現(xiàn)的呢敲霍?在真正進入正題之前我們先來簡單介紹一下Serverless架構。Serverless指的是在構建Web應用程序的時候丁存,不用擔心如何配置服務器肩杈,但是這并不意味著應用程序不會在服務器上運行,而是說服務器的管理都可以盡可能地交給相應的云平臺解寝,從而最大程度地減輕開發(fā)人員的部署與配置工作扩然。與之對應的一個名詞可能就是Function As a Service(FAAS),由AWS Lambda這個命名就能想到聋伦,當我們在構建Serverless架構時夫偶,實際上我們是在寫一個個的Function,即函數(shù)而已觉增。
流程化:APIs即服務
首先讓我們來介紹一下IFTTT即if this then that兵拢。通俗的來講,IFTTT的作用就是當一件事情被觸發(fā)時逾礁,能夠執(zhí)行設定好的另一件事卵佛。所謂的「事」,指的是各種應用敞斋、服務之間可以進行有趣的連鎖反應截汪。IFTTT的宗旨是Put the internet to work for you(讓互聯(lián)網為你服務)。用戶可以在IFTTT里設定任何一個你需要的條件植捎,當達成條件時衙解,便會觸發(fā)下一個指定好的動作。它就像是一座神奇的橋梁焰枢,能連接我們日常所用的各種網絡服務蚓峦。
而我們現(xiàn)在遇到的這個串聯(lián)式的場景是特別合適Serverless架構的舌剂,使用IFTTT并且將它跟Instapaper賬號綁定,設置文章添加暑椰、高亮霍转、歸檔等行為作為trigger條件,然后將相關信息發(fā)到某一個指定API endpoint一汽。先把操作GitHub Issue和ZenHub的各種APIs準備好避消,結合IFTTT的觸發(fā)器與Marker工具能夠非常方便地與之相集成,最后我們可以產出這樣一個APIs交互流程圖:
初始化Webtask項目
雖然AWS Lambda是Serverless架構的典范召夹,但它也有一些槽點岩喷,而且我覺得已經被人說得足夠多了,所以我們今天就來嘗嘗鮮监憎,著重介紹和使用一下Webtask纱意。你可能沒有聽說過推出該服務的這家公司——Auth0,但你一定知道大名鼎鼎的JWT即JSON Web Token鲸阔,這是一種開放標準RFC 7519偷霉,通常被運用在身份驗證(Authentication)和信息交換等需要安全傳輸信息的場景下。
首先讓我們來安裝工具初始化項目以及注冊賬號褐筛,然后使用電子郵件進行登錄:
npm install -g wt-cli
wt init <YOUR-EMAIL>
創(chuàng)建項目目錄腾它,添加index.js文件并添加以下內容:
module.exports = function (cb) {
cb(null, 'Hello World');
}
然后在該目錄中運行以下命令,進行應用程序部署之后死讹,點擊控制臺中輸出的URL就能看到編程史上最有名氣、沒有之一的HelloWorld!:
wt create index
Webtask的上下文綁定
Webtask有一個實用工具webtask-tools曲梗,可以將應用程序綁定到Webtask上下文赞警,讓我們將之前所export的簡單函數(shù)修改為綁定到Webtask的Express app,然后就可以愉快地使用Express進行開發(fā)虏两,一切就又回到了熟悉的軌道:
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
require('./routes/reading')(app)
module.exports = Webtask.fromExpress(app)
Webtask context還有一個非常重要的用途愧旦,就是在部署時傳輸一些敏感信息,比如安全Token定罢,從而在應用程序當中隨時使用它們笤虫。下面的部署命令中--secret后面所傳入的ACCESS_TOKEN都會在后續(xù)與GitHub和ZenHub APIs交互時被用到。
wt create index --bundle --secret GITHUB_ACCESS_TOKEN=$GITHUB_ACCESS_TOKEN
--secretZENHUB_ACCESS_TOKEN=$ZENHUB_ACCESS_TOKEN --secret
ZENHUB_ACCESS_TOKEN_V4=$ZENHUB_ACCESS_TOKEN_V4
# ./routes/reading.js
module.exports = (app) => {
app.post('/reading', (req, res) => {
const { GITHUB_ACCESS_TOKEN, ZENHUB_ACCESS_TOKEN, ZENHUB_ACCESS_TOKEN_V4 } = req.webtaskContext.secrets
}
}
使用GitHub Issue追蹤閱讀列表
IFTTT:添加Instapaper文章后自動創(chuàng)建GitHub Issue
得益于IFTTT非常豐富的第三方服務祖凫,IFTTT可以直接創(chuàng)建Instapaper與GitHub Issue相集成的Applet:If new item saved, then create a new issue - IFTTT琼蚯,就可以在當Instapaper新增文章的時候,自動在GitHub所指定的倉庫Issues · JimmyLv/reading 中創(chuàng)建一個新的Issue并添加相應的標題惠况、鏈接以及描述等相關信息遭庶。
但僅僅只是添加一個Issue還不夠,這時候還需要將這個Issue加入到指定的Milestone以便利用ZenHub的圖表功能稠屠,使用GitHub的Webhooks功能就可以輕松幫我們把Issue更新的狀態(tài)轉發(fā)到我們所指定的Webtask地址:
使用GitHub Webhook 更新Issue的Milestone
所以我們的Webtask就需要處理GitHub Webhook所轉發(fā)的POST請求峦睡,其中包括了Issue的類型和內容翎苫,在拿到'opened'即新建Issue類型的action之后我們可以對其進行相應的處理,即添加到Milestone當中:
if (action === 'opened') {
fetch(`${url}?access_token=${GITHUB_ACCESS_TOKEN}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
milestone: 1
})
})
}
結合ZenHub的Milestone燃盡圖我們可以清晰地看到剩余閱讀量榨了,并且能夠跟理想中的閱讀速度進行對比煎谍,從而判斷自己什么時候能夠全部讀完所有的文章×耄可能有些小伙伴看到這里會有所疑問呐粘,這些所謂的Story Point是從哪兒來的呢?接下來就要提到我們將要集成的ZenHub API了叔扼。
集成ZenHub API:閱讀可視化
更新Issue的估點和Release
GitHub Issue的任何變動都會觸發(fā)Webhook事哭,因此我們可以在Issue被加入Milestone之后再處理下一個'milestoned' action,即:
if (action === 'milestoned') {
fetch(`https://api.zenhub.io/p1/repositories/${REPO_ID}/issues/${number}/estimate?access_token=${ZENHUB_ACCESS_TOKEN}`, {
method: 'PUT',
body: JSON.stringify({ estimate: 1 })
})
.then(() => {
return
fetch(`https://api.zenhub.io/v4/reports/release/591dc19e81a6781f839705b9/items/issues?access_token=${ZENHUB_ACCESS_TOKEN_V4}`,
{
method: 'POST',
})
})
}
這樣我們就完成了對每個GitHub Issue的估點瓜富,以及設置了對應的Release鳍咱,接下來所有的變動都將體現(xiàn)在ZenHub的圖表當中。
歸檔Instapaper文章后關閉GitHub Issue
說了這么多与柑,不要忘了整個閱讀系統(tǒng)最最核心的部分依然還是「閱讀」鞍肌!在眾多的稍后閱讀工具中我無比喜愛Instapaper并遲遲沒有轉到Diigo的原因就在于它優(yōu)秀价捧、簡潔丑念、純粹的閱讀體驗,讓人可以專注在閱讀本身這件事情上结蟋,在被Pinterest收購之后更是將所有的諸如全文搜索脯倚、無限高亮/筆記、速讀等Premium功能都變成了免費嵌屎,豈不美哉推正?
那么在完成閱讀歸檔之后,最后一步就是在GitHub當中將Issue關閉掉宝惰,但是IFTTT的GitHub服務并沒有提供close Issue的接口植榕,于是乎我們就只有利用IFTTT新推出的Maker自己創(chuàng)建一個,即將Instapaper規(guī)劃作為一個IF trigger尼夺,然后用Maker發(fā)出一個Web請求尊残,可以是GET、PUT淤堵、POST寝衫、HEAD、DELETE拐邪、PATCH或者OPTIONS之中的任何一種竞端,你甚至還可以制定Content Type和Body。
app.get('/reading', (req, res) => {
const { GITHUB_ACCESS_TOKEN } = req.webtaskContext.secrets
const title = req.query.title
let keyword = encodeURIComponent(title.replace(/\s/g, '+'))
fetch(`https://api.github.com/search/issues?q=${keyword}%20repo:jimmylv/reading`)
.then(data => {
if (data.total_count > 0) {
data.items.forEach(({ url, html_url }) =>
fetch(`${url}?access_token=${GITHUB_ACCESS_TOKEN}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ state: 'closed' }),
})
}
})
}
上述代碼就可以用于處理IFTTT Marker所發(fā)送的GET請求庙睡,我們從query參數(shù)中取到文章標題之后再去搜索相對應的Issues事富,再通過GitHub API將其關閉技俐。
而與此同時,我們在文章的閱讀過程中统台,有時候也會想要對文章中的亮點部分進行高亮雕擂,甚至添加自己的一些想法和總結,那我們也可以用IFTTT Marker和Webtask的套路添加至GitHub Issues的comments當中贱勃。具體的詳細代碼就不貼了井赌,更多內容都已經放在我的GitHub上:JimmyLv/demo.serverless-mern,與此同時我的閱讀列表也公開在GitHub上:Issues · JimmyLv/reading贵扰,歡迎圍觀仇穗。
總結與后續(xù)計劃
隨著時間的推移,日常你只需要在Instapaper添加并閱讀文章即可戚绕,而背后利用Serverless所搭建的整套閱讀追蹤系統(tǒng)將會任勞任怨的幫你記錄下所有的蹤跡和筆記纹坐,你只需要在特定的時候定期review、分析閱讀的效果與預測效果舞丛,與此同時結合自己的時間統(tǒng)計系統(tǒng)耘子,持續(xù)不斷地改進自己的閱讀目標與閱讀計劃。
最后再來考慮一下后續(xù)計劃球切,比如說我現(xiàn)在只是簡單把Instapaper中高亮部分和閱讀筆記作為評論放到GitHub的comments里面谷誓,但是最終我需要把它收藏到自己的個人知識庫即Diigo,這也是可以通過API自動實現(xiàn)的吨凑,以及最終需要被刻意記憶的部分還需要與Tinycards或者QuizletAPI相集成捍歪,對抗艾賓浩斯遺忘曲線。
與此同時鸵钝,還需要根據(jù)文章類型和難易程度具體劃分一下估點糙臼,而不是現(xiàn)在簡簡單單的1點,比如說Instapaper也有根據(jù)字數(shù)來預測的閱讀分鐘數(shù)蒋伦,以及根據(jù)中文或英文、技術或雞湯等不同種類文章閱讀難度進行區(qū)分焚鹊,從而使整套追蹤系統(tǒng)更具有效性與參考性痕届。
文/ThoughtWorks呂靖