你好,生产力(番外篇1) - Linear, be Pragmatic, but Gracefully
在生产力工具大类里,Project Management & Issue Tracking Tool(国内一般统称项管工具)可以说是其中历史最悠久也是最拥挤的品类。一方面项管工具是任何一家信息化管理的公司里最基本,最核心的工具,承担着安排计划,管理进度,追踪问题,串联其它各平台的任务。另一方面项管工具表面上的门槛比较低,Todo list其实也称得上是一个轻量化的项管工具。这两个因素叠加在一起,自然有人前仆后继地涌进这条赛道,而这其中的绝大多数产品也还是难以摆脱Jira+Trello的影子,形成低水平的重复。Linear(https://linear.app)是最近出现的又一款项管工具,倒是有些与众不同。
创始团队
Linear的创始团队背景确实很合适打造项管工具,设计师+全栈+工程管理+成功创业背景,又都是顶配。
Karri Saarinen - 之前担任Airbnb的首席设计师,Coinbase的第一位设计师以及之后的设计团队负责人。之前也在YC的其它公司创过业。
Tuomas Artman - 研发背景,主要经验在iOS移动端,早先创业的公司被Groupon收购,之后担任过Groupon和Uber的研发以及管理职位。在Uber帮助把移动工程团队从15人扩张到400人。
Jori Lallo - Coinbase早期的工程师,负责API和前端框架。
数据模型
数据建模很大程度上决定了产品的形态,体现了设计者的取舍,所以大量的篇幅会分析Linear的建模。
顶层模型 - Workspace
半顶层模型 - Account
Workspace的子模型 - Team, Project
Team的子模型 - Issue, Workflow, Label, Template, Cycle
顶层模型之Workspace
半顶层模型之Account
Account代表一个用户。说它是半顶层模型,因为它的两面性。
作为Workspace子模型的一面
管理Account设置的URL是linear.app/<<workspace url name>>/settings/account/profile。
在某一个Workspace下访问这个account所有issue的URL是linear.app/<<workspace url name>>/profiles/<<username>。
上一点URL里的<<username>>还有头像这些可以被更改,但是修改的作用范围仅限于这个Workspace。
作为顶层模型的一面
看上去和Workspace是多对多的关联关系,一个Workspace可以关联多个Account,一个Account也可以关联多个Workspace。
管理Account设置的URL,如前所述虽然是按照Workspace限定的,但其中的一些设置,比如界面Theme是否采用Light还是Dark mode又是跨Workspace的全局设置。
虽然无法看到Linear具体的DB Schema,但是从cookie上还是可以看出不少端倪。如截图,其实之前说的Theme设置是作为cookie存的,为了确认Theme只是存于本地cookie而没有存于服务端,我还专门在隐身(incognito)窗口用同一个用户再次登陆一下,确实发现Theme的值没有同步过来。截图上还可以看到有3个user,它们都有相同的邮箱地址,各自属于不同的Workspace(cookie里是organization字段表示)。
这样看来,本质上Account还是一个Workspace的子模型,只是在设计上通过障眼法使得用上去感觉像个顶层模型。那为什么Linear不直接把Account设计为一个顶层模型呢,毕竟这样的做法是一个更符合直觉的设计。我的猜测是考虑到隔离性,按照Linear目前的设计,只有Workspace一个顶层模型,那么数据层可以按照Workspace进行切片,每一个Workspace其实都是独立的沙箱。这个对于运维,部署,数据迁移等都有巨大的好处。举个例子,不少企业通常考虑到数据隐私安全的原因,都会要求工具进行私有云部署,虽然Linear目前还仅提供SaaS公有云服务,但是将来要把它上面的某一个Workspace迁移到私有云就比较容易,因为一个Workspace就是一个沙箱,整体迁移很容易,不会牵扯到数据的裁剪或添加。当然Account隶属于Workspace,也会带来一定的开销,一个实体用户在每一个Workspace都会有一份用户数据,这个就产生了冗余,冗余会导致不一致,也会造成操作的繁琐,比如将来如果要给用户添加MFA,SSO等功能就需要每个Workspace都配置一遍。
Workspace的子模型
为了阐述方便,先放一张叫space2的Workspace截图
Team
从之前Cookie截图中能看到,Workspace对标的是Organization组织概念,Team作为Workspace的一个子模型也就比较自然,一个Workspace可以包含多个Team,而一个Team只能属于一个Workspace。从Team设置的链接也能确认这点linear.app/<<workspace url name>>/settings/teams/<<team key>>,这里的team key类似于Jira里的project key,作为Team下Issue的前缀,如上图中展示的TEAM1。
Project
从视图上看,Project是挂在Team下面的,看上去是Team的子模型。事实上Project和Team一样是Workspace的子模型。和Team是多对多的关系。对应的URL是linear.app/<<workspace url name>>/project/<<project id>>。
截图上可以看到project22关联了2个Team,这个对应到实际场景也很合理,许多项目(Project)是由多个团队(Team)参与的。
Team的子模型
Issue
在所有的项管工具里, Issue或者有些系统里也叫Task都是最核心的模型,作为工作项的载体。在Linear里, Issue是属于Team的,并且只能属于一个Team。对应的URL是linear.app/<<workspace url name>>/issue/<<team key>> + <<issue sequential id>>/<<issue title>>。team key指定了team,issue sequential id是一个从1开始的自增序列。从链接可读性上考虑,url里也包括了issue title,但是issue的定位并不依赖这个信息。虽然URL整体是放在Workspace下面,但是因为用了team key的前缀,所以还是属于Team的。另外Issue中也可以关联子Issue。
Workflow
Workflow以当前形态看更确切的叫法应该是Workflow state/status,因为只定义了State,没有定义Transition。对应的是Issue上的Status字段。Linear在这里限定了5大类状态Backlog, Unstarted, Started, Completed, Canceled,暂时还不允许新增。而在每一个大类状态里,用户则可以自定义小类状态,有一点特殊的是Started类下,进度环会根据状态的数量自动均分。
Label
Label就是打在Issue上的标签,对应的URL是linear.app/<<workspace url name>>/team/<<team key>>/label/<<label name>>。URL下展示的是这个Team下打了这个label name的所有Issue。
Template
Template用于新建Issue时的预填模版。对应的URL是linear.app/<<workspace url name>>/team/<<team key>>/templates/<<template id>>。
Cycle
Cycle算是Linear的一个特色。许多研发团队都是按照固定研发周期进行交付的,比如2周一迭代。类似于敏捷开发中的Sprint概念。Linear没有直接采用Sprint这个术语,是为了避免和敏捷开发的耦合。对应的URL是linear.app/<<workspace url name>>/team/<<team key>>/cycle/<<cycle id>>。URL下展示的是关联了这个Cycle的所有Issue。
数据模型小结
团队(Team)/项目(Project)为中心 vs 问题(Issue)/任务(Task)为中心
项管工具的建模从大的选择上主要分为两种,主流的是把Issue/Task作为Team或者Project类似概念的子模型,像Jira, Github, Gitlab以及Linear均采用了这个模型。另一种相对小众的则是把Issue/Task作为顶层模型, Asana,Google的Issue Tracker(https://issuetracker.google.com),Apple的Radar采用的是该模型。两种模型各有优劣,前者以Team/Project为中心,更加结构化,但也使得Issue/Task需要和Team/Project进行耦合,适合于团队的项目管理。后者以更加原子的Issue/Task为中心,更为灵活,适用的范围不仅限于团队的项目管理,也适用于通用的工单管理系统,但是这个灵活性也是要付出不小代价的,一旦Issue成了顶层模型,那么和Issue中关联的Workflow, Label, Template, Cycle也需要考虑成为顶层模型。拿Label来说,如果它作为顶层模型,就需要拥有自身的一套权限管理,谁能使用这个Label,修改这个Label,删除这个Label都需要单独设计。同时还要考虑像不同人各自创建了同名Label这样的场景。如果还是作为Team的子模型,以上规则就简单多了,权限使用Team的用户操作权限,同时不允许同名Label。但是当Issue是顶层模型,Label是Team子模型时又会出现其它问题,例如把Issue和team1关联修改到和team2关联,那本来属于team1的Label在team2中未必存在,也可能和team2中已有的同名Label冲突。因为Linear本身定位于软件产品团队,所以它选择以项目为中心的模型也是合理的。
Workspace作为唯一的顶层模型
Linear只有代表组织(Organization)的Workspace这一个顶层模型。从架构设计角度,应该是为了避免引入多个全局状态,而每一个顶层模型就代表一个全局状态。只有1个全局状态的系统远比有多个全局状态的系统要简单,因为前者可以按照这个唯一的全局状态标识进行切分,几乎所有的问题都可以采取分治的思路解决。拿Linear的例子来说,针对成千上万个Workspace和针对1个Workspace的运维操作本质上并没有太大区别。Linear又通过交互设计的障眼法,使得代表用户的Account使用起来感觉也是个顶层模型。这点上,我也是赞同Linear的选择,把有状态的部分也就是模型层(Model)做得尽量简单,在无状态的部分也就是视图层(View)增加复杂度来弥补前者的缺陷。
经典和巧妙
Linear从一开始的顶层设计上就采用了近几年慢慢沉淀下来的SaaS经典模型,Workspace(Organization) + Team/Project的2层设计。相比于之前的项管工具来说,在这点上是有后发优势的,毕竟当年的项管产品都没有考虑到Organization功能,后面都是靠打补丁的方式加上去的。
而在Workspace之下,Linear同时引入了Team和Project两个概念。Project这个概念由于Jira等项管产品的普及,是一个被滥用的概念,团队,产品,项目都能成为Project。而在Linear里,通过Project的进度展示交互,巧妙地传递了Project包含时间的概念,再结合Team和Project的字面意思,能比较清楚地传达这两个概念间的边界。
交互
Linear的交互也有自己的想法,试用下来体会最深的也是它官网亮点里提到的前两点,快和Keyboard first
快
Performance is a feature
虽然单人使用还感受不到多人使用时信息同步的速度,但是Linear作为一个SPA应用,在页面间跳转的速度远比Jira那样每一个页面都要reload一下要快得多。项管软件里的信息彼此关联性很强,所以页面间跳转是一个高频场景。此外搜索采用的也是instant search的交互,搜索结果随着搜索框内容变化而变化,当然因为试用环境的内容有限,所以还无法验证真实场景的搜索响应性能。
Keyboard first
Linear身上带着Notational Velocity(http://notational.net/)和Alfred(https://www.alfredapp.com/)的影子。前者是一款推崇Mouseless Interaction的笔记软件,后者通过快捷键唤起输入框,再输入命令执行相应动作。这些都是针对键盘党程序员操作习惯进行的优化设计。Linear上的常用操作都有对应的快捷键,在光标悬浮时展示出来,时刻引导用户用键盘操作
另外像J/K的上下导航,G(Go)开头的界面跳转也都带着VI的烙印。
API和集成
Linear目前提供了Webhooks和GraphQL的API。Webhooks在Issue或者Comment创建和更新时触发。而GraphQL的选型还是比较大胆的,虽然已经有GitHub这样体量的GraphQL实践者,但是整体上GraphQL的生态还很薄弱。Linear内部也是采用了GraphQL作为前后端的API接口,从这个角度来说以GraphQL的形式把API开放出去也是一个自然的选择。但是另一方面,过早地把一个还未经足够时间验证的技术作为API接口暴露出去还是有比较大风险的。
开头说到项管平台是串联起组织里其它各色系统的公共平台,在集成方面,目前提供的有GitHub, GitLab, Slack, Figma, Zapier, Google Sheets。这个列表之后肯定会不断增加。
总结
<<程序员修炼之道>>是一本不少程序员应该都听说过的书籍,咋听上去书的名字还不错,但其实翻译把原版标题<<The Pragmatic Programmer>>的精髓完全丢失了。Pragmatic翻译过来叫做实用主义,这个词不仅能用来描述程序员,同样也可以用来形容工具,毕竟工具的使命就是帮助使用者Get shit done,先满足顺手,再追求顺眼。不少Todo List还是项管工具,陷入的一个误区是觉得工具本身没有太高功能性门槛,于是在视觉设计上追求差异化,这也就像<<程序员修炼之道>>这个翻译一样,看似高大上,实则偏离了主题。Linear也有出色的视觉设计,但首先它是一款透着浓浓Pragmatic气息的工具, made by the developer, for the developer。在数据模型层面,Linear既沿用了Jira的不少经典设计, 比如Issue, Team Key, Workflow, Template等,又对Jira Project滥用的问题进行了改良。相对Jira而言,Linear当前核心功能点又都比较克制,比如Workflow里限定Backlog, Unstarted, Started, Completed, Canceled 五大状态,不允许新增;Issue不允许自定义字段,也不允许关联多个Project。另一方面作为一款SaaS服务,除了功能性外,Linear也考虑到了可运维性,采用了一个顶层Workspace模型的设计。
Linear唯一让我觉得还有点缺憾的地方在于不支持undo/redo,支持undo/redo不仅能简化交互(撤销容易的话,绝大多数地方都不需要引入二次确认),而且它背后的一整套command pattern体系也是应用作为顶层设计的核心部分,之后可以扩展出脚本,录制等能力。早期产品没有支持的话,后期支持会比较困难。这里不确定的是Linear究竟已经埋了个坑,还仅仅是没有把能力暴露出来。但总的来讲,对于Linear的欣喜远胜遗憾,在Project Management & Issue Tracking这个品类里,已经很久没有看到一款做得不一样的产品了。近几年新涌现的产品里面,无论是Jetbrains Space还是狂打广告的Monday,给我的感觉就是又来一个。反倒是Jira老而弥坚,之前花了数年时间完成了把整个Infra搬上公有云的壮举,最近又在不断优化Issue和工作台两个最核心页面。
最后再说一下期待吧,Linear目前的能力已经能很好服务中小研发团队的使用场景了,但是以目前的扩展能力,很难满足大型组织的研发管理诉求。但话又说回来,项管工具的灵活性对绝大多数组织来说并不是好事情。拿Jira来说,绝大多数组织并没有驾驭它的能力。组织是可以很容易地在Jira的Workflow里增加一个流程卡点,但许多时候问题是出在组织本身的体制,文化,生产关系上,配一个流程反而是恶化了问题。无论是Jira还是Linear,都是用心的产品,而用心的产品,是会引导/教育用户的使用习惯。Jira有一套Agile Methodology,而Linear的背后则是Linear Method (https://linear.app/linear-method)
Build for the creators
Opinionated software
Create momentum - don't sprint
Meaningful direction
Aim for clarity
Say no to busy work
Simple first, then powerful
Decide and move on
项管产品很大程度上决定了组织的工作方式。目前还是小而美的Linear,主要服务的还是中小型团队。但我个人也还是希望Linear可以挑战大型组织的市场,毕竟项管领域一直是Jira派一家独大还是有点无聊的。接下来Linear团队在功能点上会做如何的取舍?以Linear轻盈的身姿是否能挥舞好它的精灵宝剑征服巨龙?就让我们拭目以待吧。