可视化你的足迹

可视化你的足迹 数据可视化可以让读者以一种轻松的方式来消费数据,人类大脑在处理图形的速度是处理文本的66,000倍,这也是人们常常说的一图胜千言。在本文中,我们通过将日常中很容易收集到的数据,通过一系列的处理,并最终展现在地图上。这仅仅是GIS的一个很简单场景,但是我们可以看到,当空间数据和地图结合在一起时,可以在可视化上得到很好的效果,读者可以很容易从中获取信息。 我们在本文中会制作一个这样的地图,图中灰色的线是城市中的道路,小六边形表示照片拍摄地。颜色表示当时当地拍摄照片的密度,红色表示密集,黄色为稀疏。可以看到,我的活动区域主要集中在左下角,那是公司所在地和我的住处,:) 要展现数据,首先需要采集数据,不过这些已经在日常生活中被不自觉的被记录下来了: 数据来源 如果你开启了iPhone相机中的定位功能,拍照的时候,iPhone会自动把当前的地理信息写入到图片的元数据中,这样我们就可以使用这些数据来做进一步的分析了。 我在去年学习OpenLayers的时候已经玩过一些简单的足迹可视化,另外还有一篇全球地震信息的可视化,但是仅仅是展示矢量信息,并没有深入,而且都是一些前端的JavaScript的代码。最近又在重新整理之前的GIS知识,重新把这个作为例子来练手。当然,这次会涉及一些地图编辑,空间计算的内容。 我的照片一般都通过Mac自带的Photos管理(前身iPhoto),手机里照片会定期同步上去。老版本的iPhoto用的是XML文件来存储照片的EXIF数据,新的Photos的实现里,数据被存储在了好几个SQLite数据库文件中,不过问题不大,我们只需要写一点Ruby代码就可以将数据转化为标准格式,这里使用GeoJSON,GeoJSON既可以方便人类阅读,也可以很方便的导入到PostGIS或者直接在客户端展现。 实现步骤 我们现在要绘制照片拍摄的密度图,大概需要这样一些步骤: 抽取照片的EXIF信息(经度,纬度,创建时间等) 编写脚本将抽取出来的信息转换成通用格式(GeoJSON) 使用QGIS将这些点的集合导入为图层 插入一些由六边形组成的图层(设置合适的大小) 计算落在各个多边形中的点的个数,并生成新的图层heatmap 使用MapServer来渲染基本地图 数据抽取 Mac上的Photos会将照片的元数据存储在一个SQLite3格式的数据库中,文件名为Library.apdb,通常位于这个位置~/Pictures/Photos\ Library.photoslibrary/Database/apdb/Library.apdb。这个文件可以通过SQLite3的客户端直接打开,不过由于可能有其他进程(Mac自己的)打开了该文件,所以会有锁文件,你可能需要先将这个文件拷贝到另外一个位置。 然后将表RKVersion中的部分信息导出即可,SQLite内置了很方便的导出功能,通过它提供的shell客户端sqlite3,将信息导出到csv文件中: sqlite> .mode csv sqlite> .headers on sqlite> .output places-ive-been.csv sqlite> select datetime(imageDate+978307200, 'unixepoch', 'localtime') as imageDate, exifLatitude, exifLongitude from RKVersion where exifLatitude and exiflongitude; sqlite> .output stdout 注意这里的日期,苹果的日期偏移和其他公司不同,始于2001年1月1日,所以要在imageDate之后加上这个base值,然后将文件以.csv的格式导出到places-ive-been.csv中,该文件包含3列:时间,纬度,精度。 imageDate,exifLatitude,exifLongitude "2012-10-25 16:34:01",34.19216667,108.87316667 "2012-10-28 14:45:53",35.1795,109.9275 "2012-10-28 14:45:45",35.1795,109.9275 "2012-10-25 16:34:04",34.19216667,108.87316667 "2012-10-19 23:01:05",34.19833333,108.86733333 ... 转换为GeoJSON 方便以后的转换起见,我们将这个文件转换成GeoJSON(其实很多客户端工具可以支持CSV的导入,不过GeoJSON更为标准一些)。 require 'csv' require 'json' lines = CSV....

September 18, 2015 2 min

如何写一本书

我在过去的几年中,写了4本书。有传统意义上的两本实体书:《JavaScript核心概念及实践》和《轻量级Web应用开发》,还有两本电子书《3周3页面》和《函数式编程乐趣》。当然对我而言,主职工作是软件开发,写作是个副业。 在写作的过程中,有一些有趣的心得。 写作本身是一个很好的学习过程(至少是一个驱动你学习的动力) 写书非常枯燥,特别是校对的时候 写作不会让你变得富有,但是有时候会让你开心(不总是) 写文章 vs 写书 写博客/文章和写书还是有很大差别的,一个明显的差异是写文章会比较随意,而且应该尽量保持精简。一篇文章提供一些信息即可,应该尽量远离细节(如果写一篇教程,则另当别论)。而写书则应该尽可能的深入细节,尽可能可以让读者依书自修。 投入与回报 首先要明白的一点是,不要指望用写书来赚钱,至少前4本是这样的。粗略的算一下:我的第一本书卖了3000册,每卖一本我可以得到4元RMB,一共就是12,000元RMB。而这本书我断断续续写了三年。那是很多个周末,很多个假期,很多个夜晚的付出换来的,如果真正要计算投入产出比的话(纯粹金钱上),这显然是一个毫不合算的事情。 作为一个参考,IBM developerWorks的投稿,千字200元,一般写5,000字以内,也就是800元RMB左右。而要写一篇这样的文章,我只需要一天(当然需要数周/数月的积累)。12,000元RMB需要写15篇文章,如果每周写一篇,不到4个月就可以写完,而且写文章比写书容易多了,毕竟篇幅比较短小,易于校对。而且对于大部分开发者来说,固定在一个主题上的难度要比15个独立的主题简单的多,因为无需特别深入。 所以根据经验,要抱着公益的情怀来写书。也就是说为了让知识更好的分享,让你学习到的先进科学技术来帮助更多的开发者,提高他们的开发效率,让他们可以在周末多休息一天。而至于翻译技术书籍,那基本上就是免费的了,完全是一个公益活动(耗时数月,斟酌字句,推敲表达方式,但是价格极为低廉:千字60元RMB),所以下次见了技术书籍的译者,就多少给他捐点吧,他们才是在为人民服务。 知识的诅咒 “知识的诅咒”是指人们在获得了某种知识之后,就无法想象没有这种知识的情况了。这种现象随处可见,比如一个你到了一个从未去过的陌生城市,遇到以为当地人,然后向他问路。当地人觉得已经说的很清楚了,但是你还是不知道该怎么走。另一个例子是:假设你不认识泰文,然后你打开任何一本泰文写的小说,你只能依稀感觉到这是一种文字,除此之外你并不能从中获取任何的信息。但是当你学习了一段时间泰文之后,再来看这本小说,之前的那种感受就再也没有了。 写书的时候,你首先需要具备某种知识。但是写书的目的是将这些知识传递给那些不具备此知识的人,而根据“知识的诅咒”,你又无法确知那些初学者会遇到哪些问题!解决这个问题的方法就是找初学者来试读。而且为了保险起见,还应该找尽可能多的人来试读。 写作方式 一种方式是自下而上的,写一些独立的文章,最后发现可以串起来,然后形成一本书,另一种方式是自上而下,但是又会逐步调整。根据经验,不论是写一篇简单的博客,还是写一本书,都需要按照自上而下的方式。随心所欲的写下去,基本上都收不住,而且整个文章支离破碎,貌似有很多内容,但是不成章法,读者也无法轻松的获取知识。 先列出大的章节,然后逐步细化,但是未必是按照顺序来写。先编写自己最熟悉的部分,然后逐步完善。例子的选取需要精妙而恰当,最好有图例来说明。 配图制作 一般而言,我在书中会使用两种图:流程图和一些截屏。截屏通常使用Mac OSX自身的功能就已经足够,而流程图我会采用一些额外的工具如: graphviz keynote/sketch 用Graphviz画图的好处就是可以将图像代码一样放入版本库来管理。 除此之外,我还学习了一些设计软件的基本用法,事实上只需要用一些简单的元素就可以做出非常专业的配图: 字形/字体(大小,粗细的变化) 颜色(基本的配色理论就可以做出很舒服的配色) 层次(尺寸,位置,颜色的深浅) 阴影 代码格式 书中实例需要很多代码来说明,如果是制作电子书的话,可以使用Markdown预处理器自带的功能来高亮。另外如果需要RTF格式,可以使用这些工具: highlight工具 intelij中的插件copy on steriod 这里有一篇博客来说明如何将你的代码带着格式拷贝到剪贴板中,拷贝之后,就可以将这些内容粘贴到Word或者Keynote中了。 jest.dontMock('../components/headline.jsx'); describe('Headline', function() { var React = require('react/addons'); var Headline = require('../components/headline.jsx'); var TestUtils = React.addons.TestUtils; it('#render', function() { var text = "this is a title"; var headline = TestUtils....

August 4, 2015 1 min

如何将你的想法变为现实

说实话,这是一篇软文,为我的新书《轻量级Web应用开发》写的软文。如果你不想接着往下读,可以直接去这里买一本来看,:) 之过去的几年中,我参加过好多次Hackday活动。每次看到在为期两天的时间里,2-3个人将一个想法变成现实,都会有一种强烈的成就感。而且这个Hack的过程中,会重拾编程的乐趣,大家的积极性都非常高,用着各种有趣的技术(大数据,开源硬件,Node.js,GIS系统),逐步的将模糊的想法,变成现实,并最终为客户带来价值。最新的一次在这里 通过这些Hackday的经历,以及在众多项目中的经验,我总结了一些轻量级的方法/实践。这些方法/实践非常容易落地,并且久经验证。在很多项目中已经在不断的使用。它们可以帮你更好的将一个想法变成现实,并且在随后的开发中还可以继续发挥作用而不至失效(测试,构建脚本,自动化部署等等)。我希望你可以在自己的项目中尝试这些方法/实践,也希望这些方法/实践可以真正的帮助你和你的项目取得成功。 细化你的“点子” 根据一个已有的产品来参考,演绎,并形成自己的产品并非难事,而创新则是一件非常困难的事情,因为你需要“无中生有”。在ThoughtWorks,我们有这样一些步骤可以帮助客户来梳理信息,并最终交付产品,简而言之,可以归结为这样几个步骤: Discovery(用户研究,探索) Define(归纳洞见,发现) Design(原型设计,验证) Delivery(制定计划,实施) 上图是一个“点子”的原型(一个交换技能的应用,用户可以教别人自己擅长的技能,作为交换,也可以从别人那里学习心得技能),原型事实上是第三步的产物。我们通过一些调查(口头采访,或者问卷调查)得到一些基本的信息,然后归纳这些信息,并和真实用户再次确认,得到一个概念。有了概念,再来设计一个基本的原型,这个原型还可以迭代数次,然后进入下一个阶段。 前三个阶段更多的是用户体验设计师,以及客户的业务人员参与的。在前三步完成之后,进入实施的时候,软件工程师开始投入。这篇文章更关注**第四步(Delivery)**中的各种实践,通过这些实践,我们可以很好的完成交付计划,使得我们的好想法最终可以变成为用户提供服务的产品。 实现“点子”的方法 在软件领域,将一个想法变成实际的产品需要经历若干个阶段。按照传统的软件开发方式,会有前期的调研,需求分析,概要设计,详细设计,编码实现,测试,发布等一系列的流程。这种方式对每个阶段的定义都非常明确,而且每个阶段需要依赖前一个阶段的输出,因此往往被称为“瀑布模型”。后来慢慢发现,这个模型的反馈周期太长,一个软件从调研到发布往往需要数年,当发布之后,可能市场早已经沧海桑田。人们后来发明了更加符合现代市场需求的“敏捷开发”,在敏捷中,更加强调短平快的将需求变为产品。 简而言之,敏捷开发更强调: 快速发布 渐进增强 小步迭代 而在敏捷开发的继承者精益中,这几点理念也被更进一步的深化。由于没有办法预见未来,我们只能用一种边做边看的方式来验证想法。简而言之,就是先根据经验和调查,做出一个合理的推断,然后定义好范围,构想出一个最小可行产品(MVP),这个MVP的功能非常内聚,非常紧凑,我们需要尽可能快的让其上线,并被真是的用户使用,测试。根据这些用户的反馈,我们会做一些调整,比如去掉那些很少人使用的功能,聚焦在用户喜欢的功能上;从用户的实际使用中,调整界面元素的位置,子功能的入口等等。这个过程会持续多轮,最后的结果会是一个有真是用户使用,并且比较贴近真实需求的产品。当然这还不够,我们需要不断的打磨,渐进式的增强产品的功能,逐步完善功能等。 有一个非常形象的图,可以看出瀑布模型和敏捷开发两种方法的对比: 敏捷开发通过逐步细化,迭代前进的方式,分阶段的将需求实现,在整个过程中,更容易做到快速调整。 所有的这些过程,都非常依赖“快速”这个关键点。如果MVP花了3周就产生了,但是为了让其上线,你花费了1个月,那么很可能这个MVP已经过时了;如果你确实快速的将MVP发布了,在得到了用户的很多反馈之后,花费1个月来实现这些反馈,又会让你落在竞争对手之后;如果快速的发布了多次,并且幸运的是,你的用户量变多了,如果花费很长时间来调整架构,则可能失去当前的市场窗口。也就是说,你需要非常快速地对变化做出反应! 轻量级的开发方式 开发中的三个重点 在工程实践中,我认为有三个特别需要注意重要的点,这三点可以极大程度的改善项目现状,提高效率,并使得产品的高质量交付成为可能,它们分别是: 自动化(自动化一切) 质量内嵌(defect的数量,是否真正满足了需求) 代码本身的质量(可读性,可维护性,可扩展性) 自动化包括,自动provision,自动部署,自动化测试,自动打包等等。这是提高团队开发效率的必要工具。比如书中提到的grunt/gulp脚本,jasmine/rspec/capybara测试,部署脚本,vagrant/Chef等,都是关于如何将日常开发中的任务尽可能的自动化。 软件没有Bug当然是所有人都追求的,我们有很多中方式来保证代码质量。而在编写产品代码的同时,写大量的自动化测试,是投入产出比最高的一种了。通过单元测试,集成测试,以及一些有限但是关键的UI测试,我们可以覆盖很多的需求,而将这些测试自动化起来之后,可以节省大量的开发/测试成本,并减少回归测试的代价。 要支撑快速的发布,我们需要一系列的技术实践。这些技术包括环境的搭建,框架的使用,代码的编写,产品的发布;而且包括后台的数据库设计,业务代码,同样还有前端的展现等。 何为轻量级? 在《轻量级Web应用开发》中,我介绍了一系列的实践/工具,这些实践/工具贯穿整个软件开发的生命周期,使得敏捷开发/精益的开发方式变得可以“落地”。比如如何使用轻量级的开发框架来搭建API原型,如何将应用发布在免费的云平台上,如何通过虚拟化技术快速搭建开发环境,从而节省环境配置的投入,如何快速平滑的发布,如何使用测试先行的方式来保证代码质量,如何做高效的自动化UI测试等等。 轻量级Web框架 前端开发流程 构建工具 环境自动化(开发环境的搭建,CI服务器的搭建) 自动化部署 UI测试 实例驱动(书中有很多的实例,也有很多从项目中总结出来的实践) 这是一本主要关注开发实践的书,书中通过很多实际的例子来帮助读者建立一套完整,高效,轻量级的开发方式,这些方式可以直接在你的下一个项目中使用。甚至如果项目的技术栈变成了另外一种语言,你也可以迅速找到同类的替代品。比如rake之于gradle,sinatra至于spring-mvc等等。 每个组件都是可以替换掉的,比如ORM,如果你觉得DataMapper无法满足实际需要,那么可以换成ActiveRecord。如果Rails太重,使用Sinatra或者Grape或许是一个更好的选择。AngularJS包含了太多东西,Backbone.js或许适合你的场景,而也未尝不可以用Riot.js来替换掉Backbone中的view层。 在本地,可以将应用部署到一个vagrant+chef来provision的环境中,而通过部署自动化,这个动作可以很容易的在AWS的云上实现。轻量级的开发方式,帮助你用最小的代价来替换系统中的任意一个组件,因为每个组件在一开始都是按照可替换原则选用的。 另一方面,轻量级的另一个意思是:现发布静态的版本,然后再将内容替换为动态版本。发布一个静态的页面非常容易,具体细节可以参考这篇文章。当需要动态内容是,免费版的Heroku是一个触手可得的选择,AWS则是一个更加专业的选择(各种服务都配置完善,你只需要关注自己的应用部署即可)。

August 2, 2015 1 min

PM是大傻逼吗?

一些背景故事 坊间流传着很多关于PM(Project Manager,项目经理)的笑话,在这些不无刻薄的笑话中,PM往往被描述成一个盲目的承诺客户需求变更,不了解实际情况而又喜欢指手画脚的专门坑开发的家伙。毋庸置疑,这些笑话当然是那些聪明的开发发明的(不过你得承认,在很多团队,这些笑话其实是实实在在每天都在发生着的)。 在智力工作中,对于开发的实际进度,开发速率等问题,具体着手做的人永远比在背后指手画脚的人更有发言权。软件开发正是一项智力活动,优秀的软件无法通过人力的堆积而产生。一个关于PM的经典的讽刺是:PM就是那些指望着9个女人在1个月内生出1个小孩的二货。从传统的意义上来说,这个笑话还真是一针见血。 我记得在加入ThoughtWorks不久的时候,私底下经常听到这种论调:PM基本就是项目上被人鄙视(当然大家不会表现的那么明显就是了)的角色,基本上负责团队建设去哪儿这种杂事儿就行了,团队的其他人员可以高度自治,并不需要被管理,项目就会如预期般按时交付。 这些论调在某些情况下可能是对的。但是如果在国内项目的这个上下文里,没有一个专业的PM来协助项目,控制需求,划定项目范围,与客户谈判等等,没有任何一个项目是可以真正成功交付的,指望高度自治的开发们来完成项目?咱们还是现实一些吧。 一个悲剧的事实是,开发人员往往都恃才傲物,有时还会带着一幅要来拯救世界的心态来做项目,这事实上和客户的期望,以及PM的期望是有很大出入的。在项目启动之初,PM会面临重重困难:首先,团队里的每个人都不好管,而且每个人都认为自己不需要被管理(当然这种想法在大部分时候都是错误的);其次,PM需要和客户快速建立信任,并推动项目进入正轨;最后,往往留给PM自己的时间也非常有限,他们也需要学习大量的项目相关的上下文(业务上下文,人员关系,资源协调等)。 除了催进度,PM平时还干点啥? 本质上开说,PM其实就是一个轮询器:识别所有的项目风险,然后不断跟进。项目风险可能是技术风险,比如某个技术上压根搞不定的问题。也可能资源风险,比如人手不够,或者开发者很多,但是没有足够的设计师协助,这些风险都会导致项目无法按照时间交付。一个客观事实是,所有项目都会变化,做完售前到需求分析结束之后,需求可能会发生巨大变化,如果还按照报价来做项目很可能会亏本。 PM的一个重要职责就是在项目之初将项目范围定下来,这个范围的划分非常依赖经验:划得少了团队得天天加班,累得跟狗一样,然后才能保证交付(据我的经验,虽然项目一般不会天天加班,但是总会有一些攻关,打补丁的事儿,最后还是会累成狗),划得多了客户不买单,意思是就这个小功能你要做两个月,绝对不行。PM需要协调这些不一致,还需要和销售,客户等方面不断谈判,写方案,排计划,简而言之,也是累跟狗一样(而且潜在的,还可能被那些天真幼稚的开发坑 — 开发经常会高估自己的开发速度,反正我还没遇到过低估的,你见过吗?)。 我们每天看到的PM干的最多的事情就是:元芳,那个接口怎么样了?什么时候能做完,有什么blocker?李柯,昨天说的代理的事情怎么样了?小波,高保真什么时候出?何方,我们周三下午要showcase,麻烦你订一下会议室吧…… 除了写代码,Dev平时还干点啥? 如果脱离开PM的角度,做为一个孤傲的开发,时常会觉得PM为什么老是问我进度,是不是怀疑我的能力?为什么监视我的工作?相信我,其实他才不想监视你。但是你设想一下:如果你不参与代码编写,每天只是看旁边的哥们写,你如何知道他实际的进度呢?而且众所周知,开发很难准确的更新自己的工作进度,而且遇到问题也很少积极主动的报告,通常都会自己埋头尝试解决。那么,轮询显然是一种成本最低,反馈最快的方法。 不主动更新进度是另外一个大问题,不过这个得单独说。关于更新进度,典型的的场景是:早上站会的时候,开发目光呆滞的盯着某个卡片,努力回忆其中的验收条件以及自己的当前进度,如果恰好脑海中的技术细节和卡片的描述在某个点上匹配了,他会迅速的告诉你,目前进展良好,今天上午应该就可以做完。开发在更新进度时,不是盲目乐观,就是跳进太细节的地方进行讨论,最后讨论的结果就是:跟没更新一样,除了浪费了10分钟时间。但是别忘了,PM会在15分钟之后再来轮询一次。 PM每周都需要汇总很多数字,比如本迭代完成的点数,剩余的点数,总体进度如何,有没有人有请假计划,遇到什么blocker,每个blocker的具体原因,每个风险点的最终日期是何时,等等等等。他肯定不能记住这些数字,所以可能一天之内向你询问数次。 PM的其他职责/技能 上边说到的其实只是描述PM的辛苦,而最微妙,最考验PM的是其“察言观色”的技能。这绝对是一个工作经验在10年之内完全无法获得的技能(而且是在中国的项目上工作10年)。比如,在showcase的时候,有个客户说,嗯,挺好,整个流程就是这样的,后续你们的UI是不是还会美化?如果你遇到这个情况,请问,这个客户是什么意思? 如果你能回答上这个问题(而不是提出问题),那说明你还离PM差十万八千里。成熟的PM会先判断,问这个问题的人是什么角色,以及他在系统中的话语权如何,还有其他人就此问题的反应如何等等因素,然后找到一个合适的答案。 PM另一个绝技是扯皮(不是贬义),开发会花一个下午(我是说10分钟)去跟客户讨论需求的范围吗?或者会为5个人天来讨价还价吗?我想开发大概会说,尼玛,找其他供应商吧,老子不伺候了。 一个项目的成功,需要多方合作,这里说的合作并不局限在甲方和乙方之间,即使乙方的团队之中,也需要很紧密的合作。比如项目经理和开发,设计师之间的合作。如果仅仅从开发的角度来看,PM有时候看起来就是和客户站在一起来整开发的一样,比如催进度,过分保守的估算人天(导致团队加班赶工)。PM需要释放团队中的负面情绪,保证团队士气,还需要他做一些开发不屑于做的琐碎的事情。 设身处地,替他人着想 本质来来说,每个项目都是一次生意。在去掉那些繁杂的流程和形式之后,做一个项目和你去菜市场买菜其实并无二致。举个例子,根据传统,软件开发界特别喜欢找建筑行业做类比,我也找个建筑方面例子。装修房子的时候,我们会要求施工方提供图纸(水电改造,基本设计等),按期交付(确定工期),同时会界定项目范围(比如刷墙,贴地砖,吊顶,封阳台等等),会要求工人按时来上班,正常出勤,认真工作,直到项目结束。过程中我们还会讨价还价,比如捎带着把栏杆拆除,捎带着敲掉一面隔离墙等等。在过程中,我们还会敲敲地砖,检查过门石,检查吊顶,测试水电等等。作为甲方,这些活动相信没有人会觉得过分。 但是一旦我们做乙方,也就是施工方的时候,情况就全变了。比如客户要求打卡,有人会觉得不爽,客户要求代码review,有人会觉得不爽,要求代码有设计文档,有人会觉得不爽,要求设计有多个备选方案,有人会觉得不爽。大多数情况下,这都是虚无缥缈的虚荣在作祟,这种情况所在多有,不过还不致命。一旦涉及到讨价还价(不是商务上的讨价还价,而是和客户就工作量达不成一致,或者就某个技术方案达不成一致之后),开发全部歇菜,一言不合,转身就走,压根不具备讨价换件的能力,这样还怎么做生意啊?设身处地想一下,如果你是甲方,当提出了一些合理的要求(比如需要一方提供验收标准,通过验收测试等),结果施工方还一脸的“我不跟你说了,你就是以大傻B”,你能乐意吗? 如何合作? 说了这么多,这两种角色在同一个项目上要如何合作呢?我想,作为开发来说,有这样几点可能: 首先,理解PM的工作。在很多时候,开发会有莫名其妙的优越感(其实每个角色都会有了,比如销售看不上技术人员,技术Lead看不上PM等等),主要原因其实是坐井观天,对其他角色的辛苦和工作不清楚。然后错误的认为别人的工作都很low。 之前听一个同事讲过一个小session,里面有一点我印象非常深刻:不要因为一个人不会某个技术而鄙视他。就好比你不应该因为不会弹钢琴,而被一个会弹钢琴的人鄙视一样。道理很简单,但是开发在长期的“宅”生涯或者坐井观天中,进化出了这种非理性的观点:如果一个人连vim(此处的vim可以换成任何其他技术)都不会,就压根不足以谈人生。 其次,学习如何报告进度。PM催你的根本原因是进度不明确,如果每一个潜在的风险都清楚的显示着进度,而且有明确的负责人,PM就会降低轮询的频率。这需要开发经过刻苦的练习才能达到: 站会前自己花3分钟整理一下昨天做的工作 根据story的验收条件(最好有和BA/QA一起的讨论需求),进行合理的任务划分(tasking技能) 可以借助便签纸等工具,帮助自己明确进度(划分了5个子任务,昨天完成了3个,那么可以粗略的估计为60%) 再次,合理估算。有些时候,新人(来自于传统管理环境的新人)可能会误以为PM是一个管理的角色,或者处于某些考虑会在PM询问进度时做出一些错误的回答。比如PM在迭代启动会议上是问这个迭代我们有没有可能做完所有计划内的任务,作为一个负责任的开发,你需要在第一时间指出那些“非理性”的期望,以便PM进行更加准确的计划。 明确告诉PM,有哪些需求是不可能按时交付的,PM会根据实际情况来重新定计划,并和客户确认 明确告诉PM一些可能的风险,团队整体对交付负责,而不是PM,或者开发 按照经验,项目从来就不会按照计划进行,在做好一个粗略的计划之后,PM的职责更多的是进行动态调整。所以团队内部至少需要保持信息的流通,虽然可能短期来看可能会影响开发速度,但是从整体上来看,可以减少很多不必要的浪费。 简而言之,要站在别人的角度考虑问题:如果换做是你,你会怎么做?

July 7, 2015 1 min

前后端分离了,然后呢

前言 前后端分离已经是业界所共识的一种开发/部署模式了。所谓的前后端分离,并不是传统行业中的按部门划分,一部分人纯做前端(HTML/CSS/JavaScript/Flex),另一部分人纯做后端,因为这种方式是不工作的:比如很多团队采取了后端的模板技术(JSP, FreeMarker, ERB等等),前端的开发和调试需要一个后台Web容器的支持,从而无法做到真正的分离(更不用提在部署的时候,由于动态内容和静态内容混在一起,当设计动态静态分流的时候,处理起来非常麻烦)。关于前后端开发的另一个讨论可以参考这里。 即使通过API来解耦前端和后端开发过程,前后端通过RESTFul的接口来通信,前端的静态内容和后端的动态计算分别开发,分别部署,集成仍然是一个绕不开的问题 — 前端/后端的应用都可以独立的运行,但是集成起来却不工作。我们需要花费大量的精力来调试,直到上线前仍然没有人有信心所有的接口都是工作的。 一点背景 一个典型的Web应用的布局看起来是这样的: 前后端都各自有自己的开发流程,构建工具,测试集合等等。前后端仅仅通过接口来编程,这个接口可能是JSON格式的RESTFul的接口,也可能是XML的,重点是后台只负责数据的提供和计算,而完全不处理展现。而前端则负责拿到数据,组织数据并展现的工作。这样结构清晰,关注点分离,前后端会变得相对独立并松耦合。 上述的场景还是比较理想,我们事实上在实际环境中会有非常复杂的场景,比如异构的网络,异构的操作系统等等: 在实际的场景中,后端可能还会更复杂,比如用C语言做数据采集,然后通过Java整合到一个数据仓库,然后该数据仓库又有一层Web Service,最后若干个这样的Web Service又被一个Ruby的聚合Service整合在一起返回给前端。在这样一个复杂的系统中,后台任意端点的失败都可能阻塞前端的开发流程,因此我们会采用mock的方式来解决这个问题: 这个mock服务器可以启动一个简单的HTTP服务器,然后将一些静态的内容serve出来,以供前端代码使用。这样的好处很多: 前后端开发相对独立 后端的进度不会影响前端开发 启动速度更快 前后端都可以使用自己熟悉的技术栈(让前端的学maven,让后端的用gulp都会很不顺手) 但是当集成依然是一个令人头疼的难题。我们往往在集成的时候才发现,本来协商的数据结构变了:deliveryAddress字段本来是一个字符串,现在变成数组了(业务发生了变更,系统现在可以支持多个快递地址);price字段变成字符串,协商的时候是number;用户邮箱地址多了一个层级等等。这些变动在所难免,而且时有发生,这会花费大量的调试时间和集成时间,更别提修改之后的回归测试了。 所以仅仅使用一个静态服务器,然后提供mock数据是远远不够的。我们需要的mock应该还能做到: 前端依赖指定格式的mock数据来进行UI开发 前端的开发和测试都基于这些mock数据 后端产生指定格式的mock数据 后端需要测试来确保生成的mock数据正是前端需要的 简而言之,我们需要商定一些契约,并将这些契约作为可以被测试的中间格式。然后前后端都需要有测试来使用这些契约。一旦契约发生变化,则另一方的测试会失败,这样就会驱动双方协商,并降低集成时的浪费。 一个实际的场景是:前端发现已有的某个契约中,缺少了一个address的字段,于是就在契约中添加了该字段。然后在UI上将这个字段正确的展现了(当然还设置了字体,字号,颜色等等)。但是后台生成该契约的服务并没有感知到这一变化,当运行生成契约部分测试(后台)时,测试会失败了 — 因为它并没有生成这个字段。于是后端工程师就找前端来商量,了解业务逻辑之后,他会修改代码,并保证测试通过。这样,当集成的时候,就不会出现UI上少了一个字段,但是谁也不知道是前端问题,后端问题,还是数据库问题等。 而且实际的项目中,往往都是多个页面,多个API,多个版本,多个团队同时进行开发,这样的契约会降低非常多的调试时间,使得集成相对平滑。 在实践中,契约可以定义为一个JSON文件,或者一个XML的payload。只需要保证前后端共享同一个契约集合来做测试,那么集成工作就会从中受益。一个最简单的形式是:提供一些静态的mock文件,而前端所有发往后台的请求都被某种机制拦截,并转换成对该静态资源的请求。 moco,基于Java wiremock,基于Java sinatra,基于Ruby 看到sinatra被列在这里,可能熟悉Ruby的人会反对:它可是一个后端全功能的的程序库啊。之所以列它在这里,是因为sinatra提供了一套简洁优美的DSL,这个DSL非常契合Web语言,我找不到更漂亮的方式来使得这个mock server更加易读,所以就采用了它。 一个例子 我们以这个应用为示例,来说明如何在前后端分离之后,保证代码的质量,并降低集成的成本。这个应用场景很简单:所有人都可以看到一个条目列表,每个登陆用户都可以选择自己喜欢的条目,并为之加星。加星之后的条目会保存到用户自己的个人中心中。用户界面看起来是这样的: 不过为了专注在我们的中心上,我去掉了诸如登陆,个人中心之类的页面,假设你是一个已登录用户,然后我们来看看如何编写测试。 前端开发 根据通常的做法,前后端分离之后,我们很容易mock一些数据来自己测试: [ { "id": 1, "url": "http://abruzzi.github.com/2015/03/list-comprehension-in-python/", "title": "Python中的 list comprehension 以及 generator", "publicDate": "2015年3月20日" }, { "id": 2, "url": "http://abruzzi.github.com/2015/03/build-monitor-script-based-on-inotify/", "title": "使用inotify/fswatch构建自动监控脚本", "publicDate": "2015年2月1日" }, { "id": 3, "url": "http://abruzzi....

June 22, 2015 2 min