js SDK 设计指南
http://blog.csdn.net/hel613/article/details/51680611 git flow 分支模型 版本发布管理 文档生成
jsSDK 工程构建
单元测试
1:设计规范
2:了解实现细节
3:编写mock环境
4:编码
整个jssdk的设计有一下几个核心问题:
- 代码如何被使用页面接入
- 如何实现跨域通信
- 如何实现优雅api的设计
- 公共资源的使用
- 代码组件化
代码如何被使用页面接入
这个问题涉及到几个小问题需要讨论:
- 命名空间. 动态的命名空间,在url中带上namespace=xxx
- 样式冲突
- 版本维护
- appid等参数的传入
命名空间
动态的命名空间,在url中带上namespace=xxx
样式冲突
利用sass、less这些预编译语言很容易
例如下面的代码:
$name: avUI;
.#{$name}__dialog{
@include reset();
.#{$name}__dialog__header{
color: white;
}
} 怎样制作高质量的更新日志?
指导原则
- 记住日志是写给人的,而非机器。
- 每个版本都应该有独立的入口。
- 同类改动应该分组放置。
- 版本与章节应该相互对应。
- 新版本在前,旧版本在后。
- 应包括每个版本的发布日期。
- 注明是否遵守语义化版本格式.
变动类型
- Added 新添加的功能。
- Changed 对现有功能的变更。
- Deprecated 已经不建议使用,准备很快移除的功能。
- Removed 已经移除的功能。
- Fixed 对bug的修复
- Security 对安全的改进
如何减少维护更新日志的精力?
在文档最上方提供** Unreleased **区块以记录即将发布的更新内容。
这样有两大意义:
- 大家可以知道在未来版本中可能会有哪些变更
- 在发布新版本时,可以直接将Unreleased区块中的内容移动至新发 布版本的描述区块就可以了
有很糟糕的更新日志吗?
当然有,下面就是一些糟糕的方式。
使用git日志
使用git日志作为更新日志是个非常糟糕的方式:git日志充满各种无意义的信息, 如合并提交、语焉不详的提交标题、文档更新等。
提交的目的是记录源码的演化。 一些项目会清理提交记录,一些则不会。
更新日志的目的则是记录重要的变更以供最终受众阅读,而记录范围通常涵盖多次提交。
无视即将弃用功能
当从一个版本升级至另一个时,人们应清楚(尽管痛苦)的知道哪些部分将出现问题。 应该允许先升级至一个列出哪些功能将会被弃用的版本,待去掉那些不再支持的部分后, 再升级至把那些弃用功能真正移除的版本。
即使其他什么都不做,也要在更新日志中列出derecations,removals以及其他重大变动。
易混淆的日期格式
在美国,人们将月份写在日期的起始(06-02-2012对应2012年6月2日), 与此同时世界上其他地方的很多人将至写作2 June 2012,并拥有不同发音。 2012-06-02从大到小的排列符合逻辑,并不与其他日期格式相混淆,而且还 符合ISO标准。因此,推荐在更新日志中采用使用此种日期格式。
常见问题
是否有一个标准化的更新日志格式?
并没有。虽然GNU提供了更新日志样式指引,以及那个仅有两段长的GNU NEWS文件“指南”, 但两者均远远不够。
此项目意在提供一个 更好的更新日志惯例 所有点子都来自于在开源社区中对优秀实例的观察与记录。
对于所有建设性批评、讨论及建议,我们都非常 欢迎。
更新日志文件应被如何命名?
可以叫做CHANGELOG.md。 一些项目也使用 HISTORY、NEWS或RELEASES。
当然,你可以认为更新日志的名字并不是什么要紧事,但是为什么要为难那些仅仅是 想看到都有哪些重大变更的最终用户呢?
对于GitHub发布呢?
这是个非常好的倡议。Releases可通过手动添加发布日志或将带 有注释的git标签信息抓取后转换的方式,将简单的git标签(如一个叫v1.0.0的标签) 转换为信息丰富的发布日志。
GitHub发布会创建一个非便携、仅可在GitHub环境下显示的更新日志。尽管会花费更 多时间,但将之处理成更新日志格式是完全可能的。
现行版本的GitHub发布不像哪些典型的大写文件(README, CONTRIBUTING, etc.),仍可以认为是不利于最终用户探索的。 另一个小问题则是界面并不提供不同版本间commit日志的链接。
更新日志可以被自动识别吗?
非常困难,因为有各种不同的文件格式和命名。
Vandamme 是一个Ruby程序,由 Gemnasium 团队制作,可以解析多种 (但绝对不是全部)开源库的更新日志。
那些后来撤下的版本怎么办?
因为各种安全/重大bug原因被撤下的版本被标记'YANKED'。 这些版本一般不出现在更新日志里,但建议他们出现。 显示方式应该是:
0.0.5 - 2014-12-13 [YANKED]
[YANKED] 的标签应该非常醒目。 人们应该非常容易就可以注意到他。 并且被方括号所包围也使其更易被程序识别。
是否可以重写更新日志?
版本维护使用“主版本.小版本.补丁号”这种有语义的命名方式管理版本。
v1.0.0
v1.5.0
v2.0.0 这样的版本号让使用者容易在changelog文档中跟综和查找。
添加新特性。对现有功能的变化(改变)。(弃用)once-stable特性在以后的版本中删除。(删除)弃用功能在本版本中删除。(固定的)任何bug修复。[安全]邀请用户升级的漏洞。
版本维护的目的是保证代码最新,功能最全,而不用每次做了升级,通知所有使用的第三方开发者把自己页面的代码挨个更换。两种比较好的方式:
- 小拖大,动拖静:即第三方引入的js是一个动态的,或者没有缓存没有cdn的,然后由它带出后面的cdn
- 隔段时间动态创建script
推荐使用「小拖大,动拖静」,后面介绍组件化也要使用这个方式来按需加载代码
小拖大,动拖静
(function(){
.....
var url = '最新版本cdn的地址';
load(url);
}())
隔段时间动态创建****script
(function () {
var s = document.createElement('script');
s.type = 'text/javascript';
var t = +new Date;
t -= %864E5;
s.src = 'http://xxx.com/sdk.js?t='+t;
var x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
** }**)(); appid等参数的传入
一般在引入sdkjs代码的时候需要加参数或者版本号,比如开放平台需要配置appid,所以url写法是: sdk.js?appid=xxxx&namespace=xxx 。jssdk需要拿到url中的这些参数,方法有以下两种比较通用的:
- 给script标签增加特殊属性,例如<script src="path/sdk.js?appid=123" id="_jssdk">
- 使用查找script标签方式:
//get url args function
function parserUrl(){
var scripts = document.getElementsByTagName("script"),
len = scripts.length,
url;
if (len > 0) {
for (var i = 0; i < len; i++) {
if (scripts[i].src.indexOf("path/to/sdk.js") !== -1) {
return scripts[i].src.split("?").pop();
}
}
}
}
所以appid,namespace这些都可以解析出来如何实现跨域通信
对于不在一个域名下的第三方页面引入的jssdk少不了的是跨域请求,这块移动上可以直接使用postMessage方法,将来可以使用xhr2+CORS,相兼容IE,参考《三水清跨域tag》
如何实现优雅api的设计
这里的api指的是开放平台提供的http接口,一般都会有一些标准的规范,比如:
我们设计这个函数接口的时候,应该充分考虑到将来server接口的增加,所以应该做成通用的服务,比如我们设计个sdkjs.api方法,接受四个参数:url\data\callback\method,默认如果data是函数就后面参数自动前提。
api: function(url, data, callback, method) {
var _args = $.toArray(arguments),
_callback = _args[2] || $.emptyFn;
if (_args.length < 3) {
throw Error("api arguments length wrong");
}
if (!$.isString(_args[0]) || !$.isObject(_args[1]) || !$.isFunction(_callback)) {
throw Error("api arguments format error");
}
var _cbid = 0;
if ($.isFunction(_callback)) {
_cbid = _CallbackManager.add(_callback);
}
//跨域发起请求
xDomain.send("api", {
url: _args[0],
data: _args[1],
method: _args[3] || "get",
_cbid: _cbid
});
return back;
}
网友评论