织语移动端


  • 首页

  • 归档

人脸识别简介

发表于 2018-09-17 | 分类于 人工智能

概念

人脸识别(Face Recognition)是一种依据人的面部特征进行身份识别,定位,查找的一种生物识别技术。生物特征识别技术所研究的生物特征包括脸、指纹、手掌纹、虹膜、视网膜、声音(语音)、体形、个人习惯(例如敲击键盘的力度和频率、签字)等,相应的识别技术就有人脸识别、指纹识别、掌纹识别、虹膜识别、视网膜识别、语音识别(用语音识别可以进行身份识别,也可以进行语音内容的识别,只有前者属于生物特征识别技术)、体形识别、键盘敲击识别、签字识别等。

人脸识别特点

人脸识别的优点:

  • 直观:可以通过观察比较人脸来直接区分和确认身份,具有同类特性的还有语音识别,指纹识别不具备该特性。
  • 非强制性:人脸识别是利用可见光获取人脸图像信息,不同于指纹识别或者虹膜识别需要利用电子压力传感器采集指纹,人为配合才能完成采集。
  • 非接触性:用户在进行人脸识别的时候,并不需要和相关的摄影设备直接接触。
  • 并发性:实际应用场景中,人脸识别技术可以进行多个人脸的分拣、判断及识别。

人脸识别的难点:

  • 识别率依赖环境:光照环境,人脸图像位置,清晰度,遮挡物等,都会影响识别成功率。
  • 人脸相似性:人类脸部存在相似性,不同个体之间的区别不大,所有的人脸的结构都相似,需要有足够智能的算法来区分出不同个体。
  • 人脸易变性:同样的人脸,也会面临着面部衰老,变化(胡须,眉毛等),人为改变(眼镜,化妆,整容等)等因素,增加识别的难度。
  • 人为因素:通过各种手段,人为的制造模拟的人脸图像(静态图片,3D模型等)。

人脸识别步骤

人脸识别主要流程如下

1.图像采集(Image Capture)

人脸图像分为静态图像和动态图像,静态图像是指照片和静态的纸质图片等,动态图像主要来自于摄像机实时拍摄采集或者已有视频。

2.人脸检测(Face Detection)

人脸检测就是找出图像中所有的人脸

能够实现人脸检测的算法非常多,原理也各不相同。最著名的当属 Viola-Jones 在 2001 年提出的算法,他们通过 Haar 特征和 AdaBoost 去训练级联分类器(Cascade Classfier)获得实时效果很好的人脸检测器,检测流程如下:

  • 图像预处理(将提取到的图片统一大小和灰度化)

    一般来说,计算机中的彩色图片都是由若干个色彩通道累积出来的,比如 RGB 模式的图片,有红色通道(Red),绿色通道(Green)和蓝色通道(Blue),这三个通道都是灰度图,比如一个点由8位来表示,则一个通道可以表示 2^8=256 个灰度。那样三个通道进行叠加以后可以表3*8=24位种色彩,也就是我们常说的24位真彩。对这样的图片做处理,无疑是一件很复杂的事,所以有必要先将彩色图转为灰度图,那样可以就减少数据量(颜色信息对于人脸识别没有作用)。灰度化和减少图片大小后,数据计算量和资源损耗大大减少,检测速度增加。

  • 构造级联分类器(Cascade Classfier)

    什么是级联的分类器呢?级联分类器是由若干个简单分类器级联成的一个大的分类器,被检测的窗口依次通过每一个分类器,可以通过所有分类器的窗口即可判定为目标区域。

    加载已经训练好的内置模型 haarcascade_frontalface_alt.xml,构建级联分类器。分类器可以加载不同类型的模型,OpenCV 内置了很多模型

    基础分类器以 Haar特征为输入,以 0/1 为输出,0表示未匹配,1表示匹配。其中 Haar 模型特征分为3种

    • 边界特征,包含四种
    • 线性特征,包含8种
    • 中心围绕特征,包含两种

      分类器可以运用不同的模型对预处理后的图片提取出不同的特征值,特征值是检测人脸的关键数据。不同的模型直接影响检测的成功率,这里用的是 OpenCV 已经训练好的数据模型,不同的厂商可能都会有自己的模型训练方法。

  • 运用 AdaBoost 算法进行检测

    将级联分类器和待检测图片一起 利用 AdaBoost 算法就能检测出图片中是否存在人脸,具体 AdaBoost 算法的原理,相对比较复杂,这里就不介绍了,可以详细查看 Wikipedia。

iOS 代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 图片灰度化
cv::Mat matImage;
UIImageToMat(image, matImage);

// 转换颜色空间
cv::Mat gray;
cvtColor(matImage, gray, CV_BGR2GRAY);

// 加载级联器
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"haarcascade_frontalface_alt" ofType:@"xml"];
cv::CascadeClassifier classifier;
classifier.load(filePath.UTF8String);

// 运用 AdaBoost 算法进行人脸检测
std::vector<cv::Rect> faces;
classifier.detectMultiScale(gray, faces, 1.1, 2, 0, cv::Size(30, 30));

// 是否包含人脸
BOOL hasFace = faces.size() > 0;

3.人脸校准(Face Alignment)

人脸校准是给一张脸,找出特征点的位置,比如鼻子左侧,鼻孔下侧,瞳孔位置,上嘴唇下侧等等点的位置,如下图:

图中红色的框就是在做 Detection,白色的点就是在做 Alignment。

找到人脸上68个普遍存在的点(称为特征点,landmark)

  • 下巴轮廓17个点 [0-16]
  • 左眉毛5个点 [17-21]
  • 右眉毛5个点 [22-26]
  • 鼻梁4个点 [27-30]
  • 鼻尖5个点 [31-35]
  • 左眼6个点 [36-41]
  • 右眼6个点 [42-47]
  • 外嘴唇12个点 [48-59]
  • 内嘴唇8个点 [60-67]

就可以知道眼睛和嘴巴在哪儿了,后续将图片进行旋转,缩放和错切,使得眼睛和嘴巴尽可能的靠近中心,人脸基本上就对齐了,经过校准之后人脸的识别率会更高。

4.人脸识别(Face Identification)

人脸识别这一块变数是最大的,有相对简单的离线方案,仅仅需要内置一些基础的样本数据,利用相关的算法就可以实现简单的识别功能。但这种方式实现的功能相对较弱,漏检率较高。另一种相对完善的方案是通过后台大数据配合深度学习,对统一实体自动构建出多种多样的数据模型,包括正面和反面的数据模型,来提高识别成功率。OpenCV 自带了三个人脸识别算法:Eigenfaces,Fisherfaces 和局部二值模式直方图 (LBPH)。这些算法都可以进行深度学习。

活体检测

人脸检测方法多种多样,但所有的方法都会面临着各种各样的欺诈手段,常见的3种为:

  • 合法的用户人脸照片
  • 合法的用户人脸视频
  • 合法的用户3D模型或者面具头套

面对这些欺诈手段时,一般采用活体检测技术来解决,活体检测实现的手段多种多样:

  • 基于运动检测,常见的有眨眼,动嘴等,该方式用户交互成本较高,欺诈成本较低。
  • 基于微纹理,利用假人脸经过二次采集后呈现与真实人脸的纹理差异检测
  • 基于多光谱,基于皮肤和其他材质在光谱放射率上的差异检测

目前大部分免费或者开源的人脸识别代码库都不带活体检测功能,这里收集了一些开源代码备用

opencv_contrib

EyeBlickCheck

Zeusee-Face-Anti-spoofing

行业现状

人脸识别系统的研究始于20世纪60年代,80年代后随着计算机技术和光学成像技术的发展得到提高,而真正进入初级的应用阶段则在90年后期。人脸识别系统成功的关键在于是否拥有尖端的核心算法,并使识别结果具有实用化的识别率和识别速度。国内的人脸识别企业较多,下图列举了目前人脸识别排行榜前几位的企业

其中前四家企业细分领域如下图

主要客户对比

盈利模式

企业开放 SDK

企业开放的人脸识别 SDK 分为在线和离线两种方案,在线方案以服务端为主,通过服务端对接 SDK 提供的 API,客户端只需要跟自己的服务端交互即可。这种方案适合服务端资源较充裕,而且对人脸识别及时性要求不是非常高的情况下使用。同时服务端可以充分利用大数据和深度学习相结合,发展出更多的应用场景。离线方案,是指客户端直接嵌入 SDK 供应商提供的离线 SDK,不需要与服务器交互,直接能够获取到识别后的结果。该方案使用场景较单一,适合轻量级接入到客户端,不依赖网络。

下面是部分人脸识别厂商的对比

企业 公开提供 SDK 支持离线 SDK 收费方案 产品缺陷
旷视(Face++) 是 是 单平台按年收费 暂无
商汤(SenseTime) 否 是 未公开 暂无
云从 是 是 未公开 暂无
依图 否 是 未公开 暂无
百度 是 是 按授权码个数收费 iOS 端不支持离线 SDK
腾讯优图 是 否 按 API 调用次数收费 不支持离线 SDK
阿里云 是 否 按 API 调用次数收费 不支持离线 SDK
虹软(ArcSoft) 是 是 永久免费、闭源(每年授权一次) 识别率一般,活体检测功能只在 Android 端公测

开源项目

OpenCV

OpenCV 是一个基于 BSD 许可(开源)发行的跨平台计算机视觉库,包括人机互动,图像分割,人脸识别,机器视觉等应用领域的开源成果。

OpenFace

基于 FaceNet 和 OpenCV 的实现的 OpenFace 开源库,是用 Python 开发的服务端程序。OpenFace 最主要的特色是依赖大数据进行基于深度神经网络的学习。

SeetaFace

中科院 山世光 老师开源,包含人脸检测,人脸对齐,人脸识别三个模块。基于 OpenCV 开发,同时对算法做了一些改进。但是在人脸检测速度上相对较慢,漏检率较高,这里有实测样本。

开源方案商业化落地的缺陷

  • 漏检率较高
  • 1 : N (多人识别)的识别率较低,识别较慢
  • 活体检测功能较弱
  • 离线方案没有深度学习能力

Demo演示

ArcFaceDemo

行业应用和产品落地讨论

有了上面的技术探索和实践,大家可以讨论一下,人脸识别在织语产品上的落地方案。

织语 iOS Hybrid 框架

发表于 2018-03-25 | 分类于 Hybrid开发

前言

Hybrid 作为一种混合开发模式,依赖 Native 端的 Web 容器(UIWebView / WKWebView),上层使用 H5、JS 做业务开发。这种开发模式,非常有利于办公协同APP的开放平台搭建,由 Native 端提供API,供第三方使用开发、快速迭代。

Hybrid APP 框架

一个完整的 Hybrid APP 框架主要包括 Manager、WebView 、Bridge、Cache 等模块。整个框架设计理念是组合,而不是继承,因此框架设计的不是一个 XXWebView / XXWebViewController 基类,使用者不需要在业务代码中继承 WebView 。框架设计的是一个 Manager 对象,使用者只需要跟自己业务中的任意一种 WebView 进行绑定,就可以拥有 Hybrid 的能力。

  • Manager 作为核心,负责处理 Hybrid 业务,校验和注册API

  • WebView 作为容器,负责展示前端页面,响应前端交互

  • Bridge 作为桥梁,负责 Native 和 JS 之间通信交互

  • Cache 作为缓存,负责缓存资源文件等

框架结构如下:

Hybrid 框架

WebView 容器

iOS8 以后苹果推出了一套新的 WKWebView,对于 UIWebView 和 WKWebView 的区别,可以参考 教你使用 WKWebView 的正确姿势,本框架暂时选用 WKWebView 作为容器,针对 WKWebView 的问题,本框架做了以下解决方案:

Cookie 问题

前端抛弃对 Cookie 的依赖,改为使用 H5 的 Storage 能力。另 Native 提供存读接口,以备前端使用存储功能。

NSURLProtocol 支持

WKWebView 包含一个 browsingContextController 属性对象,该对象提供了 registerSchemeForCustomProtocol 和 unregisterSchemeForCustomProtocol 两个方法,能通过注册 scheme 来代理同类请求,符合注册 scheme 类型的请求会走 NSURLProtocol 协议。但是这种方案存在两个严重缺陷:post 请求 body 数据被清空;对 ATS 支持不足。

跨域访问

iOS9 以后,可以通过 KVC 设置 WKPreferences 的 allowFileAccessFromFileURLs 和 allowUniversalAccessFromFileURLs 属性,来打开跨域访问。但是 iOS8 暂不支持。

Crash 白屏问题

在 WKWebView 白屏的时候,webView.title 会被置空,因此,可以在 viewWillAppear 的时候检测 webView.title 是否为空来 reload 页面。

缓存问题

针对单个资源文件,可以对该资源地址加时间戳避开缓存。针对全局资源文件,需要手动清理缓存,iOS9 以后,系统提供了缓存管理接口 WKWebsiteDataStore。而 iOS8,只能通过手动删除文件来解决了,WKWebView 的缓存数据会存储在 ~/Library/Caches/BundleID/WebKit/ 目录下,可通过删除该目录来实现清理缓存。

Bridge

由于容器选择是 WKWebView,所以 JS 调用 Native 端有两种方式 URL拦截 和 messageHandler 。下图为两种方式性能对比

性能对比

messageHandler 对比 URL拦截 性能大约提升了 20%,受益于 WKWebView,本框架采用 messageHandler + evaluatingJavaScript 的方式进行通信交互。

JS -> Native

Native 注入对象
1
2
3
4
//配置对象注入
[self.webView.configuration.userContentController addScriptMessageHandler:self name:@"nativeObject"];
//移除对象注入
[self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"nativeObject"];

注意:如果当前 WebView 没用了,需要先移除这个对象注入,否则会造成内存泄漏,WebView 和所在 VC 循环引用,无法销毁。

JS 调用
1
2
3
4
5
6
7
8
//准备要传给native的数据,包括指令,数据,回调等
var data = {
action:'xxxx',
params:'xxxx',
callback:'xxxx',
};
//传递给客户端
window.webkit.messageHandlers.nativeObject.postMessage(data);
Native 接收调用

当 JS 开始调用后,会调用到指定的 WKScriptMessageHandler 代理对象

1
2
3
4
5
6
7
-(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
//1 取出 name 是否与注入 name 匹配
if (message.name isEqualToString:@"nativeObject") {
//2 取出对象,做后续操作
NSDictionary *msgBody = message.body;
}
}

Native -> JS

对于 WKWebView ,除了evaluatingJavaScript,还有 WKUserScript 这个方式可以执行 JS 代码,他们之间是有区别的

  • evaluatingJavaScript 是在客户端执行这条代码的时候立刻去执行当条JS代码

  • WKUserScript 是预先准备好JS代码,当 WKWebView 加载 Dom 的时候,执行当条 JS 代码

很明显这个虽然是一种通信方式,但并不能随时随地进行通信,并不适合选则作为设计 Bridge 的核心方案。

注入时机

并不是所有前端页面都需要用到 Native 能力,因此在需要用到 Native 能力的页面,才注入 JS 代码,为其提供 Native 能力。与前端约定,如果需要,就假跳转至一个指定的 URL, 然后客户端在代理方法 webView:(WKWebView *)webViewdecidePolicyForNavigationAction:decisionHandler: 里判断 URL 是否为指定的 URL,如果是,则执行注入。

1
2
3
4
5
6
7
8
9
10
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
NSURL *url = navigationAction.request.URL;
if ([url.absoluteString isEqualToString:@"指定URL"]) {
// 执行注入 JS 代码

decisionHandler(WKNavigationActionPolicyCancel);
return;
}
decisionHandler(WKNavigationActionPolicyAllow);
}

Bridge 框架

整个 Native 和 JS 的 Bridge 交互流程如下图所示:

brdige流程

在 Native / JS 端,创建 Bridge 对象,该对象需包含:

property
  • messageHandlers 字典,以 handlerName 作为 key,保存对应 function
  • responseCallbacks 字典,以 callbackId 作为 key,保存响应 function
function
  • doSend: 调用另一端方法,传递 message 字典参数
  • responseAnotherMethod: 响应另一端的调用,接收 message 字典参数

Manager

Manager 为整个 Hybrid 核心,负责 JS 方法到 Native 端的映射,可灵活扩展。利用 runtime 特性,使用得到的 className 和 functionName 反射出指定的对象,并执行指定函数。

权限验证

针对打开的 WebView, 是否拥有合法使用 Hybrid 的权限需要进行验证,只有验证通过的页面,才能使用原生提供的能力。Manager 提供入口,具体验证由上层实现。

1
- (void)authenticationSignatureParameter:(NSDictionary *)parameter comlete:(void (^)(NSError *error))complete;

组件协议

JS 页面加载完,在使用 Native 能力之前,需要进行注册,即告知 Native 当前页面所需要使用的 API 列表。Manager 处理该流程,验证 Native 是否实现该 API,同时把 API 转换成对象,对象遵循以下协议:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@protocol KKWebViewJSApiBaseProtocol <NSObject>

@required
/// api名字
@property (nonatomic, copy) NSString *apiName;
/// 是否支持js多次回调
@property (nonatomic, assign) NSInteger isNeedRegistId;
/// 是否为事件类型,客户端调用,类似发通知给JS
@property (nonatomic, assign) NSInteger isEvent;
/// api接口参数数据
@property (nonatomic, strong) NSDictionary *paramData;
/// api接口响应回调
@property (nonatomic, copy) WVJBResponseCallback responseCallback;

@property (nonatomic, weak) KKWebViewJavaScriptManager *jsManager;

@end;

反射函数

Manager 把 API 转换成对象时,利用 Objective-C 的 runtime 反射机制:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Class cls = NSClassFromString(className);
if ([cls conformsToProtocol:@protocol(KKWebViewJSApiBaseProtocol)]) {
id<KKWebViewJSApiBaseProtocol> obj = [[cls alloc] init];
if ([obj respondsToSelector:NSSelectorFromString(functionName)]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[obj performSelector:NSSelectorFromString(functionName)];
#pragma clang diagnostic pop
return obj;
} else {
NSLog(@"function is not found");
return nil;
}
} else {
NSLog(@"clss is not found");
return nil;
}

Demo链接

参考文章

教你使用 WKWebView 的正确姿势

WKWebView 那些坑

浅谈Hybrid技术的设计与实现

自己动手打造基于 WKWebView 的混合开发框架

58 同城 iOS 客户端 Hybrid 框架探索

从零收拾一个hybrid框架

小团队Code Review实践

发表于 2018-03-21 | 分类于 代码管理

引入Code Review的想法,预谋已久。除了希望提高代码质量之外,还有以下目的:

  • 提前发现代码中的低端错误和潜在Bug
  • 培养开发者良好的编程习惯,促进技术提高

工具选取

由于项目本身已经托管在内网的Gitlab上,所以优先考虑的是直接利用Gitlab为平台进行代码Review。Gitlab官网演示了基本的代码Review流程,基本流程如下:

  • 开发者在Feature分支上修改代码,需要提交时,新建Merge Request,指定Review人员
  • Review人员收到Merge Request后,进行代码Review
  • Review通过,Merge Request指派给具有合并分支权限的人员进行Merge
  • Review不通过,拒绝Merge Request,重复上述步骤

这一套流程实践下来的问题是:

  • 每次Push代码之后需要开发者手动创建Merge Request(当然可以通过脚本进行自动化,但需要额外配置),然后进行代码Review,不是很方便。
  • 团队内使用标准的Git Flow,大量开发工作在Feature分支进行。Gitlab无法对每个新建的Feature分支自动添加权限控制,也就无法强制对Feature分支进行Code Review。

在Gitlab无法满足团队需求的情况下,继续寻找替代方案。目前比较流行的Code Review平台,主要是Google出品的Gerrit和Facebook出品的Phabricator,二者都已开源。

Phabricator对比Gerrit有如下优势:

  • 界面美观(在工具使用非常频繁的情况下,美观度也是非常重要的)
  • 功能齐全(Phabricator除了代码托管和Code Review之外,还集成了任务、Wiki、日程等)
  • 提供两种不同的Review方式,团队可以灵活切换
  • 能够集成各种自动化插件

当然,Phabricator相对Gitlab也有缺点:

  • 代码托管方面不如Gitlab专业(也不弱,但不够专业)
  • 部署和使用成本较高(环境配置复杂,命令行较多,对于非开发人员使用成本较高)

但这些缺点对研发团队来说都不是硬伤,可以想办法解决,所以最后决定使用Phabricator。

Phabricator实战

服务端部署

服务端的部署主要由运维团队支持,这里就不详细介绍了(如有需求,后续由运维团队进行详细介绍)。部署成功后界面如下:

Web端功能简介

Phabricator支持Code Review、任务、代码托管、审计、Wiki等各种协同开发工具,非常适合小团队使用。

安装客户端环境

Phabricator Code Review需要两个库支持:

1
2
3
4
mkdir ~/phabricator
cd ~/phabricator
git clone https://github.com/phacility/arcanist.git
git clone https://github.com/phacility/libphutil.git

arcanist 主要用来做代码的修改和提交,libphutil 是配套工具库,用来做代码语法检查等。安装完成后,设置环境变量,方便全局使用 arc 命令

1
export PATH=$PATH:"~/phabricator/arcanist/bin/arc"

这样客户端环境就搭建完成了。

初始化设置

  • 创建Admin账号,默认第一个登录的为Admin
  • 设置用户的注册规则和登录认证方式(注册设置为只能以公司域名结尾的邮箱才能注册,登录采用用户名+密码的认证方式,依据实际情况设置)
  • 设置服务端邮件发送参数(后续所有的Review信息都会通过邮件通知)
  • 设置代码仓库读写方式(支持SSH方式,用户需要在设置里上传自己的SSH公钥,支持HTTP方式,需要设置拉取代码必须的VCS密码)

仓库管理

设置完成后,开始迁移旧仓库代码,首先在Phabricator上创建新仓库


编辑URIs:


将 I/O 修改为 No I/O。

选择New URI添加旧代码的git仓库地址,I/O Type选择Observe模式。

右边Set Credential添加SSH认证(有效公钥)或者HTTP认证(有拉取旧代码权限的用户名和密码)


设置好仓库之后,回到Basics页面,在Actions中选择Activate Repository激活仓库。

如果参数都正常的话,过一段时间就会将原仓库的代码都同步到Phabricator服务器上。

同步完成后,将新仓库代码 clone 到本地。如果代码在本地已经存在,需要修改remote url指向新的url:

1
git remote set-url origin ssh://domain/testdemo.git

同时在仓库中添加配置文件 .arcconfig,.arcconfig 文件是一个放置在项目的根目录的 JSON 文件。:

1
2
3
{
"phabricator.uri" : "http://your.phabricator.domain"
}

也可以设置全局的配置 etc/arcconfig,如果本地仓库没有配置文件,默认会读取全局配置。
这里只设置了 phabricator.uri(安装 Phabricator 的 URI),其他详细用法可参考官方文档。

配置Herald强制代码Reivew

如果希望所有的代码提交都需要Review,可以添加Herald规则。创建新的Herald Rule


设置好规则,如果没有提交过Differential Revision,禁止Push代码到服务器。

Review流程

传统的Review流程:

  • 开发者修改代码(Write)
  • 本地提交代码(Commit)
  • Push到服务器(Publish)
  • 代码审核(Review)
  • 通过或者拒绝(Merge or Refuse)

Phabricator本身也支持这种Review方式,主要是通过Audit进行提交后Review。这种流程大家都比较熟悉,在这里不做重点介绍,主要介绍另一种Review方式:

  • 开发者修改代码(Write)
  • 本地提交代码(Commit)
  • 预审核(Pre-Preview)
  • 提交审核通过(Merge -> Publish)
  • 提交被拒绝(Refuse)

以Feature分支为例,修改代码,本地提交,Push到远程仓库。由于前面设置了强制Review,所以直接Push会报权限错误:

Phabricator通过 arcanist 进行代码Review,详细用法可以使用arc help命令查看。先用 diff 命令生成Revision:
arc diff

填好Reviewers,如果需要通知其他人,填好Subscribers。如果本地有 .arclint 文件,diff 过程首先会调用 lint 脚本进行代码分析,生成编译错误或者警告。可以通过 arc linters 命令查看默认支持的 linter,也可以支持第三方或者自己开发的 linter。lint 检查通过后会生成Revision URI:


同时,如果之前邮件系统已经配置好,Reviewers和Subscribers都会收到邮件。在浏览器中打开URI,可以看到相关的修改


评论之后,选择Accept Revision,然后提交。Revision状态会变为Accepted,其他人的列表中变为Ready to Land状态。

表示Revision Review通过,等待开发者执行 land 命令,提交到远程仓库Merge。开发者收到Review通过的邮件之后,在本地执行 arc land --onto feature/test1 将代码提交到远程仓库。–onto 后面指定需要Merge的远程分支名,如果不填,默认为 master。

land 之后的代码就成功进入了远程仓库,整个Review过程结束。

关于代码格式化

对于提交仓库的代码是否需要格式化,目前有2种方式:

第一种是在代码进入远程仓库后,通过自动化脚本进行格式化。这是最可靠的格式化方式,但缺点是格式化代码会对部分提交进行修改,造成代码中会多很多冗余的提交,同时修改代码之后还需要自动化系统来保证编译的正确性。

第二种是在客户端预埋脚本,提交代码时如果不符合规范,无法提交成功。这种方式会比第一种方式风险小,但是覆盖面不够广,必须依赖每个客户端都安装脚本。同时格式化脚本的接入,会提高代码提交成本。想想有时候因为部分代码风格的问题,导致代码迟迟不能入库,也是一件很烦人的事(Xcode提供 crtl+i 的快捷方式进行代码格式调整)。

总之,两种方法都有弊病,具体如何抉择,由团队内部根据实际情况来选择。

代码Review控制

Web方式Review代码的缺点是不适合Review大块代码,同时也没办法像IDE一样进行调试。所以尽量是控制每次提交的量代码量,每天提交代码进行Review。如果积攒了几个月的代码一次性提交,审核者也是一头包,Review效率也会大幅下降。

同一个功能最好是由同一个人Review,这样能保证业务的熟练度和细节的Review粒度。也提倡互相Review代码,而不是长期由Leader或者高级工程师Review,促进所有开发人员的技术成长。

后续目标

  • 与Gitflow无缝配合使用
  • 与已有的Jekins系统对接,实现自动化编译和测试

参考链接:

Phabricator

Phabricator Review Workflow

Phabricator中文站

使用Phabricator做为Code Review工具

大家的公司的Code Review都是怎么做的?遇到过哪些问题?

织语移动端

专注于工作协同的IM平台

3 日志
3 分类
© 2018 织语移动端
由 Hexo 强力驱动
|
主题 — NexT.Muse v5.1.4