成长,就是持续创造价值

我时不时会收到一些小朋友们的私信,问是否招实习生或者「程序员学徒」的,可以不要薪水。我一般回复「没有」,就不再多说什么了。并不是我高冷,而是觉得这样的小朋友恐怕并没有什么潜力值得去挖掘。
这么冷酷的结论,并不是拍脑门想出来的。经历了多次打脸,我最终明白一个道理——如果一个人把「廉价」甚至「不要工资」作为核心竞争力,那么他不仅对自己没有信心,其实也不会有任何主动性去发展自身。他们只期待一个武林高手从一招一式开始教起,像妈妈带娃一样照顾始终,而自己只需负责饭来张口即可,希望在人畜无害的气氛中,无能的成长起来。
显然这是做梦。即便这样一位「程序员学徒」不要工资,其他人为了培养他而投入的巨大精力和时间难道不值钱?武林高手有这个时间干点什么不好,不能去争一争武林至尊吗?为什么要把时间浪费在一个连学习知识技能都需要他人喂食的巨婴身上呢?这些幻想成为「程序员学徒」的小朋友明显算错了数,他们以为「不要工资」是自己的巨大优势,实际上这样的人带来的往往是负价值,对团队和项目都有巨大损害。
举一个我自己的例子。我曾经在一个水平相当低的工程师身上耗费了近半年时间,从 Google 搜索引擎和 stackoverflow 的用法,到代码规范,到 Python 各个标准库的用法,再到各类 Pythonic 代码的写法。之所以耗费这么大精力,是因为我是一个不错的老师,能把很多道理讲的深入浅出(例如我可以在 1 分钟时间里让任意一个无技术背景的人理解金融量化交易引擎的技术原理),经过我的细致培训,他一定有机会成为一个代码细腻而简洁的工程师。
直到被我劝退前,他都一直在用百度搜中文关键词并跳转到 CSDN 上看技术文。
这是什么概念呢?就是一个数学老师教了你半年的二项式展开,最终面对最简单的二项式题,你依然在掰手指数数。
这样的程序员带给同事的往往是噩梦。在他离职之后,我们依然时不时的从他代码中发现骇人的 bug,然而数据已经被污染,重新修正几乎不可能。由他引入的问题,很有可能直到公司破产都不会有人愿意去解决。这样巨大的负担,当年的我如果更成熟一点,是万万不会惹祸上身的。所以现在收到各类的「不要工资」的申请,心里都会默默的想,「你当我是傻子么」。
每个人都渴望成长,但成长不是商品,不是你用「不要工资」就能够换回来的。成长源于你一步一个脚印的学习,在学习过程中,你又创造出了价值。本质上,只有当你持续创造价值的时候,你才会成长;而不是反过来。
如果你技术不好、没公司要你,能否在力所能及的范围内,对开源社区做一点贡献?
如果你技术不好,能否仔细研究业务代码,试着花一个月甚至两个月的时间写一个简单但核心的模块?
如果你技术不好、又想找个老师,能否先帮这个老师做一点事情、哪怕只是帮他写单元测试?
……
可做的事情太多了,简直数都数不过来,而它们的共同点就是——持续创造价值,而不是持续索取关照。
所以,当我们对一件事情有了强烈的渴求时,最好先问问自己,能不能用已有的技能先创造一些价值出来。如果不能,说明你其实并没有那么渴求。那么,请不要再去骚扰那些工作量已经很饱和的工程师了,码农滞销,可怜可怜老乡们吧。

Tagged : / / /

技术部门团队管理的一点心得

最近半年公司一直在对整体业务后端数据存储做大修改,由我负责开发核心的数据存储、拉取组件,这个组件以 gRPC 为协议,完全重构了早先的 Java 业务,即将部署到公司线上产品以及机构产品。除了数据存储拉取以外,其他组件之间也统一使用 gRPC 协议,这种情况下,需要一个简单易用的 gRPC 接口测试框架对各个接口进行压力测试。
而此时,我刚开始管理公司的测试开发团队,团队的常规任务是完成开发团队的测试需求,但最重要的任务是为开发团队提供简单易用的测试工具。总的来说,更偏重于开发而非测试。因此近期测试开发团队的最重要任务就是搭建一个上述框架出来,保障即将上线的新产品顺利交付。
目前团队只有我和另一个新入职的测试工程师(正在招聘手工测试员一名)共二人,由于测试工程师并无开发经验,刚开始上手开发有一些障碍,因此对稍微复杂的开发任务表现出无力感。
在这种情况下,团队管理出现几个挑战:

1. 新入职员工对工作内容不熟悉、以及技术上有欠缺,无法独力完成项目
2. 团队人数较少时,人事关系容易出现扭曲,表现为团队负责人与成员过于亲密或过于疏远,这两种情况都会伤害团队未来的发展。
3. 新成立的部门往往被委以重任,甫一成立就会面对攻坚战类型的技术难题,而此时恰恰是作为新生儿的团队最脆弱的时候。

针对挑战一,我的解决方式是,结伴编程快速提升工程师的基础开发能力,并使之在短时间内熟悉公司的技术栈和代码规范。这段时间压力会很大,学习内容也会很多,但是要求并不能放松,需要管理者持续关注工程师的进度和心态,对成员烦躁、失落的情绪及时进行安慰和疏导,同时在某些环节进行必要的技术辅助。
针对挑战二,首先避免过分亲密的关系,保持普通的社交距离,同时也在处理「挑战一」的时候让对方感受到你的关心。张弛有度,会使双方关系有序的发展下去,也为团队的长远发展打下基础。
针对挑战三,要和部门的上级主管进行沟通,确定部门的目标方向,然后主动将目标按优先级一一列出,根据实际情况向上级索要资源(要么给人,要么给时间,要么降低任务量)。以我的经验,能够主动索要资源的团队,往往是资源最充沛、进度最快的团队;对于管理者来说,一个能够合理索要资源的下属,也大概率是一个有思考深度和执行力的团队成员。
在数年前做运营的时候,团队管理就是一个我很重视的问题,每个工种对人有不同的影响。例如运营部门的基础运营成员往往看不到职业发展的前景,进而转行到其他行业;一线工程师则埋头于技术,疏于梳理工作内容和工作前瞻。这样其实给团队管理提出了很大挑战:作为管理者,到底能在多大程度上纾解这些职业对成员的负面影响、并提高团队运行效率?
在前些天给 CTO 提交的一份测试开发团队工作计划书中,我提到了进行人才梯度建设。虽然测试开发团队人数不多,以后最多也不会超过5人,但是由于分工不同,必然产生事业层次的高低。在团队内部明确人才梯度,告知每个人未来的上升渠道,指明上升的途径,不仅成员会主动成长,人员流失率也会得到降低(软件测试行业的流失率非常高)。一旦形成稳定的循环,那么这个部门将能够实现「无人驾驶」,几乎自动化的在公司内部高效运转。这也是我未来的工作目标。


最近买了一款 CMON 出品的卡牌构筑类的塔防主题游戏《XenoShyft: Onslaughter》,感觉比领土好玩很多,无论美术或游戏机制都远远超过其先辈们。先贴几张图以飨读者,后面会写一篇文章,来介绍和评论一下这款游戏(前两张图是我拍的,图中还乱入了我的猫「三十」。最后一张游戏图是 Google 来的,仅供示范)。
WechatIMG55
WechatIMG56
Xenoshyft-Board

Tagged : / / / / / /

关于开发流程的一些体会

工作近5周,共完成了2个项目(第二个项目已经基本完成测试,准备收尾中)。第一个项目,是用爬虫抓取数据,然后做好 API 供用户使用。第二个项目,是扫描僵尸用户,发邮件唤醒,如未唤醒则关停僵尸用户的进程。
做这两个项目的过程中各有各的体会。
首先,是关于解决问题的方式。做第一个项目时,刚刚进入公司,很难适应工程师文化,加上和同事不熟悉,脸皮薄,不愿意问问题,甚至没有仔细确认需求和工程方式就动手开搞,最终耽误了不少时间。在工程上,沟通极为重要,工程师不是低着头闭门造车的,恰恰相反,工程师们是用集体合作的方式共同搭建一个或繁或简的系统,最终完成个体无法完成的大规模工程。这应该是工程师们在一起工作的最重要意义之一吧。
工程被分割成一张张工单,并不意味着其整体被切割成无关联的个体。在完成工作的时候需要尽可能多的理解工程的有机性。例如我将爬下来的时间序列存入数据库时,每条数据的时间都被我存成了str,于是在后期制作 API 的时候就遇到了一些问题,最后需要通过将其转成datetime来解决。类似的问题说明我在完成某件工作时,并不知道这件工作在工程中的位置与意义,这就需要多问和多做了,在对整体熟悉了以后,自然会逐渐清晰。
其次,是关于单元测试的重要性。其实『单元测试』这四个字,有弱化其意义的副作用。我在做第二个项目的时候,由于内部处理数据的逻辑比较复杂,导致大大小小的 Bug 一大堆,每次提交都认为自己已经做得差不多了,但还是在 code review 时被打脸,来来回回提交了若干次,花费大量时间,甚至同事成了我的人肉 Debug 处理器。最后同事说,你还是写一些测试用例吧,覆盖的情况越多越好。
果然,写了一百多行的测试用例后,将单元测试完成,自然发现了一些之前很难发现的 Bug,无论对我还是其他工程师来说,都节省了大量调试改错的时间,多灾多难的第二个任务也随之迎刃而解。经此一役,我对单元测试的意义恍然大悟,其实单元测试并不仅仅是『测试』这么简单。在『测试』的背后,其实是将代码化整为零、各个击破的写作过程,因此单元测试的写作时间,应当与程序本体同步,也即『写一个函数,就写一个测试』,二者几乎是同步完成的。这样看上去花了很多时间在设计测试用例上,其实是规范了自己的思路和代码,同时大大提高了后期的可维护性。
在明白了第二点(也就是单元测试的真正意义后),觉得自己仿佛突破了一个模糊边界——一个软件工程师和业余代码爱好者的界限。虽然现在代码依然很烂,但是本着对代码负责的态度和对自己职业的尊重,我会把以后写下来的所有代码都同步加上单元测试,配得上一个专业人士应有的严谨。
以上就是我在完成了两个项目后的些微体会。工程师的快乐,是由一个个微小的痛苦组成的。此生竟有幸成为工程师,真是一件幸福的事情。

Tagged : / /

我的求职经历

2015年下半年,我在一家外贸软件企业任运营总监,某天无意间看了一眼当时公司产品的前端代码,竟在已发布的产品中发现各种注释,而且注释都是51cto之类网站的教学文章链接。那时候想,如果让我来做的话,应该比他们做的更专业一些。在思考了几个月后,2015年11月,我申请离职,开始脱产学习 Python。
『他们不行,我上!』这个理由,其实是我学很多东西的动力。例如两年多前学爵士鼓,就是看侨城堂教会的鼓手实在太水、于是买了 Roland TP4K 开始练习的。后来没有坚持练下去,水平也就一般般,但临时顶场什么的已经无压力了。
断断续续学了大半年 Python,在闭门造车的做了几个小项目后,我从2016年9月开始投简历。最开始在拉勾上被拒了大概二十几遍,只拿到一个面试,是给一家网站做分布式爬虫,面试结果不好,而我对这种纯应用型的部门也不太感冒(虽然自己技术不好,但一直有个目标,就是要去技术型的公司)。
后来觉得这种海投策略不行,郭老师给我提意见,说写个 cover letter 吧。我乖乖的听话,而当时自己完全没想到这个举动会带来后面的巨大收获。

某日在 v2ex 上闲逛,发现 Ricequant 在招聘 Python 工程师,于是研究了一下这家创业公司,发现居然还开源了一个量化策略研究框架,创始人技术也很好,就写了一封长长的 cover letter 过去,居然也混到了一个面试(收到 Ricequant 面试通知电话的时候,我正在上文提到的那家公司面试中)。9月27日来到 Ricequant ,CTO 正和另一个求职者谈话,于是安排了一位工程师来面我,很快工程师觉得我基础太差无法胜任。CTO 此时也闲下来了,简单聊了一下后,留了学习排序算法的作业。后来我整个十一假期都在做这个作业。
十一结束后发邮件交付了作业,以为可以轻松一下了,但1个小时后就收到回信,要求用代码实现所有排序并提了一堆需求。二话不说,接下来一个星期就继续埋头苦干,把之前没搞懂的面向对象、递归、单元测试等等搞定。第2次作业交付后,长舒一口气,但是还是在2天后收到催命邮件,要求我继续优化代码。这一次把算法部分和界面部分分开,同时做多线程优化等等。就这样又忙了5天,交付了第三次作业,同时也第二次去 Ricequant 面试,并现场拿到 offer。我问了 CTO 为什么会这样反复测验和面试我这样的初学者而不是直接筛掉,他说你 cover letter 太有激情了。此处为郭老师鼓掌三分钟。
(在二面 Ricequant 之前,我还收到了腾讯云的电话面试,依旧因技术太差而被直接告知不行,但建议我转投运营开发岗位。面试我的工程师人也很好,但我没有再投腾讯。)
从开始学习 Python,到找到工作,刚好一年。一年间,我的学习速度很慢,又是零基础,对自己的要求也不严格,经常连续半个月没写几行代码。好在朱老师一直鼓励我,说小步快跑是坠吼的,不用强求速度。事实也证明我的确更适合这种轻松的学习状态,而不是苦大仇深的埋头苦学。
我在刚开始入门时报过开智的 Python 入门班,相信我,很垃圾,不要浪费钱。Python 的入门资料很丰富,看书、在 Stackoverflow 和 Google 上查资料、在 Github 上给牛人提 issue,就已经完爆你能找到的所有国内培训课程了,而这一切都是免费的。
学写代码是我这个习惯性半途而废者第一个坚持下来并让我进入职业圈子的事。我依旧是小白一个,要学的东西太多了,对未来很期待也很紧张。但一年的学习让我找到了一种自信,就是无论在哪里都要坚持下去,为了家人,为了自己,如果需要做律师,我就去读法学院,如果需要牙医,我就去读医学院,如果需要木匠,我就拜师学木艺。1年不够就2年,2年不够就10年,总会有实现目标的一天。
今天是2016年的1024程序员节,在耕耘一年后终于有了收获,我很骄傲。

Tagged : / /

《Automate the boring stuff》学习心得

经过一个多月的懒懒散散的学习,终于啃完这本600多页的Python实战类教科书。在《Automate the boring stuff》(以下简称Automate)中比较重要的内容是,掌握Python基本语法和数据结构,学习一些内建库,同时了解和应用一部分解决职场问题非常方便的第三方库。
由于早先已经学过了《笨方法学Python》,基本语法语法掌握告一段落,因此开头几章比较顺利。下面我标记出(对我而言)比较重要的几个章节,供参考。
《Automate》使用Python3,如果需要多版本共存,可以查看我早先写的如何安装和配置Pyenv的文章——《Mac上修改Path,及用Pyenv管理多版本Python》
Chapter 5 – Dictionaries and structureing data
Python中Dictionary的用法非常重要,从这里开始,就成为本书中最常使用的数据结构。而用来操作Dictionary的几个函数(如keys/values/get等)则需要多写几行代码来记住用法。
后半章的结构化数据我还没弄非常明白,只是跟着教程完成了Project,有机会要在看一下(写本文的时候,我又看了一遍Dictionary部分,果然忘了好多)。
Chapter 7 – Pattern Matching with Regular Expressions
本章学习正则表达式的用法,为后面批量操作文件和写爬虫打好基础。内容稍微有点不好理解,并且需要记忆的地方很多。由于Python2到Python3中升级了部分语法(例如格式化字符**%**统一变成了format.(),不再需要记忆数据类型),因此需要注意目前使用的python版本。
这一章内容多而繁琐,又比较抽象,可能需要多花点时间。
Chapter 11 – Web Scraping
爬虫是全书的核心重点之一,也是Python最常用的功能之一。requests/BeautifulSoup这两个库是这个章节中最重要的部分,前者用来下载需要的数据,后者用来解析HTML标签。这两个库构成了本书中设计的简单爬虫的发动机。
Chapter 14 – Working with CSV Files and JSON Data
标题内容虽然是CSV和JSON两类数据文件的使用,其实本章节讲的是API的使用(各类服务的API多以JSON等格式来输出数据)。章节不难,但是需要理解数据是怎样通过API来到本地、继而用一些method对数据进行加工和输出。这一章比较有趣,可以举一反三。
Chapter 18 – Controlling the Keyboard and Mouse with GUI Automation
本章对普通读者用处可能不大,但生活中却经常见到和使用。朱老师说他正在做的安卓app的向导部分,即使用了本章内容。完整学完这一章,对于类似程序会有一个新的认识,能够理解软件背后的基本原理。


 
以上五章是这本书的难点和重点,其他章节或者仅涉及Python基础语法,或者仅介绍了一些并不算常用的库(可以现用现学,不用着急背下来)。如果能将这五章内容搞懂,基本上也就理解了全书最紧要的部分。
对我而言,本书最大的收获之一,就是搞明白了一些之前不懂的原理,并且知道了Python到底能做哪些事,为后面的Flask学习打下了基础。

Tagged : / /

技术型运营人员的几个特征

在过去的一年中,我带领一个运营团队在外贸软件行业整整工作一年,总结下团队的成果:
1. 创造了阿里巴巴国际站内效率最高的消息群发设备组,群发量全国第一。
2. 从创建一个5人QQ群开始,将之运维到10000人的用户QQ群组。我们这行业太小,所以应该是妥妥的国内第一了。
3. 是我知道的唯一一家让阿里外贸圈论坛全站置顶红色警告的软件企业,利用了阿里的一些小bug且推广量大到惹毛官方,『捣蛋分子』成就达成!
4. 整个推广团队加上我只有3个全职,用竞品10%的资源达成竞品60%的真实注册用户量,人均效率完爆同行。
运营人员有时被公司同事理解为『文员』、因而感到沮丧和困惑。这不是事实。运营绝非『文员』,并且恰恰相反,运营是科技企业里除了一线工程师以外,最需要技术的岗位。
运营意味着为一线工程师的产出赋值,将流水线产品变成更富个性的『手工艺品』。在这个意义上,一行行代码远非产品的最终形态,那只是包裹产品的外壳,而产品的实质则产生于内容运营、用户运营、社区运营等等环节之中。如MIUI的诞生固然给当时的Android固件领域带来一阵新风,但产品本身却并不能产生滚雪球的效应,卓越的社区运营才是为小米公司获得最初市场基础的核心(而市场营销,则是在那之后的事情了)。
运营需要哪些技术?
先声明,我所说的技术,不局限于写代码,还包含自由的想象力、以及将想象力变成现实的任何实践能力。因为这些大多需要以计算机技术作为工具,因此就笼统称为『技术』了。
第一,要有一定的代码能力、或阅读代码能力。能够通过代码完成一些简单的功能,如批量操作、运算等。这里除了常见的各类编程语言,Excel等表格处理软件事实上也包含在内,能够通过Excel等工具处理复杂数据,和编程是一样的。另外,能够主动运用技术手段提高运营效率,也是一条必备能力。运营中往往涉及大量重复性工作,需要运营人员寻找合理的技术方案来解决,在寻找方案的过程中不断降低成本、提高效率。
其次,理解工程师的行为逻辑。对于产品,有自己的理解。以我部门为例,运营部与产品部毫无关联,但是产品的任何改动,无疑都会在第一时间作用在运营数据上。因此一个好的技术型运营必须对于产品有整体性的理解,即:产品为什么这样调整?用户行为和数据反映了产品设计的哪个特性?运营应该怎样承接产品的迭代方向?做运营的都听过一句话,产品是一坨屎也跟你没关系,运营得好才是真牛逼——说这种话的人显然缺乏足够的行业经验,一个老资格运营必定对产品有深刻的理解,否则无法出色完成运营工作;甚至老资格运营也应该对产品充分表达自己的意见,而作为最接近用户的运营人员,往往是最懂用户痛点的,当一位资深运营看到堪比『一坨屎』的产品时,他最应该做的就是马上扭头走人,不要在这坨屎上浪费时间。
再次,能够主动认识到自己在技术上的缺陷,寻找有兴趣加入运营团队的技术人员。运营人员再懂技术,往往也并非职业工程师,在技术上的差距很难通过业余时间的学习进行弥补。因此不断的寻找技术人员加入自己的团队,也可看做是一个技术性运营的『天生嗅觉』。换一个角度,判断一家公司的运营团队是否强健,也可以『是否有工程师全职参与运营』为一个标准,能达到这个标准的企业,其运营一般都是较出色的。
以上三点,可以看做是技术型运营人员的几个特征。再次强调,所谓『技术型运营』,并非指运营人员撸起袖子写代码,而是『运营工程师』始终处于一种『寻觅更好的运营技术』的状态中,不断提高自己对『技术』的理解与品位,致力于将团队打造成自动化的『机动部队』。有这种状态的运营人员往往可遇而不可求,一旦发现,应该尽快吸纳入团队,并赋予充分的活动空间。
这是我对『技术型运营』的理解,和对『运营工程师』的画像。粗浅理解一定错漏百出,希望与各位讨论,不吝赐教。

Tagged : /