article_image

本文选自拙作《Shortcuts 设计之道》,欢迎购买完整栏目。
独辟蹊径:Shortcuts 设计之道
独辟蹊径:Shortcuts 设计之道

几乎每个结构最终都倾向于比设计者想要的更重。这部分归因于称重部门过于乐观的估计,但也是因为几乎每个人都有“求稳”的倾向,从而使每个部分都比实际所需更厚也更重。——J· E·戈登:《结构是什么?》

如果说制作 Shortcuts 动作是一场烹饪游戏,那么各种逻辑运算模块就相当于香草和辛料等配料。至于最常见的 If 判断模块,则好比厨房里最常见的调味料——食盐,几乎任何动作都用得上,但是也很容易遭致滥用。

很多爱好者倾向于制作如瑞士军刀一般的多功能动作,比如万能视频下载工具,借一系列复杂的条件判断,尽可能囊括常见的下载需求。但是 If 判断模块毕竟太单薄,苟想用它覆盖多种情况,就需要不断嵌套新的 If 模块。那些动辄上百个步骤的巨型 Shortcuts 动作往往就是 If 扭曲成的乱麻。

Alt text
你愿意维护这种玩意儿吗

诚然,这些大家伙固然让人兴奋——美名其曰“万能下载工具”——但随着网站或软件本身的政策慢慢缩紧,原来的下载方式纷纷失效,而由于动作本身设计复杂,导致维护变成了一场让人如履薄冰的挑棍子游戏,弄错一个模块,很可能整个动作都用不了。

一如太咸的菜肴往往涩口而难以下咽,安插了太多 If 判断模块的动作也过于冗长,难以维护。客观来说,这类巨型动作在早年间确实起到了推广 Shortcuts 的作用,让很多初识者眼前一亮:原来还有这么好用的免费工具!可惜,一旦使用者受挫,反噬也很快:鲜有人能够维护它们。在国外进阶用户的论坛上,经常有人批评 Shortcuts 缺乏传统编程工具中的逻辑判断模块,最后还是回到 Python 或者 JavaScript。

Shortcuts 和传统编程语言当然不在一个赛道上,但是如果设计妥当,Shortcuts 动作也不至于非得膨胀成长满分支的乱草丛。Unix 原则指出,维护的成本往往会超过制作。类似的,编写 Shortcuts 动作时,最好也考虑到将来阅读和维护动作的人,包括——尤其,这是我加的——你自己。

本文选择复杂条件判断为切入口,介绍如何使用基础 Shortcuts 模块实现编程语言中四两拨千斤的 case/switch 运算,以简单的模式应对多变的使用环境,而不是重复使用 If 模块、让它像癌细胞一样布满整个动作。

基础多条件判断:以图片和视频处理为例

第一组例子来自相对简单的图片和视频处理。

我在处理配图时意识到 If 会碰壁:早年间写博客,由于手机截图体积实在太大,我就做了简单的图片压缩工具,根据图片格式采取不同压缩策略。问题在于,JPG 和 JPEG 其实是一种格式,只是文件拓展名不一致,如果严格遵从 If 判断模块的用法,那就要为两种本质上一样的情况各创建一个分支,并且复制一大串压缩和保存动作,。这样的动作,无论制作、维护还是向别人说明都非常尴尬。

幸好当时有一点编程基础,说到一次性匹配多种情况,我本能地想到了正则表达式,接下来的问题就成了如何将正则表达式和条件判断结合起来。如果您同样有一些编程经验,经过这些提示,答案恐怕也呼之欲出:首先获取文件拓展名,然后尝试用正则表达式 jpg|jpeg 去匹配,若匹配成功,就运行对应的压缩操作。

Alt text
用匹配和条件判断模块,实现简单的多条件判断

上述模块组合虽然简单,但效果立竿见影,原本或许要为 JPG 个 JPEG 各制作一套压缩流程,现在可以统一处理。

如果说正则表达式多少有些晦涩,那么图形化的过滤模块也是殊途同归。在处理视频文件时,我用 Filter Files 模块统括多种文件格式。我设计了一个为视频增加封面的 Shortcuts 动作,而常见的封面文件格式大概一只手——最多两只手——就能数得过来,因此只要识别出目标文件属于常见格式,Shortcuts 就会将其作为封面,继续处理。你可以继续增加其他可能的图片格式,只要保持第一行的条件间逻辑关系是 Any,则任意多的情形都可以归属其下。

Alt text
用图形化的过滤模块统括多种情况

不过,正则表达式和过滤模块只是简化了一部分条件判断,相当于把后续操作相同的分支合并在一起,并没有从根本上砍掉那棵恼人的 If 大树。在视频处理和图片处理时,由于常见格式不多,本节方案倒也未见掣肘。但是在条件继续膨胀之际,就要考虑全然不同的复杂条件判断机制。

进阶多条件判断:以套壳截图和费用计算器为例

套壳截图一直是热门的 Shortcuts 练手项目,既有恰到好处的技术难度——介于枯燥无味和难啃之间的甜蜜地带——又有可丰富社交生活,内行人一眼看出同道中人:哟,你也会这个啊1。其实这一同质化严重的热门品类,恰恰最考验制作者的功底。

Alt text
我早年间也制作过套壳截图类动作

早些年,iPhone 无非黑白两色,一个新手也能在十几分钟内学会怎样自制套壳工具。但随着产品线一直爆发式横向发展,无论手机还是平板电脑的机型都太多了。相当长一段时间,网上流传的套壳动作都大同小异,最后看的无非是谁先收录了最新发布的机型,或者谁支持的机型范围最广。竞争到这一步,基本就是一份苦力活,比拼谁更有耐心在巴掌大的屏幕上堆砌出几百个步骤的动作。Macstories 的套壳工具在北美玩家圈子里几乎占据垄断地位,与其说是因为它有什么巧妙构思,不如说是面对如此沉重的现成工具,除了制作者本人尚有一腔热血,其他人估计也没兴趣去改进或者与之竞争。

在六七年前,我就意识到这种像堆积乐高积木一样的思路并不可取。与其收录历史上出现过的所有机型,不如建一个轻盈的框架,让用户往里面填充自己实际在用的机型素材。而既然想鼓励用户自己动手,那就不可能把100个 If 判断模块甩到他脸上,必须从根本上选择另一种条件判断结构。当时我的选择就是字典。

**字典(Dictionary)**是一种特殊的数据数据,比列表(List)更加多元。列表是多个条目组成的,而字典中的每一条都有两个部分,分别是键(Key)和值(Value),当然,具体的数据可以自己设置,只要保持这种一一对应的结构即可2。在套壳截图动作中,我选择了“机型:素材图片编码”的结构,把可能用到的素材列成一目了然的字典,提取数据时只需判断机型就能撷取对应数据。此组合步骤固定,却能容纳无限的情形。3此模式的核心步骤包括:

  1. 一个字典(Dictionary)模块,以“键:值”的格式存储数据;
  2. 一个 Get Value form Dictionary 模块,用抽取到的“键”去提取对应“值”,本例中即以分辨率数据提取对应机型素材。
Alt text
用字典存储可能用到的图片素材

字典贵在简明,使用者可以在字典模块中删掉他不需要的机型,或者添加其他素材,而完全不需要修改后续操作。

Unix 所倡导的模块化设计实现了:素材存储、条件判断和后续步骤得以解耦,互不打搅。除了结构简单,字典也比条件判断模块更快,尤其在手机芯片功率欠佳的年头,那些有几百个步骤的动作可能要跑上十几秒甚至动不动就崩溃,但是我设计的动作无论预设多少素材,都不增负担。4

如果说截图只是娱乐,那么接下来还有更严肃的例子。我的本职工作是职业律师,在和当事人交流时,经常需要预先计算一下收费情况,互相都有个底。律师收费和法院收费都有很明确的规定,计算方式虽然不困难,但是步骤烦人,当场抽出纸笔列公式肯定不体面,而小程序和网页计算工具也有可能刚好打不开(服务器不稳),于是我自己写了一个费用计算器,其间正好遇到了更为复杂的条件判断。

Alt text
随手计算诉讼费用(图中为受理费)

诸位读者可能对律师费和诉讼费没有什么概念——希望您永远不要有机会掏这些钱——其实它们的计算方式和个人所得税类似,均分多个区间,各有不同的收费比率。自制费用计算器,其实就是先判断当前金额落在哪个价格区间,然后套用对应的公式。由于 Shortcuts 本身的条件判断太羸弱,导致第一步耗费了更多精力。最终我用了稍有改动的复杂条件判断模式。

Alt text
用词典、循环和条件判断模块,综合判断不同的计费区间

在截图的案例中,只需判定机器型号就能获得对应素材,而在判断数值区间时,由于字典中的每一个键都是浮动范围而非固定文本,思路也要随之调整。好在数值范围可以从小到大或从大到小排列,只需要依顺序逐区间比对,很快也能确定区间。本例所用组合是字典、循环和条件判断:

  1. 字典模块,存储数据;
  2. 循环模块(Repeat with each),逐个考察诸种情况;
  3. If 判断模块,核实是否符合当前数值区间。

另一种变体:以通用扫码工具为例

字典已能够容纳几乎无限的分支情况,不过,如果你真的考虑良多,很可能发现上一节的模式还不够快。原因很简单,虽然当前手机处理器性能过剩,但 Shortcuts 的优化却稀里糊涂,如果使用了循环模块,那么每次循环都会占用一个“最小时间”,假如你有几十个字典项目,那么延迟就积少成多。

此时,正则表达式再次登场。

我设计过一个通用二维码扫描工具,在扫码后可以跳到对应软件,如果没有对应项目则直接打开微信或者支付宝——毕竟这两者在国内是兜底的扫码工具。

Alt text
扫描跳转过程,无需手动点选

在确定键时,我插入了一段正则表达式,将字典中的所有预设键合并起来,用 | 分开,表示只要满足表达式中任何一种情形都算匹配成功——例如 weixin.qq.com|http://|https:// 就覆盖了最常见的几种二维码开头——据此可以一次性完成条件判断,随后再如前一节的模式那样按图索骥,根据键取得值。5

Alt text
用词典和匹配模块,判断不同的扫码入口

如果你也到了需要考虑 Shortcuts 动作运行效率的时候,至少有一件事情值得庆幸:你已经和新手拉开了相当长的距离,因为那些仍然身处 If 丛林的人,想必还难见舆薪,看不到这些模式。


  1. 至于文人相轻的那些故事,我们就不谈了。
  2. 实际上也可以制作出非常复杂的层级结构,但是本文暂不涉足过深。
  3. 具体方法:根据当前截图的分辨率判断机型。显然这种方法不能区分各种颜色,但是既然一般人只有一台手机,为什么要给它换上你根本未曾拥有的颜色呢?或许让原本简单的动作无限膨胀变异的,不仅仅是落后的设计思维,更有人们的虚荣心。
  4. 严格来说主要是不会增加运行时的负担,但是在编辑动作时,由于 Shortcuts 需要读取图片素材,可能还是会多花几秒钟,即便如此,负担也远远小于 If 怪物。
  5. 图中有文本替换模块和特殊转义语法 \.,这些是为了在字典中兼容正则表达式,技术细节可阅读原文,不影响对本文模式的理解。

author_avatar

Lawyer, macOS/iOS Automation Amateur