18 2015

手环比较 – 小米 & Jawbone Up

好久没写和技术无关的文章了。手环我算是比较早的吃螃蟹的人,2013年的时候我就水货购买了一支Jawbone UP2手环,佩戴了大概3个多月的时间,然后它就故障了,囧。Jawbone的3个月算是比较有名的故事了,我不知道是品控还是什么问题,总是会有各种各样的故障。比如说无法充电,无法连接数据,等等。我当时是无法充电,插上之后直接没反应。之后这支UP2手环就被我弃置一旁了。

最近几天正好网上随便看看看到了小米手环,就买了一支随便玩玩,然后有了不少比较的经验,于是想要留点关于这两者之间的对比。

比较主要分为下面几部分:

0. 易用性

这点上先要申明一点,我买的Jawbone太老了,是UP2。这个版本的UP手环不支持蓝牙,易用性烂到了家,每次同步都需要脱手环,拔盖子,插入手机,烦躁。然后充电也要脱手环。而且UP手环为了监测的准确性,需要手动开启夜间模式,这点到了UP24手环还是没变。晚上睡觉的时候在睡着前记得要长按按钮,启动夜间模式。

所以易用性上来看小米手环完爆Jawbone UP手环,即便是型号24。小米的手环支持蓝牙,同步数据无需卸下手环。晚上睡觉不需要切换开关,直接就OK。

1. 睡眠监测

上面说到了UP手环需要开启夜间模式,启动其特色的MotionX监测,对你夜间的睡眠进行监测,并给与精确的反馈。小米在这点上差远了,虽然其易用性相当棒,不用手动启动track,但是精确性上不能和Jawbone UP比。观察就可以发现,小米记录的入睡时长很短,而我体感上是很久才睡着的。而且中间醒了几次,小米完全没监测到。我估计小米手环的睡眠监测就是手环(手)的移动频率进行简单的换算,其中应该没有进行脏数据的过滤。

见图:

IMG_0150 IMG_0132

2. 运动记步

和上面的睡眠监测同理,小米手环的精确性上有很大问题,简单测试可以发现单纯的甩手臂就能有记步数据。完全没有对数据进行脏数据过滤。Jawbone UP这方面做得好多了。其实从手环的体型上就能看出来,小米的才那么点体积,Jawbone比它大得多了。Jawbone那么大一根基本上里面都是电池和传感器,小米的才那么一丁点大小。

见图:

IMG_0151 IMG_0133

3. 智能闹钟

两者都有智能闹钟这个功能,监测闹钟设定时间点之前的X分钟内,使用者是否进入浅眠,如果进入浅眠,则发送几次轻度手环震动,尝试唤醒使用者。这样使用者就可以在浅眠中自然醒过来,无痛唤醒。

两者的这个功能我都尝试了,基本上还是准确的,也确实能做到无痛唤醒。体感上来说Jawbone的做得好些,手环的震动能力比较强,毕竟人家手环是一体的,不像小米只有一个核心。

IMG_0152 IMG_0135 IMG_0136

4. APP使用

这方面大家看图就可以了,不用细说了。从界面美观,数据可读性,健身健康建议,等等,Jawbone都比小米做得好太多太多。

IMG_0131 IMG_0134 IMG_0137

4. 佩戴

Jawbone UP手环只要稍微一掰就能打开,很方便穿脱,而小米手环使用的是表带式的卡扣,用起来相当不方便。美观上来说,Jawbone也比小米的好太多太多。

5. 总结

先放个图:

蓝的是Jawbone UP2手环,黑的是小米手环:

IMG_0140

 

行文中大家不难看出我对Jawbone手环的推崇。易用性上差了一点点,毕竟晚上睡觉的时候还要记得切换状态。从UP24手环开始,蓝牙功能已经有了,手环的易用性基本上已经和主流的手环一致了。最主要的记录功能,外形,应用的易用性和美观性,Jawbone都完爆小米。有钱的土豪完全不需要纠结,直接用Jawbone的就好了。

小米的手环优势只有一个,不过这个足矣,就是价格。Jawbone的手环走美亚也至少800+的RMB,小米才80,整整不是一个数量级上的。相信很多用户其实也并不是非常关心到底记录的精确度有多少,能记录就好了。所以,不得不说,小米干得漂亮。。。

04 2015

MAC下privoxy安装使用,及问题解决

1. 前言

很久没写博客了,各种各样的原因。本来这篇也不是很想写的,不过考虑到privoxy安装时候遇到的那么多问题,还是记录一下会比较好。

这里先说下安装privoxy的目的,因为现在使用自己的ShadowSocks,提供稳定的XXX。而SS是socks5代理,不支持HTTP。这里我们就需要使用一个软件将socks5转换成HTTP代理。查下来privoxy算是一个比较好的工具。

2. 安装

安装就一句话,直接就完成了。

brew install privoxy

主要我们要看下配置文件里的几个选项:

confdir /usr/local/etc/privoxy #配置文件位置,一般不改
logdir /usr/local/var/log/privoxy #日志文件位置,一般不改
logfile logfile #日志文件名字,一般不改
#日志级别,默认完全不打开,只记录fatal,需要自行编辑打开
debug     1 #记录请求地址
debug  1024 #记录被拒的请求及理由
debug  4096 #记录启动信息及警告
debug  8192 #记录非致命错误
listen-address  127.0.0.1:8118 #本地地址监听
forward-socks5   /               127.0.0.1:1080 #代理转发的源,这里填SS地址

如果需要开机启动,可以安装brew提示的内容,将plist文件放到指定地点

3. 查错

默认安装完后有几个问题比较麻烦

3.1 日志无输出

观察下来刚才配置文件里定义的日志没有任何输出,问题在于privoxy的mac plist文件编写有问题:去掉启动参数里的–no-daemon就OK了。这个参数是指在命令行下启动,并将日志输出到控制台中,debug时候用,自然没有日志输出了。

3.2 日志显示不停重启

2015-03-04 13:53:00.718 000003c0 Fatal error: can't bind to 127.0.0.1:8118: There may be another Privoxy or some other proxy running on port 8118
2015-03-04 13:53:10.792 000003c0 Info: Privoxy version 3.0.22
2015-03-04 13:53:10.792 000003c0 Info: Program name: /usr/local/Cellar/privoxy/3.0.22/sbin/privoxy
2015-03-04 13:53:10.792 000003c0 Info: Loading filter file: /usr/local/etc/privoxy/default.filter
2015-03-04 13:53:10.795 000003c0 Info: Loading filter file: /usr/local/etc/privoxy/user.filter
2015-03-04 13:53:10.795 000003c0 Info: Loading actions file: /usr/local/etc/privoxy/match-all.action
2015-03-04 13:53:10.795 000003c0 Info: Loading actions file: /usr/local/etc/privoxy/default.action
2015-03-04 13:53:10.801 000003c0 Info: Loading actions file: /usr/local/etc/privoxy/user.action
2015-03-04 13:53:10.802 000003c0 Fatal error: can't bind to 127.0.0.1:8118: There may be another Privoxy or some other proxy running on port 8118
2015-03-04 13:53:20.874 000003c0 Info: Privoxy version 3.0.22
2015-03-04 13:53:20.874 000003c0 Info: Program name: /usr/local/Cellar/privoxy/3.0.22/sbin/privoxy
2015-03-04 13:53:20.874 000003c0 Info: Loading filter file: /usr/local/etc/privoxy/default.filter
2015-03-04 13:53:20.877 000003c0 Info: Loading filter file: /usr/local/etc/privoxy/user.filter
2015-03-04 13:53:20.877 000003c0 Info: Loading actions file: /usr/local/etc/privoxy/match-all.action
2015-03-04 13:53:20.877 000003c0 Info: Loading actions file: /usr/local/etc/privoxy/default.action
2015-03-04 13:53:20.883 000003c0 Info: Loading actions file: /usr/local/etc/privoxy/user.action
2015-03-04 13:53:20.884 000003c0 Fatal error: can't bind to 127.0.0.1:8118: There may be another Privoxy or some other proxy running on port 8118

10秒一次,日志显示不停在启动privoxy,导致一直绑定失败(之前的没关,当然绑定失败)。还是plist文件的问题,将 KeepAlive 置成false就OK了。

基本上就这些了,记录一下,以防以后需要。

09 2014

Dart 中 Future 的错误处理

Dart里Future的错误处理有点绕,官方的guide在:https://www.dartlang.org/articles/futures-and-error-handling/

这里最容易造成的误解在于,当你自己创建一个返回Future的函数的时候,在该函数内的逻辑处理需要自己处理Exception。说起来有点抽象,可以看下代码。举例来说:

Future doItWithFuture() {
    var e = new Exception('error!!!');
    throw e;
    return new Future.value(123);
  }
 
  void handleError(e) {
    print(e);
  }
 
  doItWithFuture()
  .then((_) {
    print('normal end');
  })
  .catchError(handleError);

你可以猜下,运行的结果是什么,结果是:

Unhandled exception:
Exception: error!!!

程序崩溃了。

这里我们需要注意的是官方guide里的一句话:

The registered callbacks fire based on the following rules: then()’s callback fires if it is invoked on a Future that completes with a value; catchError()’s callback fires if it is invoked on a Future that completes with an error.

这里的关键在于粗体的那段 ,也就是说,你在写返回Future的函数的时候,必须自己处理好内部的错误,即便有错误,也需要返回Future,只不过这里的Future是一个承载错误的Future。

看范例:

Future doItWithFuture() {
    var e = new Exception('error!!!');
    return new Future.error(e);
  }
 
  void handleError(e) {
    print(e);
  }
 
  doItWithFuture()
  .then((_) {
    print('normal end');
  })
  .catchError(handleError);

运行结果一切正常,打印:

Exception: error!!!

这里有点小绕,所以留个笔记。

最后附带一个使用Completer的范例:

Future doItWithFuture() {
    final completer = new Completer();
 
    var e = new Exception('error!!!');
    completer.completeError(e);
 
    return completer.future;
  }
 
  void handleError(e) {
    print(e);
  }
 
  doItWithFuture()
  .then((_) {
    print('normal end');
  })
  .catchError(handleError);

07 2014

耶鲁开放课程:聆听音乐

Section 1:

什么是音乐,你为什么听音乐。你平时听的流行音乐和古典音乐到底有什么区别。

课程的时间,内容,教材,考试的简单介绍。几段简单的古典音乐片段的识别,简单乐理知识的认识和分析。

Section 2:

音乐赏析:

  • 贝多芬第五交响乐。
  • 柴可夫斯基第一钢琴协奏曲。
  • 莫戴斯特 穆索尔斯基 波兰牛车。
  • 理查德 斯特劳斯 死亡与净化。

音乐风格介绍。

乐器介绍:圆号:horn。巴松管:bassoon。中提琴:viola。

每种乐器的泛音不同,或者各自的物理特性导致其针对的泛音强度不同,使得各个乐器相互区别。

概念解释:

  • 歌带歌词,古典音乐基本不带字词。
  • 最低的声音发出了最长的声波:The lowest sounds create the largest sound waves。
  • 最低的声音持久最长:The lowest sounds last the longest。

名词解释:

genre,音乐风格。

symphony交响乐。交响乐一般有四个乐章:four movements。旋律:melody。音符:note。和弦:harmony。大调:major。小调:minor。

协奏曲:concerto。协奏曲一般有三个乐章。管弦乐队:orchestra。交响诗:tone poem,只有一个乐章。

铜管乐器:brass。弦乐器:string。木管乐器:woodwind。

动机:motive。主题:theme。泛音:partial、overtone。和弦:chord。八度音:octave。渐强:crescendo。不和谐音:dissonance。和谐音:consonance。基音:tonic、dominant。音高:pitch。

音阶:scale。揉弦:vibrato。拨奏:pizzicato。颤音:tremolo。

Section 3:

音乐赏析:

  • 穆斯林圣歌。
  • 查克 曼卓林 萨克斯独奏。
  • 科尔 波特 斗牛犬。
  • 莫扎特第四十号交响曲 g小调交响曲。
  • 约翰 斯特劳斯 的圆舞曲。
  • 流行音乐 专辑Document by REM。
  • 莫里斯 拉威尔 波莱罗舞曲。

乐理解析:

  • 二拍子、三拍子。
  • 识别重拍的方法:1. 重拍一般是长音。2. 识别重音(accent)。3. 识别音域(range):伴奏的样式(patterns of accompaniment),重拍一般落在低音。4. 识别和弦。
  • 节拍的分割和组合就是拍子。

名词解释:

音乐记谱法、乐谱:musical notation。二分音符:half notes。四分音符:quarter notes。全音符:whole note。休止符:rest。附点:dot。切分音:syncopation。抬头音:pick-up,在重拍之前的一小节音乐。

节拍:beat。拍子:meter。重拍:downbeat。和声:harmony。

Section 4:

音乐赏析:

  • 奇异恩典
  • 路易斯 阿姆斯特朗 哭泣的威利
  • 莫戴斯特 穆索尔斯基 基辅的城门
  • 莫扎特 安魂曲

乐理解析:

  • 音乐的速度指的是节拍的快慢(pace or speed of the beat)。
  • 节奏类型:1. 切分音:并未出现在拍子上的音,提早提前出现的音。
  • 三连音:在原来两个音的位置换成三个音
  • 音乐织体:曲调线的分布
    • 单音织体:monophonic texture,整个乐曲只有一个音
    • 主音织体:homophonic texture,整个乐曲有两个音,其中一个是主导的
    • 复音织体:polyphonic texture,整个乐曲由多个单独运行的音相互交织而成,其中还分模仿式和非模仿式两种
  • 数小节能帮助我们理解音乐的句法(syntax of music)

名词解释:

振幅:amplitude。音乐的速度:tempo in music。节奏类型:rhythmic devices。三连音:triplet。音乐织体:musical texture。对位法:counterpoint。数小节:count measures。

UPDATE:2014-07-09

这个课程虽然标注的是从0开始,但是课堂上已经涉及了太多太多的乐理知识了,而且还没系统讲解乐理知识。感觉就很别扭,而且和我最开始想象的教学内容不太一致,我一开始还以为是以鉴赏为主。稍显枯燥了点。先打住吧,暂时看到section4。

最后留点感想:将古典音乐拆分成小的乐理概念之后,你就会发现,其实和绘画是一样的,各种乐理概念作为你“画”上的“颜色”填充进去,目的是为了向听众展现、阐明一些什么东西,无论是场景、还是理念、还是想法。

21 2014

Dart 学习笔记

1. 简介

Google的东西用起来一般感觉都不赖,即便是编程语言,这点也没变。Dart不单单只是一门语言,其相关的配套设施也一应俱全:

  • DartIDE:简单好用的IDE,当然更推荐使用JetBrains系列的IDE,配上Dart的插件
  • dartanalyzer:语言分析工具
  • dart2js:js转换工具
  • dartfmt:代码格式化工具
  • docgen:文档生成工具
  • pub:官方自带的包管理工具(官方给出解决方案肯定比第三方出包管理工具要好太多太多了)。

Dart给我的印象是多种语言的优点的集合。再深入点,你会发现Dart最主要是受了JavaScript和Java两种语言的影响。设计模式上更倾向于Java,而语言本身的使用则更倾向于JavaScript。从服务器角度来说,Dart和NodeJs是一脉相承的:原生的lambda表达式,原生的异步IO支持,单进程的设计,基本上和NodeJs没什么差别。

在接下来的文章里,主要以外部资源介绍为主,因为google官方给的文章内的指导已经非常到位了,不需要我再写班门弄斧的文字了。这里主要是理清思路。

2. 基础资源

3. 语法

这里简单介绍与其他语言差别比较大的,需要特别注意的点:

4. 教程文章

  • Idiomatic Dart:教你如何使用dart式思考来编程,介绍了一系列dart式的语法和编程方式,基本上在读 Dart Style Guide 的时候顺道把这篇也干掉就对了。这篇文章里 Future.delayed 这段特别值得一读
  • Guidelines for Dart Doc Comments:怎么写文档注释,主要了解下dart提倡的简单书写,以及在注释中使用markdown
  • Emulating Functions in Dart:讲了在dart中函数动态调用相关的奇技淫巧,call函数,Function.apply函数,typedef函数的类型匹配,noSuchMethod函数,等
  • Mixins in Dart:Mixin 代码混合,在dart里的实现和使用,看下三条原则,和几个例子就差不多了。Dart是没有interface这个关键字的,接口一般使用 abstract class 来定义,这里的 Mixin 也起到了类似的作用
  • Snapshots in Dart:Dart的代码缓存机制,类似于字节码的东西?大概。官方说明是说能提高启动速度,不过我没看到能提高运行速度的说明
  • Optional Types in Dart:Dart里动态类型的一些规则和最佳实践,比如说要不要申明、什么时候申明类型啊,–checked模式会检查什么,之类的
  • The Event Loop and Dart:Dart的event loop是如何工作的,对于没接触过nodejs的人来说,这篇是非常重要的概念帖,里面有几点需要重点理解:
  • Numeric Computation:数字类型在Dart VM内的实现,以及如何使用它们,如何提升性能。在dart内部,int申明就有3种隐藏实现。注意Typed List这节,以及后续Pulling back the curtains这一大节里的优化点。
  • Reflection in Dart with Mirrors: An Introduction:Dart语言里的反射机制,动态调用,和类定义了解,都需要使用这套工具

14 2014

从技术人的视角谈软件公司经营

标题范围稍微大了点。从业6年有余,软件行业各种东西看得也比较多,甚至自己都出来干过一次(虽然是小打小闹的),估计写出来的内容也比较杂,就杂一点吧,写点我想得到的东西。

Index

  1. 人才的重要性
  2. 如何招聘人才
  3. 如何培养人才
  4. 如何留住人才
  5. 上层构造的重要性
  6. 其他
  7. 附录

1. 人才的重要性[Top]

1.1 什么是人才[Top]

几点我的归纳:

  • 能够适应公司文化
    • 适应公司文化这个说法实际上有点太文艺了,说穿了,就是员工能不能认可老板这个人、老板的做事方式。看不惯的,时间长了必然出问题。
  • 能够顺应公司发展方向
    • 能力能不能跟上公司发展,举个实际的例子,公司技术转型,新技术能不能学得会用得好。
  • 能够不断提升自我
    • 不能老想着啃老本,软件公司,技术日新月异,能不能在将来的挑战中活下去,不停自我学习很关键。
  • 能够为公司提供价值
    • 最关键的一条,公司雇佣员工,就是为了创造价值。

1.2 什么是价值[Top]

这绝对不是指工作产量,而是对于公司当下或者将来具有积极意义的和有用的东西。

举个最现实的例子来说,如果我用上班时间来写这篇文章,我花掉的这些时间,并没有写出一行代码(个人当前工作产量为0)。但是,假如这篇文章对于公司经营来说有启发意义(公司整体产量提升),就比我一人花这点时间写几十行代码来的有用得多得多,价值就更高。

再举个例子,我花了半天写了300行代码,然后花了半天做code review、写单元测试脚本,保证代码质量。比我花一整天写1000行代码要产出更多价值。因为事后产生的线上bug会少很多,假如提前预防掉的bug是支付等关系营收的敏感代码,则更等于产出了多得多的价值。

1.3 为什么需要人才[Top]

1.3.1 人才能创造更多价值[Top]

这点是显而易见的,而且是至关重要的,但是从我从业至今的经历来说,没有几个老板真的表现出对这点的关切(在缺乏人才的时候是否将人才招揽作为第一优先级处理)。这点我感觉非常不理解。

这里我举个例子来说。有一个软件公司的一个项目,持续的时间非常长,历任的程序员换过无数个,代码洋洋洒洒几百万行。但是流过的程序员没一个称得上人才,也甚至不能说是靠谱。结果很凄惨,代码质量如今可以用“考古”两个字来形容。代码质量差,并且没有一个主心骨领导的结果是显而易见的:业务开展异常缓慢,任何的新功能添加、老功能修改都可能引发一场地震(没人理解以前的代码内容和结构),营收慢慢下滑。这种项目只可能有一个结果,就是等死。

反过来思考,如果在这个项目一开始就有一个人才级别的领导者,并能持之以恒贯穿项目开发始终。项目代码必然结构清晰,文档齐全,各部门协作通畅。无论是代码质量保证,程序性能保证,功能开发,bug修复,都必定是顺畅无比的。

1.3.2 人才能带来更多人才[Top]

这点太容易理解了,我们经常听一些成功的产品在分享经验的时候说,口碑是最好的宣传,人才和产品在这点上非常类似。好的人才,能带来好的工作氛围,好的工作氛围,能让已经加入的人才更多地为公司做宣传,然后带来更多的人才,这是一个良性循环。

google的第二十位员工,当时唯一的女工程师,现在的雅虎CEO,玛丽莎·梅耶尔就说过:“尝试与你可以找到的最聪明的人一起工作,因为他们会挑战你而让你思考和工作得更好。”

人才能保证推荐进来的都是靠谱的人。物以类聚,人以群分,古今亦然。这会很大程度上减轻公司招聘的压力,并帮助你找到更多更好的员工。太多太多的创业成功者在分享招聘经验的时候,会告诉你,通过招聘手段和途径招到的员工,在招聘总量中总不会太多,而推荐反而是一种行之有效的手段。

反向思考一下。很多时候,我们会看到这样的现象。某些不靠谱的员工,爬到了一个与其能力不匹配的位置。当这样的人拥有了招聘权,公司的噩梦就开始了,能力拙劣的人会招聘人才?你让他怎么坐得稳他好不容易爬上去的位置?他会通过其影响力,推荐进来各种不理想的员工。最后,“他们“会想尽办法阻碍真正人才的进入,“劣币驱逐良币”,大家都懂,不是么。是不是很可怕?

1.3.3 人才能节约公司开支[Top]

这和1.3.1中论述的内容相辅相成。也是很多老板看不到的地方。雇佣靠谱的人才,会在很多隐形的地方给公司节约大量的开支。举例来说,靠谱的人才一次性写出来,能反复复用的代码,岂不是远远比写出来后跑个几次又发现重大问题反复重写的稀烂代码要节约得多?

2. 如何招聘人才[Top]

2.1 什么是知识,什么是能力[Top]

很多面试官在面试的时候经常会搞错两个概念,甚至很有经验的面试官亦然:什么是知识,而什么是能力。

对于大部分的面试官来说,面试就是问,这个你会不会,那个你会不会。这个时候,他考察的所有的点,都是“知识”。你会不会,你知道不知道,这只是知识,而不是能力。

能力是什么,能力是人们顺利完成某种活动所必备的个性心理特征。举例来说,有的面试问题一个应聘者回答不上,但是他在回答这个问题的过程中展现出来的心理素质、分析能力、逻辑思维能力、互动能力,是不是让你很满意?

当然,知识和能力都非常重要,只有能力而没有知识的应聘者同样是不合格的(没法在短期内就开始为公司创造价值),两者都是决定一个应聘者综合素质的要点。这里面试官需要注意的是不要只看到知识,而完全忽视了能力(很常见的现象)。

2.2 硬实力是一部分[Top]

这里我们把知识称为硬实力。很多时候,我们招聘到的员工,都只看到了他的硬实力,能不能干活,会不会这个技术。硬实力很重要,毕竟公司招聘员工,到底还是为了产出价值的。而且在招聘的时候,大部分时候薪资的定位都是靠硬实力来衡量的。但是招聘者必须要理解,我们经营的是什么?软件公司!这个行业变化万千,几年前的技术在几年后能不能存在经常都要打个问号。光有知识的员工是不堪重用的。

就说说游戏行业,几年前如日中天的flash,现在已经是日暮西山了,当年拿高薪的那些flash程序员现在可安好?可能现在还有工作,还混着。那再过几年,flash完全被淘汰了呢?

2.3 软实力更重要[Top]

能力是根本,有能力的人,无论行业怎么变化,他都能适应自如。就说程序员,代码写多了,本质的东西掌握了,语言就是一种工具,拿来就用。换个语言也就是换个工具,根本的东西不会变。有了这样的员工,公司也就有了底气,一个转身,pivot转型成别的经营模式,公司照样能活得很滋润。为什么?因为有靠谱的人才帮公司解决技术难题,支撑公司运作下去。

2.4 招聘必须落实到可执行、可量化的流程[Top]

理解了前面的内容,招聘工作还是必须要落实到操作上。很多公司的招聘,都有一个问题,就是结果不可量化。

“刚才那个人面试怎么样?”“不错,还可以。”“怎么样?”“很好啊。”

请问,可以在哪里?不错在哪里?这种模棱两可的结论其实是很没意义的。面试必须要做到能量化一个人,并且将其知识和能力都列入考量范围。

3. 如何培养人才[Top]

3.1 为什么需要培养[Top]

主要原因有两点。

第一,成本制约。

薪资必然是制约一家公司招募人才的一个重要原因,特别是现在中国生活成本大幅上涨的大环境下,老板必然想要降低成本,这里就有冲突了。正确的思路是绕开这个制约点,这个时候就势必会考虑怎么以低廉的价格招到可造之材,然后培养以期大用。

第二,技术方向和管理方向。

新进员工必然有很多东西需要培养。举例来说:

  • 公司文化的学习、适应
  • 工作中技术点的变化(相同的结果,实现方式可能不同)
  • 工作中工具链的改变
  • 团队协作习惯不同

等等,所以只要是新进员工就涉及到培养的问题。

3.2 正确认识培养需要的投入[Top]

从理性的思路上来说,要衡量一个投入有没有价值,必然要考虑它的产出。这里我们看看培养所产出的东西。

第一,人才的产出。

在第一章中,我们早已经讨论过人才在企业中的重要作用。所以这里我觉得我可以节省一点口舌再大动干戈论述人才的重要性。如果企业中人才的培训主要是针对3.1中的第一点情况的话,那更是省不得,因为你招聘进来的员工都只是种子,还没开花结果呢。持续稳定的培养投入能稳定提升你团队的实力、能力,对于长远来说,必然是很有意义的一件事情。

第二,人才的稳定性。

一般看到这里,我觉得很多老板都在心里嘀咕,培养完了,人走了怎么办?人之常情。这里简单解释下,主要的论述,我们押后到第四章,在那里我们会仔细讨论如何留住人才。

刚才在1.3.2中举例的时候也说到过,良币驱逐劣币,有些事,你越不做结果越坏。将心比心,你觉得作为员工的,是喜欢一家有担当会为员工的培养而付出的公司,还是小鸡肚肠一直打着小算盘的公司?这道理很简单不是么?

3.3 如何在工作的过程中进行提升[Top]

当然,培养培训,从来没人说一定要花公司成本而0产出。实际上很多东西,也是可以在工作的过程中进行的。

举个简单的例子,如果公司现在需要重做官网,让我来操作的话。我肯定会建议老板,我们使用当前最新的HTML5+CSS3+AngularJs+Grunt自动化工具,这一系列最新的web开发技术堆栈来实施。总的开发周期必然会延长,但是当事情结束,公司收获的就不仅仅是一个能看的网站,同样收获了一套能实践、使用的最新web技术能力。这对于公司来说,增进了技术积累。而对于员工来说,增加了新技术的能力培养。一举两得不是?

这样的情况其实在一家公司里其实是非常多的,关键就是要培养员工对技术的敏感度和学习同时工作的文化。员工没有这个意识,那就没人提这种可能性。公司没有这个气量,那就没有可能实施这种计划。

3.4 如何在业余时间提升[Top]

工作当然主要还是为了公司产出价值,所以一个人,如果需要提升,最主要的还是需要靠在业余时间自我培养。当然这里我们不会细谈如何提升自我学习能力,这是一个很大的话题。这里我们要谈的是如何保持公司里的一种学习氛围。

当你招募的员工都是码农的时候,必然的结果就是没人关心技术,关心的只是如何把工作做掉,然后回家休息,甚至是如何在工作的时候偷懒。这个时候,管理层就需要想办法解决这个惰性状况(即便你招聘到的都是人才,也是有惰性的,很多东西都需要激励)。

我觉得可以从以下几点着手:

  • 鼓励员工讨论新技术,培养、散播关注新技术的能力和手段。眼界首先需要培养,都不知道从哪里了解最新资讯还谈什么学习。
  • 择几项当前正红的技术,开讲座布道,入门、启迪。适当举一些新技术应用的例子,会有更好的效果。然后自然就会慢慢扩展开来。
  • 布置任务,接力棒的形式慢慢钻研一门技术,由简到深提升一门技术的熟练度,在时间、付出和收获上达到一个平衡。

3.5 谈谈如何做讲座[Top]

我见过太多的公司,都有所谓的讲座,但是做得都不好。我个人觉得从根本上,没有把握到应该怎么做讲座的方法。

首先,必须要明确讲座的目的。

在以公司的名义开讲座的时候,必须认识到,员工都是花了上班时间、业余时间,来做、听讲座的。如果对于员工来说是毫无意义的讲座的话,这就是一种浪费。举例来说,我曾经供职的公司,开过一个系列讲座,点人头一个个讲下去,由被点名的准备者任意选择他想讲什么。这太天马行空了,话题什么都有可能,大部分对我来说都是毫无意义的东西,还强迫必须参加。这只会引起反感。

讲座就必须符合大部分听众的利益(成长方向),对于实际的工作或者将来的职业成长有意义。

其次,讲座最好做成系列,循序渐进,真正能够在结束的时候有一定的收获。流于形式是最可怕的。举例来说,讲js。可以先讲js能做什么,html5应用啊,nodejs游戏服务器啊,之类的。然后讲简单语法,接着讲john resig的adv教程,再讲一些实际的简单应用。最后上个实例,搞个demo的nodejs小游戏,就很靠谱了。

这里面是有很多方法论的。从大学里出来的人都知道,理论研究搞得好的教授不一定讲得好课。

4. 如何留住人才[Top]

这个话题水很深,专业的当然必须了解心理学等一系列的理论知识,才能有一个比较系统的分析,和针对公司现状的解决方案。我这里仅抛砖引玉,说点常识论(太多的公司在管理的时候连常识论都没顾及!),主要是马斯洛理论。

4.1 马斯洛理论[Top]

马斯洛理论,又称”基本需求层次理论”,是员工激励理论的代表之一,由心理学家马斯洛提出。分为5个层次,生理、安全、社交、尊重和自我实现。低层次的生理和安全这里就不说了,也没必要多说,这和公司的关系不大(应该都能满足)。

4.2 社交需求[Top]

集体感、归属感、爱。

员工不是机器的零件,公司也绝对不是机器。在作为企业的一员的时候,员工也对企业有所需求,最基本的就是要有归属感,具有作为组织一员的自豪感,能够对企业认同。

这和企业文化就很有关系了。企业要人性化管理,在合理的范围内尽量为员工着想。磨刀不误砍柴工,即便当员工是工具,是零件,你也得想着怎么让零件发挥最大效能是吧?

所以加班加到死,想怎么弄就怎么弄,完全不考虑员工想法的,这纯粹是封建皇帝的做派。私营企业的员工会用脚投票,而且在这种情况下离开的员工一般都有怨气,人员流动率一大,公司在业界上的名声就完蛋了,到最后不要说招募人才了,连正常招聘你都没法做了。

反之,如果能做到善待员工。有时也能听到:这家公司不错,人性化管理,氛围温馨,工资不高我也会考虑。类似这样的说法。不是么?

4.3 尊重需求[Top]

能力和成就得到承认,正确的评价。

这里关键的其实就5个字:“正确的评价”。

很难,真的很难。基本上工作到现在我没见过一家公司能做好,真的。但是这又很重要,为什么。很多时候你会听到员工的声音:没存在感,没成就感,做了东西上面的人完全没看到,看到了也当没看到。

一套完善的评价机制很有必要,无论是对公司来说,还是对员工来说。从公司的角度来看,没有评价机制,你就无法定位一位员工,在工作时间长了之后,你怎么决定升职、加薪?你怎么决定公司员工的梯队?怎么淘汰没用的低效员工?怎么知道公司现在缺少什么样的人才?没有评价机制,对于员工来说,也看不到自己的工作成就得到公司的认可。涨薪的时候,觉得涨少了也很正常;无法升职,问为什么也很正常。

在没有评价机制的情况下,公司环境就和中国现在的社会环境一样了。丛林法则,搞人际关系成了头等大事,因为没有评价,有人操作的地方只要靠人际关系,什么都能吹得出来。我跟你关系好,你帮我多加点钱,老板面前帮我多吹点好话。一旦形成这种氛围,必然又是一个良币驱逐劣币的过程,到时候你老板哭都来不及。

4.4 自我提升[Top]

将来的成长、抱负。

对于软件公司来说,这一项最容易理解,就是职业生涯上的提升。软件市场风云万千,新技术日新月异,能不能跟上节奏,是以后能不能在这个行业站得住脚,生存下去的关键。

这点我们刚才在人才的培养中也说到过了,这里略过。

4.5 双赢[Top]

马斯洛是一种很好的理论。抛开理论不谈,我个人觉得企业需要做好的事情其实很简单,概括起来就两个字“双赢”。

在企业允许的范围内,尽量给员工照顾、便利和培养,并用正确的方式、制度引导和规范员工的行为和工作。适当地给予激励,适当地给予压力。在最大化员工能力和积极性的情况下,提升员工的工作效率,来最大化其对公司的价值产出。

很简单,不是么?

5. 上层构造的重要性[Top]

上面说了那么多,其实都是厘清一些概念和普及一些常识。我不觉得我能力有多强,我能想到的,你必然也想到过,问题是能不能整理出来,然后更重要的是,能不能付诸行动,改变公司现状。

公司运营得好不好将来朝哪里走,不是看员工,而是看公司的“上层建筑”。包含了功能上划分出来的职能管理,人员上划分出来的人力资源管理,以及最重要的老板。没错,老板绝对是最重要的,私营企业,老板的企业,不是么?

P.S 所以,当达到到一定的level之后,跳槽里重要的一环就是要找老板聊聊。

5.1 职能管理的职责[Top]

一家公司,其实就和人体类似,各个部门各司其职,为公司提供各种各样的能力,使整个公司成为一体,完成产品制作盈利的目的。在这样的一个结构下,各部门(职能)的管理就显得异常重要,只有各个部门的管理人员都能将自身的部门管理好,公司才能平衡发展,真正跑起来。对一家公司来说,任何一个短板都是很致命的,就像一个破了一边的水桶一样,水永远只能储到破掉的那个高度。

举个例子,想想一家软件公司,假如技术能力不及格,会是怎么样一个惨状。(P.S 而且这还很常见,我供职过的几家公司里,超过一半的都有这样那样的技术问题。)企划再优秀,运营、销售再天才,东西做不出来也是枉然。

5.1.1 中层管理[Top]

从某种层面上来说,职能的中层管理其实还比职能部门的上层管理更重要。

举个简单的例子,就像军队打仗,中央司令部被炸掉了,部队没方向了,但是还不至于指挥不灵,手脚不健全,等后继的指挥官到了,该撤退的时候照样能顺利跑掉,不伤筋骨。但是如果军队里的中层指挥全部挂掉,你看看有上面的光杆司令还有用没用。别说大的战略指挥了,小的撤退命令都下不下去。神经都断光了,要大脑还有什么用,就一瘫痪货。

所以一家公司,中层管理的培养是至关重要的。再举个更贴切实际的例子,一家软件公司,技术领导完全没问题,公司的技术储备和技术素养都很靠谱。但是中间有断层,没有一批靠谱的中层管理,那请问谁来带项目?一家大点的公司十来个项目再正常不过,难道要技术职能的负责人一个个看过来?那不现实,精力有限。到后来,项目还是会出问题,无论技术如何成熟,无论流程如何规范,无论工具如何称手,使用的、实施的毕竟是人,没有适当的、真正花精力关注在项目上的中层管理,项目后来必定会偏离正轨。

即便现在没有没问题,只要有一套合理的招聘和培训机制,让一名合格的技术负责人带一个项目一段时间,自然而然就能培养出一两名员工,然后再慢慢地推广开来。

5.1.2 上层管理[Top]

上面说中层管理的时候,也说到了,“让一名合格的技术负责人带”。这就是职能部门的上层管理,负责人。这里就不多展开了,各职能部门的负责人要有,而且必须要有很强的能力,否则公司必然会在某方面出现短板,就必然翘脚,走不远。

一句话概括,无论公司如何pivot,如何改变战略、方向,只要是职能部门能力够强,能搞定。老板就能放心出手去做。

其实我这里很想吐槽很多很多的私营小公司老板,没那个金刚钻,你揽什么瓷器活啊。靠谱的人一个都没有,纯粹瞎扯淡,一通乱搞,最后解散,浪费金钱浪费时间,何必呢。下面的中层管理和执行人员大可以慢慢培养,没几个核心的选手还是别搞了,散了回家洗洗睡吧。

5.1.3 交流与沟通[Top]

职能管理无论是上层还是中层,都有一个非常重要的职责,就是负责倾听员工的声音,并层层向上反馈。一家公司,那么多员工,必然会有各种声音各种意见,不可能铁板一块(你洗脑洗的好,也必定会有没有完全照顾到的员工)。

秉持4.5我们讨论过的结论,你不能一概无视所有的声音,这样你的公司必然走不远。这个时候我们就需要一种管道,让整个公司的声音都让上面能听得到。职能管理就负责最先的一道关卡,倾听、安抚下属也是他们工作中非常重要的一环。

5.2 人事部门的职责[Top]

5.2.1 人事的职责[Top]

很多,不,其实我呆过的所有公司,人事都只是个打杂的。何谓打杂:做的事情很多,但是做好的事情很少。

人事其实是一家公司当中非常重要的职位。我们平时常说,有正确答案的科目简单,诸如数学、物理之流,对就是对,错就是错。而没有正确答案的就难上许多。放到一家公司里,就可以理解为,和人打交道的工种,就非常难做。这里主要就是指人事所负责的那些工作。

人事的职责是什么,其实非常非常多。我们平常理解中的人事职责,例如招聘、算薪酬、搞活动、营造公司文化,等等都属于人事的范畴。而平时我们不怎么关心的,像公司里的文具、物品管理、清洁等系列杂事,也属于人事的范畴。人事就是公司的管家。

好的人事和差的人事也存在非常大的差距,人才的效应在人事这个职责也存在。举例来说,负责招聘的人事。普通的只会在各种招聘网站上发布消息,平时打打猎头电话,要几个人,就这样。但是能力强的,就会在外面找比普通招聘网站更有效的管道来找人,比如说现在慢慢开始出名的互联网垂直招聘网站拉勾网,比如说使用人脉来找推荐、从行业顶尖公司挖人(开头就说了,推荐的效率比广撒网要来得高得多得多)。

基于人事其广泛的职责覆盖,在人事这个部门上,公司其实更需要靠谱的人才。

5.2.2 核心职责[Top]

5.2.2.1 招聘[Top]

招聘工作绝对是大众对于人事这个职业的第一个认识,而且就像我在这篇文章一开始说的那样,人才相关的工作都是[Top]优先级的,也就是招聘对于公司来说是非常重要的。而与需求相反,我见呆过的所有公司的招聘,基本上都是通过非常呆板的方式进行的,最常见的就是只看招聘网站,而没有其他任何更聪明的手段。

招聘是一门具有非常多技巧的技术,这里就不铺开说了。老板只需要知道一点,你非常需要一个能帮你解决“人才招聘”难题的攻关手!

  • 了解公司当前需要什么样的人才,并对所需求的人才素质有深入的了解(游戏公司一天到晚给我推荐只做过网站的程序员,要么就给我推各种游戏公司出来的不靠谱的人,而根本不知道公司需要什么样的人)
  • 会使用常见的招聘网站,并知道如何进行筛选(别给我推那么多只会做网站程序员)
  • 了解行业相关的垂直领域招聘工具(互联网:拉勾网)
  • 有靠谱的行业领域人脉关系(游戏行业相关的人脉网络),能了解必要的信息(谁谁谁正在裁员,谁谁谁待遇不行),抓住其他公司的弱点进行攻坚
  • 为人处世圆滑老道
5.2.2.2 人员管理[Top]

看过第四章就知道,一家公司要留住员工不是一件容易的事情,要做许多工作。在很多具体实施的方面,比如说培训、沟通、评价,是由公司中层的职能管理人员来进行。而人事负责的任务更重要,要负责制定公司整个评价、培训、激励制度的大框架,从理论依据(心理学等)出发,建立一个行之有效的管理体系。

5.2.2.3 文化建设[Top]

公司文化对于培养员工的归属感和认同感是非常重要的。人事部门应该建立一整套完善的洗脑手段,保证新进入的员工能很快认同、适应公司的环境和行为准则(前提是公司的文化是合理的)。并最大程度上激发员工的积极性,而不是通过使用行政手段来强迫员工行动(想想一下主动加班和强迫加班的差别)。

5.2.2.4 问题解决[Top]

一家公司在运营过程中,总会有各种各样的问题发生。人事部门应该建立一个收集、提交、解决问题的系统,来解决公司运营中的各种问题并优化公司的运营状况。

在这个工作中,最关键的是建立一个问题提交的通道,并保证提交上来的问题能够得到回应:

  • 设立一个公司公开邮箱,让员工提交问题:
    • 公开邮箱的访问权限只有限定的几个人能访问
    • 向公开邮箱提交问题的员工邮箱地址收件人应该看不到(匿名)
    • 保证所有被发上来的邮件有看,并有回复
    • 能根据提交的问题,真正进行有针对性的解决(表面有收有回的敷衍是找死)
  • 建立一个定期的1对1面谈计划,保证下层的员工和中层职能管理有定期的沟通,并保证其声音能最终达到上层管理,并得到解决

5.3 老板的职责[Top]

这里细节不多讲,很多地方都在前面有了详细的论述。主要是提几点思路。

5.3.1 找到对的人[Top]

开篇就说了人才的重要性,这里再提一下。老板一定要能找到靠谱的人,放到最适合这个人的位置上,特别是核心的几个位置。找不到的还不如早点关门大吉,因为拖下去关门也是早晚的事情。

5.3.2 做好激励工作[Top]

这个在第四章,特别是4.5的时候就说过了,要想走得好,就两个字“双赢”。总要求员工怎么怎么付出,而不站在员工的角度思考下,员工怎么有积极性干活?就算是骗也要骗起来。激励工作做好了,积极性调动起来了,自然生产力就上去了。口碑也好了,人才也进来了,人员流动也控制住了,不是很好么。

5.3.3 做好决定[Top]

老板第二重要的任务(第一位是找对的人)。无论是决定公司的发展方向,还是决定产品的研发方向,还是决定pivot的方向,还是决定要最终关闭项目。一切都是决定。有数据依据、有理论依据支持的快速决定,是经营一家公司所必须的一个技能。

5.3.4 放手[Top]

Boss之所以是boss,并不是让你什么都抓在手上。一个人的时间精力是有限的,在有限的时间里怎么把事情做好,怎么抓最需要你去抓的事情?这就是学问。我个人觉得当老板最好的状态就是招一帮靠谱的人,让他们负责帮你把事情都做好,你就在那边数钱就好了。

反过来也很容易看出一家公司的经营状况,一个老板什么事情都要插手,而且还没啥好结果的,那公司状况必然一塌糊涂。越是闲越说明你手下有靠谱的人才在帮你打理。就这个道理。

这个实在是有太多可以参考的经验了,网上找找硅谷知名企业的CEO是怎么样的一个工作流程,就能管中窥豹了。

6. 其他[Top]

6.1 聊聊加班[Top]

软件行业的公司,哪个没加班的?反正我是没见过。当然,也不是每家公司都把加班提升到事业高度的。有的公司能正确认识加班,有的公司则不能。因为加班这个事情关系到公司内员工的留存,认同感,企业文化,工作效率,等一系列和公司切身相关的问题,也因为这个事情的普遍性,我觉得有必要在这里聊下这个问题。

6.1.1 加班的分类[Top]

加班分为很多种,大致上我觉得能分为两种:有必要的加班和没必要的加班。举例来说:

  • 有必要的加班:公司产品研发正在一个非常关键的节点,有必要赶时间将产品功能抢在竞争对手之前上线,需要短期冲刺
  • 没必要的加班:老板感觉整个部门太闲了,你们给我加加班;产品研发计划一开始就是错误的,设定的目标永远是无法完成的

正确区分这两者非常重要,这指导了接下来的对应法则。

6.1.2 正确认识加班[Top]

加班的代价很高昂。主要有以下几点:

  • 效率并没有变高,研究表明,加班的结果并没有使产出提高,长期来说反而是倒退
    • 身心俱疲,反而正常的上班时间没效率了:
    • 10(效率/小时)* 8(小时)* 5(天) > 5(效率/小时)* 12(小时)* 6(天)
  • 摧毁员工,无论是心理上还是生理上。无法照顾家庭,无法休息,无法保持健康
  • 向员工灌输错误的公司文化,长此以往员工会选择离开,并散播不好的名声
  • 反而无法发现真正需要解决的问题(效率低下的症结在哪里?怎么使得公司长期的发展变健康?)。因为任务能完成,反而关键的问题没人关心了

我觉得其中最需要有清晰认识的是第3和第4点。

第3点致命在人才。通篇的核心就是人才,错误的企业文化和人员的流动会将人才赶到别的公司,而不是你的公司。

第4点致命在公司的核心价值上,当你选择用长时间的工作时间去取代思考的时候,事情将无法挽回。没人去思考问题在哪里,会导致公司失去解决问题的能力,最后就是完蛋大吉。当你最后无力支付长期高强度加班的代价的时候,公司就崩溃了。

6.1.3 如何解决[Top]

好了,认识了加班之后,我们要正确区分,并进行解决。开始的时候也说了,分类是有必要的加班和没必要的加班。

我们主要要分析、并解决导致没必要的加班的原因:

  • 人手不够:修正当前节点目标,或者减少工作量,并同时招人。不要搞到最后因为高强度加班,人反而走光了,偷鸡蚀米,不是么
  • 工期不正确:工作量和工期不匹配,本来就干不完。因为是没必要的加班,必然是因为无聊的理由导致了工作量和工期不匹配。修正工期,或者减少工作量
  • 技术有问题:不正确的工作方法、工作工具、技术负债,导致了工作效率上不去。这个时候最忌讳继续加班赶进度,必须把问题解决掉才能轻装上阵
  • 没有理由的加班:这个还需要多说么?管理层需要反省

这里举几个简单常见的例子,不要以为加班没什么大不了的。刚才也说过了,加班的代价是非常大的。需要正确认识加班,只有心态摆正了,才能找出问题,并解决这个不健康的状态。

7. 附录[Top]

7.1 扩展阅读[Top]

7.2 关于作者[Top]

10 2014

XhGui

真正掌握一种语言,在我理解上,关键并不在于你会不会用这种语言写代码,实现功能。而是能不能分析写出来的代码的运行状态,并找出其中的问题。这个时候,我们很需要工具来帮助我们来解析问题。一般来说,这种工具叫profiler。

1. XDebug

PHP的profiler工具我用过几个,最早的时候是xdebug,很知名的一个PHP扩展。其输出的结果,我们可以使用WinCacheGrind来解析,进行可视化分析。这种工作形式非常简洁便利,而且作为扩展安装,不需要对代码进行任何调整,可操作性很强。但是问题也很多:

  • xdebug无法按需求进行抽样、过滤性启动,即它无法真对某些特定的请求进行执行,也没办法抽样运行
  • 生成的结果只能输出成文件,合并上面一点,大家可以理解到,这个工具会对服务器IO造成多么大的压力,在真正的产品环境上
  • 观察工具非常呆板,而且只有windows版本,我之前为了在mac下进行解析,还费心从源码开始编译安装了一个开源工具,见《在MAC下如何图形profilePHP脚本》

总之,结论很简单,xdebug很难应用在真实的产品线上。

2. XHProf

作为世界最大且最知名的PHP语言使用者,facebook,当然也迫切地有profile PHP代码的需求。于是,facebook开源出了一个profile工具,这就是现在基本上成为PHP profile工具标配的XHProf。

和xdebug不同,虽然xhprof也是以扩展的形式安装在php上,但是其启动和产出结果是需要程序员主动调用函数来进行的,这就带来了灵活性。xhprof还有诸如消耗小等优点。

但事实上,世界上的事情没那么简单,xhprof也还是有问题。首当其中的一点就和xdebug相同,其输出的内容,作为一段字符串,必须由程序员编写代码进行持久化存储。其次,其周边支持程序和可视化的工具也不理想,基本上,除了核心的profile能力,xhprof没有做好周边的支持。于是大量的第三方开源工具就应运而生了。我们要做的是从中选择一款最适合的来使用。

3. Choose

我们简单分析下,作为一款profile,需要的功能点:

  • 轻量级,高效,使用简便(XHProf就很符合这点)
  • 能抽样进行分析,而不是全盘都分析
  • 能按条件启动分析
  • 能将分析结果进行持久化
  • 能有一个便利强大的GUI将分析结果展示出来
  • 能横向比较多个结果,解析其异同

这里我选的是xhgui,符合上面的所有需求。

4. XhGui

github主页:https://github.com/perftools/xhgui

简介:

A graphical interface for XHProf data built on MongoDB.

This tool requires that XHProf is installed, which is a PHP Extension that records and provides profiling data. XHGui (this tool) takes that information, saves it in MongoDB, and provides a convenient GUI for working with it.

4.1 安装

这工具安装的时候还遇到了不少问题,真心蛋痛,这里记录下。关键的问题在于composer这个PHP包管理工具,之前从来没用过。问题比较多。

在安装xhgui代码之前,首先先解决几个PHP扩展的依赖问题,按github上列的列表,安装下来,就应该没问题了。当然还有mongodb这个,记得要安装。

git clone https://github.com/perftools/xhgui.git

cd xhgui

php install.php

好,报错了:

#!/usr/bin/env php
Some settings on your machine make Composer unable to work properly.
Make sure that you fix the issues listed below and run this script again:

The detect_unicode setting must be disabled.
Add the following to the end of your `php.ini`:
detect_unicode = Off

A php.ini file does not exist. You will have to create one.
If you can not modify the ini file, you can also run `php -d option=value` to modify ini values on the fly. You can use -d multiple times.

怎么解决这里不多说了,简单来说,就是运行composer的PHP版本、PHP设置有问题,一般来说是PHP cgi和PHP cli版本不同造成的,至少我这里就是这个问题。

如果composer下载有问题的话,可以跳过install.php这个脚本,自己下载composer.phar,然后放到代码根目录就OK。

甚至实在不行,你可以根本不用install.php,使用你自己OK的那个PHP cli版本,运行这个命令:

php53 ./composer.phar update –prefer-dist

4.2 使用

PHP版本必须高于5.3,因为xhgui里用了不少lambda表达式。

官方推荐的使用方法是在php里设置auto_prepend_file这个选项,那么每个脚本在运行的时候,都会将xhgui的header.php代码插入进去。当然,如果你有自己的框架的话,你也可以选择自己进行整合,至少我就是这么做的。

在配置文件的 profiler.enable 这一项中,配置上启动判断条件的lambda函数,抽样分析和按条件分析就OK了。

配置文件的 save.handler 这一项决定了分析结果如何存储,写入mongodb,或者写成文件。注意,写成文件的分析结果,可以事后使用xhgui的import.php脚本导入到mongodb里。

此外就没什么别的需要注意的了,使用上来说还是很简单的。

4.3 GUI

简单截几个图,看下效果,基本上使用很简单,没什么需要特别说明的。

compare效果:

compare

profile效果1:

profile1

profile效果2:

profile2

26 2014

AngularJs route segment plugin

关于AngularJs

AngularJs确实是一个很方便的Web开发框架,基本上以前最头痛的MVC分层,AJAX回调,数据绑定,显示管理,等等等等,angular都帮你做好了。而且最逆天的一点是你只需要最基本的js知识就可以进行开发了,angular将需要的技能堆栈都埋在里面了,开发者只需要使用最angular暴露出来的接口就行了。当然,这篇文章不是用来歌颂angularjs多么好用的。在开发过程中,你还是会发现angular有很多不支持的功能点,这个时候就不得不借助开源社区的能量了,你总是能找到很多好用的插件。

我们遇到的问题

这里,我们需要解决的问题是:angular官方并不支持在route跳转的时候,不刷新页面进行跳转。这么说可能有点抽象,举例来说。试想一下,我们现在有个站点,有一个货物列表页面,其中货物分为大类、小类、物品本身这样的层次。而页面的布局则是:

  • 最上面的nav(在任何页面跳转发生时,你都不希望它们被刷新)
  • 左边第一栏,是货物大类列表,在页面刷新出来的时候从服务端取得该列表(在后续的分类及货物id变动跳转的时候,这部分不应该被刷新)
  • 左边第二栏,是货物小类列表,即物品id列表,在选中某个大类的时候,从服务端取得该列表(在货物id变动跳转的时候,这部分不应该被刷新)
  • 右边栏,具体的物品信息内容,在选中货物小类列表中的物品id的时候,从服务端获得并显示该页内容

针对这样的需求,angular官方只能完全刷新整个页面,而不能做到我们上述的需求。这个时候,我们需要第三方的插件辅助。

插件选择

综合下来,可选的插件主要有两款:

从行文标题就可以看出,我选择的是下者,angular-route-segment插件,理由我觉得segment插件作者网站上说的很清楚了:

While it seems that this library has very similar goal to what UI-Router provides, there are some important differences between their implementations, though.

UI-Router implements its own URL routing mechanics with its own “state” concept on top of it.angular-route-segment doesn’t try to replace something in AngularJS. It is based on built-in $route engine, so that it tries to extend it rather than to replace. $routeSegmentProvider.when method is just a shorthand to $routeProvider.when with the simplified syntax. Inner segment-handling logic is built on top of events propagated by $route service, with internal usage of some route params from it.

Such approach makes it possible to accomplish the desired nested routing task in more simpler manner, which produces less code, less complexity and potential bugs, provides better cohesion with Angular core engine and is easier to understand, use and debug.

我做选择的时候有两点标准:

  • 易学易懂:这点很重要,segment明显比较容易上手,基本上没有新的概念,只需要熟悉几个segment函数就可以上手了
  • 功能足够:不求万能全能,只要能满足需求就足够了

当然,segment也有缺点,在我写这篇文章的时候,segment只有225个start,且已经2个月没更新了,最新的版本只支持angular的1.2.x版本,angular最新的发展方向1.3还未有支持的动静。反观UI-Router,2501个star,13个小时前刚更新过。从支持上来说,无疑是UI-Router更好。AngularUI团队下的东西都不错,虽然这个UI-Router我不是很满意。

segment还有一个很致命的问题就是,作者在写tutorial的时候,并没有很系统地介绍使用方法和设计中的几个关键的点,导致使用的时候发现各种不可理解的状况的发生。我是下载了github上的源码,玩了example一阵之后才完全理解的。

segment的学习

类库引入和依赖注入

<script src="../build/angular-route-segment.min.js"></script>

或者使用requirejs,都可以。

在定义angular的app的时候,记得要进行依赖申明,这里必须记住一点,因为设计上segment是在angular route上的扩展,所以它是依赖于angular route插件的 。

var app = angular.module('app', ['ngRoute', 'route-segment', 'view-segment']);

简单使用

segment插件的使用分为两部分,一部分是和angular route差不多的app.config定义,另一部分则是页面上的directive使用。源代码也很清晰地分为了route-segment.js和view-segment.js两部分。

app.config举个例子来看:

app.config([
    "$routeProvider", "$routeSegmentProvider",
function($routeProvider, $routeSegmentProvider) {
    $routeSegmentProvider.options.autoLoadTemplates = true;
    $routeSegmentProvider.options.strictMode = true;
    $routeSegmentProvider.
        when("/item",                                     "item").
        when("/item/category/:categoryId",                "item.items").
        when("/item/category/:categoryId/item/:itemId",   "item.items.detail").
        when("/others",                                   "data").
        when("/others/data/:dataId",                      "data.detail").
        // ITEM
        segment("item", {
            "templateUrl": VIEW_URL + "item/home.html",
            "controller": "AppItemCtrl"
        }).
        within().
            segment("items", {
                "templateUrl":VIEW_URL + "item/items.html",
                "controller": "AppItemListModuleCtrl",
                "dependencies": ["categoryId"]
            }).
            within().
                segment("detail", {
                    "templateUrl": VIEW_URL + "item/detail.html",
                    "controller": "AppItemDetailCtrl",
                    "dependencies": ["itemId"]
                }).
        up().up().
        // DATA
        segment("data", { /* ... */ });
    $routeProvider.otherwise({redirectTo: "/item"});
}]);

这里的when语法和angular route的when不同,参数一都是path,但是参数二从route object换成了segment name,这里的segment名字需要小心,必须以“.”来分隔展现层次。比如说我刚才举的例子里的:“item”,“item.items”,“item.items.detail”。

segment函数则起到了之前when函数里route object定义的作用。dependencies很有用,表示的是path里的哪个/些参数变动的时候,该segment负责的展示区域会被刷新。

within是向下行走一个层级,up则是向上行走一个层级。

这里需要注意,作者并没有将otherwise继承到segment里去,所以需要定义otherwise的时候还必须注入原始的$routeProvider,这个真心无力吐槽。

directive很简单,在页面上写一句:

<div app-view-segment="0"></div>

就OK了。

这里需要理解app-view-segment属性中的0,到底是什么意思。这里的0表示的是0级的segment。在刚才给的例子中,“item”、“data”都属于0级的segment,而“item.items”、“data.detail”则是1级的segment,“item.items.detail”则属于2级的segment。

插件会在页面上的directive处,检查当前的path所对应的segment配置,如果层级相符合,则将template植入该directive处。

这里吐槽下,这么重要的功能点,在官方的文档中居然是没解释的,我拿下example搞了半天才明白过来。

范例分析

回到我们一开始定义的问题场景上来。我们分解开来看这个页面流程。

index页

首先我们需要主页的nav永远不需要被刷新,index本体结构也不需要被刷新。那么这里我们需要index.html和一个固定controller相搭配,这个controller负责的仅仅只是提供segment对象到scope里,判断nav的高亮。

<!DOCTYPE html>
<html lang="en">
    <head>
        <!-- ... -->
        <script type="application/javascript">
            function AppNavCtrl($scope, $routeSegment) {
                $scope.segment = $routeSegment;
            }
        </script>
    </head>
    <body>
        <div class="navbar navbar-inverse navbar-fixed-top" ng-controller="AppNavCtrl">
            <div class="container">
                <div class="navbar-header">
                    <a class="navbar-brand" href="#/item">仓储系统</a>
                </div>
                <div class="navbar-collapse collapse">
                    <ul class="nav navbar-nav">
                        <li ng-class="{active: segment.startsWith('item')}"><a href="#/item">物品列表</a></li>
                        <li ng-class="{active: segment.startsWith('data')}"><a href="#/data">物品数据</a></li>
                    </ul>
                </div>
            </div>
        </div>
 
        <div class="container">
            <div class="row" app-view-segment="0"></div>
        </div>
    </body>
</html>

这里为了演示方便,直接将首页的nav controller写在head里了,其实应该是和angular其他的controller放在同一个地方的。需要注意的地方有两点。

第一,segment中配置的path及其对应的controller,因为有route自动触发,所以不需要在HTML中写死,而nav的controller,因为在segment里没有配置(为了不被path更改而刷新),所以这里必须在nav的HTML上写上controller,以便在angular启动的时候给nav的scope传递segment对象。

第二,这里使用了segment.startWith方法,判断了页面的当前path是否应该在nav上高亮。

item主页 / 大分类

根据我们配置的segment:

...
when("/item", "item").
...
segment("item", {
    "templateUrl": VIEW_URL + "item/home.html",
    "controller": "AppItemCtrl"
}).
...

在item首页,我们会在directive app-view-segment=”0″ 的地方引入 “item/home.html” 这个template,并启动AppItemCtrl。这个controller会调用service,获取到物品的大分类,并展示在左边栏的第一列:

<div class="row">
    <div class="col-md-2">
        <!-- 这里负责显示物品大分类列表 -->
    </div>
    <div class="col-md-3" app-view-segment="1">
        <!-- 这里负责显示物品小分类 -->
    </div>
    <div class="col-md-7" app-view-segment="2">
        <!-- 这里负责显示物品细节 -->
    </div>
</div>
item小分类 / item列表

这里的controller负责获取当前物品大分类下的物品id列表,并进行展示。因为没有牵涉到结构性的部分,这里的controller代码和HTML代码就不需要展示了。

item细节

同上,这里的controller负责获得当前物品id所对应的物品细节,并进行展示。

这样,我们在一开始提出的angular原生不可解决问题,就已经完全解决了。

Bug

segment插件我用到现在有一个蛮大的bug,就是在配置了dependencies的segment,在url跳转的时候,即便segment的根节点已经完全不是当前segment了,只要path中的dependencies改变了,该segment还是会被触发。

举例来说:当前页面是:“/item/category/:categoryId/item/:itemId”,当离开这个页面的时候,即便我去的是“/data”这个完全不同的segment,item.items.detail这个segemnt还是会被触发。

鉴于segment插件已经2个月没有更新,且github上issues完全没有人理会的情况下,我也就没有去报这个bug了。

现在的解决方法是在有配置dependencies项的segment的controller里,进行

if (typeof $routeSegment.$routeParams.itemId === 'undefined') {
    return; // wrong route page
}

这样的检查。

19 2014

Ember.js

Ember.js也是最近相当热门的一款JavaScript框架。

官方定位:

A JavaScript framework for creating ambitious web applications.

官方网站:http://emberjs.com/

github:https://github.com/emberjs

中文社区:http://emberjs.cn/,其实就是官网的翻译

Tutorial:http://emberjs.com/guides/getting-started/

Ember.js使用的template engine是handlebars:http://handlebarsjs.com/

Conclusion

先来个结论好了,虽然我不想吐槽,不过Ember.js我是肯定不会用的。要问为什么,连tutorial都看不懂的框架要我怎么用。

问题很多:

  • 框架内的内部约定太多,不利于新手学习:
    • tutorial看不懂的最大原因就是这个,介绍步骤没有问题,文本描述也很到位,但是在没有先介绍框架的工作流程以及内部约定的情况下,各种默认规则导致看的时候总是有“为什么要这么写?”的疑问
    • controller、route之类的关键类里使用了大量的默认属性,在新手接触的时候非常不友好,tutorial看的时候一愣一愣的,根本不知道哪些是自己的哪些是默认的
  • 大量使用字符串进行绑定和解析,使用起来非常困难,而且还容易写错
  • 文档多,但是思路不清晰,内容一堆,看完我还是没理清楚Ember里的程序工作流程
  • 官方推荐的资源引入方法都是使用HTML的script标签,貌似没有简便的方法和RequireJs这种模块化工具集成,不利于制作大型项目和代码管理
  • 我很不喜欢Polymer和handlebars这种将HTML模板包含在script标签内的做法

虽然从MVC框架来说,结构很清晰,功能很强大,但我还是不推荐使用。

Core Components

18 2014

AngularJs

AngularJs是google出品的一款Js框架,功能非常强大。

首页:http://angularjs.org/

github:https://github.com/angular/angular.js

中文社区:http://angularjs.cn/tag/AngularJS

官方有给出Tutorial:http://code.angularjs.org/1.2.13/docs/tutorial/step_00

Angular和Backbone相比,复杂度上去了不止一个档次,功能也强大了不止一个档次,是一款纯正的MVC框架。我们接下来从程序的角度来分析下AngularJs的组成。

Sample Tutorial

在页面的HTML元素上(一般是div、body、html),添加ng-app这个自定义属性,该属性所属标签的HTML子集,将会被作为AngularJs应用进行解析。在ng-app下属的某个HTML元素上,添加ng-controller自定义属性,则该属性所属标签的HTML子集,就被定义为一个controller的scope。

在JavaScript代码中,需要创建相对应的controller AngularJs的module。

var phonecatApp = angular.module('phonecatApp', []);
phonecatApp.controller('PhoneListCtrl', function ($scope) {
  ...
});

然后在该controller的$scope内,绑定你的模型数据。

$scope.phones = [
  {'name': 'Nexus S',
   'snippet': 'Fast just got faster with Nexus S.',
   'age': 1},
  {'name': 'Motorola XOOM™ with Wi-Fi',
   'snippet': 'The Next, Next Generation tablet.',
   'age': 2},
  {'name': 'MOTOROLA XOOM™',
   'snippet': 'The Next, Next Generation tablet.',
   'age': 3}
];

最后在HTML页面上,使用带参数的模板代码进行展示。

<body ng-controller="PhoneListCtrl">
  <ul>
    <li ng-repeat="phone in phones">
      {{phone.name}}
      <p>{{phone.snippet}}</p>
    </li>
  </ul>
</body>

最简单的MVC的例子就是这样了。

Core Concepts

  • AngularJs的核心思想是扩展式的HTML
    • 使用ng-*这样的自定义HTML属性,Angular将框架功能直接附加到HTML上。
    • 附加有自定义属性的HTML将会有额外的功能。
  • 非标准化的、自定义的 JavaScript 接口和工具。
    • 几乎任何你在开发中使用到的功能点,AngularJs都有包含,你只需要学习AngularJs就可以了(真的么?)
    • 相对的,这也增加了AngularJs的学习曲线,需要学习的内容非常多。
  • 所有的核心代码都模块化
    • angular.module(‘phonecatServices’, ['ngResource']);
  • 强烈依赖于依赖注入、工厂模式。
  • 数据绑定使用的是 dirty checking
  • ng作用域
    • 附加有ng-app属性的HTML及其子集才会被AngularJs进行解析。
    • 附加有ng-controller属性的HTML及其子集才会被AngularJs作为controller的$scope附加功能,controller的$scope里的内容在HTML中可以直接访问、使用,即便是函数也一样。

Model

AngularJs里的数据模型和Backbone的理念差别很大。Backbone是需要程序员自己定义自己的模型,并维护一系列的get、set、save等函数。而AngularJs里的数据则仅仅只是存储在controller的$scope里的一个JavaScript Object,AngularJs会使用 dirty checking 来检测数据的变化,并触发对应的事件。并且在AngularJs里,数据绑定天生就是双向的。

Controller

Controller依然是做事情最多的地方,当然相对于Backbone将controller应该做的事情扔到Model和View里面还是好太多太多了。

View

AngularJs集成了自己的渲染引擎,使用起来非常便利,在诸多ng-*属性功能的支援下,能非常便利地渲染出HTML页面。并且也带有拆分、重用等功能。

Concerns

主要的问题有两点:

第 1 页,共 21 页12345...1020...最旧 »