閱讀Mike Bostock文章:What Makes Software Good?

2018-02-11 14:08:02来源:https://weitinglin.com/2018/02/10/閱讀mike-bostock文章:what-make作者:我們的基因體時代人点击

分享

注:此篇为翻译 Mike Bostock的文章:What Makes Software Good?


身为一个开源软体开发者,我花很多时间在思考如何让软体很好。


身为开发者,无可避免地会有永无止尽的求救来自于Stack Overflow, GitHub issues和Slack mentions、email等。幸运地是你也可以看到大家是如何成功应用你所开发的软体做出超乎你想像的事情,知道自己帮得上忙,也是一个很强大的自我鼓励,让你坚持者去开发。


所以你会开始思考一件事?什么样的软体特质,可以让使用者成功或是失败?如何改善我的软体让更多人可以成功?我可以清楚地说明任何开发原则,或者其实我只是见招拆招?如同知名德国工业设计师Dieter Ram’s的 设计十诫


Good design is innovative. Good design makes a product useful. Good design is aesthetic. Good design makes a product understandable. Good design is unobtrutive. Good design is honest. Good design is long-lasting. Good design thorough down to the last details. Good design is environmentally-friendly. Good design is as little design as possible.

我曾经尝试谈论过所谓的Big Picture Stuff,像是从有趣的小问题着手、辨认和减少工具的偏误或是利用相关技术以及标準。


虽然Big picture是重要的,可能重要于今天我要谈的事情,但实际上我自己感觉Big picture的建议往往不实用,甚至很差。比如说,“尽量简单,但别太简单(Make it as simple as possible, but no simpler)”,我们也许都想要事情越简单越好,但往往我们不知道如何取捨来达到目标。


即使你有一个正确的大目标,往往不能保证你的设计能成功。实践一个想法和想法本身同样重要。魔鬼就在细节之中。


假如我没办法提供实务性或是可以立即实践的意见,那么给少点意见反而更好。一个来自Green&Petre的 Cognitive dimensions defines a set of “discussion tools" to “raise the level of discourse" about the usability of “information artifacts" such as code.


Abstraction gradient
Closeness of mapping
Consistency
Diffuseness
Error-proness
Hard mental operations
Hidden dependencies
Premature commitment
Progressive evaluation
Role-expressiveness
Secondary notation
Viscosity
Visibility

上面这十诫听起来不是很完美,也不是框架。听起来只是单纯对于视觉编成(Visual Programming),且只限于特定情境。我发现很难单纯地把一个领域中单一象限的问题直接映射到另一个领域,但还是个很好的起点来思考软体设计的“Cognitive consequences”。


这边我并不会去定义一个泛用型的框架,但我有一些观点可以分享,恰好是一个时机对于D3 4.0做事后的分析(Post-hoc rationalization),除了对于Data joing, scales, layout解离于视觉呈现很满意外,这边我将D3分解成一个又一个模组,让其他人更容易来延展应用,且修改了编程上的API,很担心这样的改变对于使用者来说很微妙,但实际上很重要。多数开发者过度专注于functionality, performance, correctness这些较好量化的主观特性。


的确上面的特质很重要,但是使用不易(poor usability)造成的代价也不小。问问那些在奋力理解令人疑惑代码模块的人,以及如找髮丝般除虫的人。我们必须尽快找到一个评估易用性的方法,且让程式更好用(We need to get better at evaluating usability sooner, and better at making software usable in the first place.)。


我们无法把代码放在手上把玩感受它的重量或是质地。代码的本质是资讯的"人工产物"(information artifact)而非物理性或是图形。你可以藉由编辑文本或是指令行来跟这些API互动。


这些互动依据标準定义来说,受到人为因子複杂性所影响。所以我们应该评估代码,就如同评估任何工具一样,并非只依据他能否达成任务,还要看这些工具是否好用,有效率和令人享受。同时我们还需要考虑到其Affordance(直观特质)和Aesthetics(美观)。


编程介面即是所谓的使用者介面。简单说,编程者也是人。在关于低估设计中人的成分,又可以听到Ram’s的说法:


Indifference towards people and the reality in which they live is actually the one and only cardinal sin in design.

这同样的暗示好的文档说明不代表是坏设计的藉口。也许你可以叫使用者去RTFM,但这是相当蠢(folly)的假设所有使用者能记得文档中的任何小细节。範例的清晰明白(clarity)、软体的可拆性(Decipherability)和除虫性(Debuggability)在真实生活中很重要。


这里提供七个案例来分享D3 4.0所做的改进和想法,这边先挑一个来翻译:


案例一:关于enter.append语法的改进


D3最重要的观念,便是资料驱动(Data-Driven),这边的Data代表的是你要视觉化的资料,而document则是你视觉化的呈现,更精确地说就是网页的Document Object Model(DOM)。



<!DOCTYPE html>
<svg width="960" height="540">
<g transform="translate(32,270)">
<text x="0">b</text>
<text x="32">c</text>
<text x="64">d</text>
<text x="96">k</text>
<text x="128">n</text>
<text x="160">r</text>
<text x="192">t</text>
</g>
</svg>


上面是一个简单的html文件,里面包含一个svg模块,其中相对应的资料就如下:



var data=[
"b",
"c",
"d",
"k",
"n",
"r",
"t"
];


在这序列资料中,要有相对应的文档模块(即为),这时就是d3中很重要的关键概念: Data-join 。



D3中Data-join的设计是给予其资料的序列和相对应要的文件模块,其会返回三个selection:


enter selection: 代表还未添加上去的要用来呈现资料的部件(element)。
update selection: 代表本来在文档中的部件,但需要调整的部分。
exit selection:代表在更动后需要被移除的部件。

但data-join并分直接去调整DOM本身,而是去计算所需要的enter, update, exit样貌。在下面这个简单的範例中,如何让文档随者资料改动而改动,是D3核心的功能。



var text = g
.selectAll("text")
.data(data, key); // JOIN
text.exit() // EXIT
.remove();
text // UPDATE
.attr("x", function(d, i) { return i * 32; });
text.enter() // ENTER
.append("text")
.attr("x", function(d, i) { return i * 32; }) // ��
.text(function(d) { return d; });


上面这块代码,是最初data-join设计的逻辑,先选择文档模块,导入资料(join),去掉更新后被移除的模块(exit),在更新还存在的部分(update),接者把新加入的资料代表要件更新(enter)。观察上面的代码模块会发现画有辣椒部分的代码是重複的:分别是更新x attribute在enter和update的部分。


在D3 2.0的时候,为了解决这个重複的问题,将对于enter selection执行append时,自动複製entering elements到update selection的部分,如此撰写逻辑可以变成如下面这样:



var text = g
.selectAll("text")
.data(data, key); // JOIN
text.exit() // EXIT
.remove();
text.enter() // ENTER
.append("text") // ��
.text(function(d){ return d; });
text // ENTER + UPDATE
.attr("x", function(d, i){ return i*32; });


虽然这样的设计减少了代码重複,但是实际上似乎是造成了使用性降低,第一点,因为其实践的机制,会让人不知道原来enter selection,会将append的要件,複製到update selection的部分,因此而产生了前面设计所谓的poort role-expressiveness或是hidden dependency。


第二点,代码的顺序因此变得会影响到执行,最后在D3 4.0版本,取消了这样的设计,提出了新的selection.merge,来整合enter和update的selection。



var text = g
.selectAll("text")
.data(data, key); // JOIN
text.exit() // EXIT
.remove();
text.enter() // ENTER
.append("text")
.text(function(d) { return d; })
.merge(text) // ENTER + UPDATE
.attr("x", function(d, i) { return i * 32; });


由上面的过程,可以体会到Rams原则: good design makes a product undersandable,而在cognitive dimension词彙上,它造成了poor consistency、poor role-expressiveness和hidden dependency.


最新文章

123

最新摄影

闪念基因

微信扫一扫

第七城市微信公众平台