开发者体验 Developer Experience(DX)
Developer eXperience(DX) 定义
普通用户关注产品,需要提高用户体验,即 User Experience(UX)。
开发者的关注对象是库、功能、API、文档,需要提高开发者体验,即 Developer Experience(DX)。
DX的核心目标:提高自服务能力
需要提供各种工具、文档、机制,让社区的开发者可以自己服务自己,很容易的完成工作。
易用性、开发者体验差,体现基本都是开发者无法自服务,需要通过深度的外部协助才能完成,比如:
- 开箱即用的库缺失,需要从头开发
- 功能缺失,无从使用
- 功能不稳定,使用容易报bug
- 功能API难理解
- 功能没文档
- 功能没教程
- 有问题,网上找不到解决办法
- 有问题,没有开发者来解答
所以良好的易用性,良好的开发者体验,总体目标也很简单:开发者可以自服务。
软件不能让开发者自服务,结果就外部开发者使用摩擦大、内部开发者疲于做支持。
提高开发者自服务能力的方法
功能建设方面
功能好是核心和基础能力。
- 功能和API
- 好的功能和API是打磨出来的,所以除了设计,需要能快速获取反馈和持续迭代
- 架构
- 解耦,区分基础模块和可扩展模块,支持外部自定义的能力
- 模型库、示例代码、示例测试文件
- 基于软件做的应用库,可以认为是软件的生态
- 模型库让算法工程师可以开箱即用
- 示例代码帮助开发新模型
- 示例测试文件帮助系统开发者了解系统
信息沟通方面
信息沟通的形式
- 没有文本化的沟通,就是不存在的沟通
- README
- QuickStart
- 上手要真的可以做到Quick
- 快速安装
- 快速运行
- 编译
- 文档体系
- API 文档
- 教程
- Change Log,提示用户升级新版本可以获得的新功能、解决的问题、需要做的兼容性修改
- 问答和求助
- 提供反馈途径,GitHub Issue、论坛、邮件列表【没有文本公开文本记录的讨论就是不存在的讨论】
- 积累问答知识,比如issue
- 在错误提示中就提供解决办法
- 吸引志愿者、布道者、开发者,让外部开发者可以互相帮助,社区自服务
真实、开放、诚信的沟通
和开发者交流的态度会深刻影响开发者对软件、软件维护者的感知。开发者很容易感知到被糊弄了,保持诚实更容易获得开发者尊重。
如果软件存在缺陷,请清楚的说明情况。比如提供一个状态页面来公布情况,诚实的发布问题处理过程,及时共享问题分析和进展。
在论坛发布功能路线图,让开发者来提供优先级建议。邀请他们参与、听取他们的写法。
让沟通总是轻松、愉快
所有的开发者都希望参与的过程是开心的。想办法让交互的过程变得正向和有趣。
优质的文档
假设读者是新手。
保持概念的一致性。
文档体系需要有符合逻辑的结构。
对于文档来说,详细(啰嗦)的介绍是好的,一个细节的介绍可能可以解决卡住其他开发者很久的难题。
代码自解释不适用于负责和外部交互代码。
Release Log
主要回答三个问题,发布的新版本:
- 带来了什么新东西?
- 修复了之前的什么问题?
- 这个版本有什么风险?比如是不是有不兼容的API
易用性建设体系
来自 MindSpore 一个比较完备的图景。这里没有显示出重点和优先级,但比较完备。来自想飞就飞 @ MindSpore 。
参考资料
- MindSpore 易用性分享,姜宁,https://mp.weixin.qq.com/s/vu-tfpxXgJuU5LLXgdyAgQ
- Developer Experience, samjarman, https://hackernoon.com/the-best-practices-for-a-great-developer-experience-dx-9036834382b0
架构
好的架构来自对要解决的核心问题的理解,之后做出理想设计。
组织架构决定软件架构。太大的组织架构难以做好一致性比较好的东西。
哲学
Reading list
- Worse is better. https://dreamsongs.com/RiseOfWorseIsBetter.html
功能
软件的基础组成单位是功能及其API,需要精细的打磨。
好的功能集合,来源于好的设计,来源于对用户反馈的深入理解。
自己需要去多使用自己开发的功能。开发功能的人自己是第一用户。开发功能的人要为功能写测试和文档。
尊重行业标准、惯用语。
不要假设编程范式。考虑其他开发者的学习成本,往往函数式编程范式就是不好的。
正反馈的工具
工具的使用,最好的方式是交互式的探索:最简理解 -> 最小计划 -> 执行 -> 拿到反馈 -> 优化理解 -> 优化计划 -> 执行,如此循环。那么做软件时,最好就能让一个抽象好理解、看到就大概猜到该怎么用、很简单就运行起来、正确或者错误有具有指导性的反馈,形成一个“正反馈工具”,进而被用户接受。而上述探索式学习的过程,对应的就是软件接口的交互性、可观测性。
参考来源:做出让人爱不释手的基础软件:可观测性和可交互性, https://mp.weixin.qq.com/s/WEO1y8vg21CXlix8wO28hw
API
How To Design A Good API and Why it Matters
Full slides: http://www.cs.bc.edu/~muller/teaching/cs102/s06/lib/pdf/api-design
Why is API Design Important?
- APIs can be among a company’s greatest assets
- Customers invest heavily: buying, writing, learning
- Cost to stop using an API can be prohibitive
- Successful public APIs capture customers
- Can also be among company’s greatest liabilities
- Bad APIs result in unending stream of support calls
- Public APIs are forever - one chance to get it right
Characteristics of a Good API
- Easy to learn
- Easy to use, even without documentation
- Hard to misuse
- Easy to read and maintain code that uses it
- Sufficiently powerful to satisfy requirements
- Easy to extend
- Appropriate to audience
Getting the requirements for your API:
- extract “true requirements” from your customers (often, customers give you solutions as requirements, when they should be giving you a problem)
- extract requirements in the form of use cases (i.e. “as a shopper, i want to be able to add items to my cart”)
- create a small specification (about one page) and create it fast. Then present it to your customers for feedback, modify, and repeat. In other words, create the specification in an “iterative” manner (with constant feedback from your customer)
Writing the API:
- make your classes/functions small and cohesive. If its hard to name, its doing too much.
- name, name, name. Naming is everything. Better names, makes your API easier to learn/use.
- use the conventions/idioms/patterns that are common in whatever language/platform your API is meant to be used on. This reduces the amount your clients have to learn in order to use your API.
- document every single class/function. For a class, what does it represent? For a function, what does it do, what are its pre/post conditions and does it have any side effects?
- keep everything as private as possible (private classes/member functions/fields)
- design your API with change in mind. You will not get it perfect the first time. Try to keep that in mind when designing your API and you’re more likely to design it in such a way that it can evolve/adapt later when needed.
- “when in doubt, leave it out”, if you’re not sure about adding something to your API, don’t. You can always add later when you are SURE. If you add it now, when your not sure, you may get it wrong, now your clients are using that wrong API and you can’t change it. Remember, you can always add to your API, but you can’t remove without breaking client code.
- keep performance in mind, but don’t sacrifice readability for it.
- keep classes as immutable as possible. Even if you can’t make a class completely immutable, make it as immutable as you can.
- only inherit when is-a relationship exists.
- if a class is meant to be inherited from, document it
- if a class is not meant to be inherited from, prohibit it (some languages let you enforce this, in others, you can just write something like “Do not inherit” in the documentation) (the reason for this is that inheritance violates encapsulation/information hiding)
- don’t make your client do anything you can do for them (this reduces the amount of boilerplate code your client will have)
- don’t violate principle of least astonishment (clients on your platform are used to certain behavior in certain situations, go along with this!)
- fail fast (i.e. if an incorrect input is sent to your function, stop and display error immediately (best is at compile time, but sometimes you have to do it at runtime))
Here is a summary of the above summary:
- extract true requirements into a small (~1 page) specification iteratively
- name/document each and every single one of your classes/functions properly (which naturally tends to make them small/cohesive)
- don’t violate principle of least astonishment (use style/convention/idioms/patterns/behavior present in your clients platform)
- don’t violate encapsulation/information hiding (don’t do inheritance unless its truly an is-a relationship, keep classes/functions as private as possible, etc…)
- keep performance in mind, but don’t sacrifice readability for it
- keep classes as immutable as possible
- fail fast
- you can always add, but you can’t remove (w/o breaking client code)
Reference:
- How To Design A Good API and Why it Matters, Josh Bloch, https://www.youtube.com/watch?v=aAb7hSCtvGw , http://www.cs.bc.edu/~muller/teaching/cs102/s06/lib/pdf/api-design
库和生态
软件首先要自己提供一些开箱即用的应用库。一方面证明自己能解决特定领域的问题,另外方面可以使得用户开箱即用,第三方面还可以为功能使用提供范例,第四方面还可以对功能提供内部反馈。以获得良好传播。