2019年3月8日星期五

领导力,是我接下来需要去努力的方向

背景

2018年11月,大概是我一个非常重要的转折节点,在原单位当了8年多的项目经理,因公司业务调整,成立了子公司,我被抽调进入了产品岗,成为了一名产品总监,这并不是什么手握大权的大官儿,你大概可以理解成小组长,甚至目前可以管理的人员数量和项目经理相比,都微不足道。
子公司从事的是线下电商数字化的业务,主要的商业服务对象也是我们集团的主营业务实体,它本身并不是从零起步的,已经经历过大概四代核心领导层的换帅,最终由我过去的老板,也是我现在的老板来接手。所以当它出现在我面前的时候,已经是一个200个人规模的大公司了。
感谢我直接上级(后称“我的领导”)的赏识,我才有机会在职业生涯中,跳过产品经理的岗位,直接变成一名产品总监,这种独特的职业履历,也正是我今天来写下这篇随笔的原动力。

我的履历

虽然我没有实际当过一天的产品经理,也没有以产品的身份实实在在地实操过互联网业务,但是通过观察和学习,我发现互联网从业人员应有的能力和我这种半路出家的人,思维模式上并无二致。
我先做一个自我评价吧,主观地讲(可能存有自我偏见),我是一个:

  • 标新立异的人,习惯于回到问题的原点进行思考
  • 勤奋愿意解决问题的人
  • 执行力很强的人
  • 共情能力还不错的人
  • 有点完美主义倾向的人
除此之外,我的专业是计算机,也从事了十几年软件研发工作,期间是啥缺干啥,从写代码、PS、文档、PPT、摄影等都得会一点。大概也是我的这种习惯的行为模式,导致我总是能在解决眼前的问题的时候,以简单直接的方式直截了当。
举个例子:前年公司搞年会,要想做个人脸识别的签到,我的同事会人脸识别,他主要负责搞定核心科技,而我就得去弄个摄像头啥的。既然是年会吧,你干巴巴地放一个摄像头肯定是low爆了,所以当时我大概花了10块钱就把这事儿办的妥妥的:
  1. 找到一张小黄人的图片,在它的两手之间PS了一个横幅,然后把它交给打印店
  2. 将打印好的小黄人剪下来,然后将小黄人的眼珠子拿刻刀划掉
  3. 然后把摄像头放在小黄人背后,整个摄像头就隐藏起来了
这大概就是我。

我的内心

上面这样的例子,虽然一点都不难,但是要做出来,我认为至少有几个要素:
  • 愿意去把事情做得尽可能更好
  • 对这个集体和目标有更多的热爱
  • 把事情的结果和自己的个人品牌建立关联
  • 动手能力要过关
我的过去如此,大概我的现在也如此。
作为一名下属,我觉得是我这种遇事迎头解决、全力以赴的方式,让领导一次又一次更加信任地将事情交给我。但是我不是万能的,我一定有解决不了的事情,这时候我的另一个经验就发挥了作用,我会尽力将我的困难及时地向上反馈。从协作网络的角度讲,我应该算是一个合格的网络节点。而这些认知,也大概变成了我对别人的期待:
  • 在成为一名专家之前或者同时,你需要成为一个优秀的网络节点,这样才能在一个组织网络中,让组织的效用最大化
  • 既然是网络节点,就需要快速、准确地传递信息,不论是你能做到的,还是不能做到的,都需要及时反馈
这就是我内心的一些价值主张。

新公司

回到我的新公司,一个既新又充满历史的组织,新是因为对于我是新的,顶层boss是新的,管理思路是新的,旧是因为人是旧的,思维模式是旧的,具体执行的组织结构是旧的,遗留的系统是旧的。
这里的新旧,不是我作为好坏评判的标准,所以暂且忘记哪些是旧的,哪些是新的。
单纯讨论公司的架构,可能需要我铺垫太多跟公司相关的背景知识,你才能做更进一步判断,那么我就从我们做出“产品”的团队,来向你描述我们的组织形式。
我们的产品,大多并不大,从形态上,你可以理解为像微信这样功能相对不是特别臃肿的形态,从用户规模上,你倒是也不用太在意,如果数量庞大,大概公司也就不会经历四轮换帅了。还有一些产品的形态,像是一个短期的活动,你类比一下美团搞个朋友圈裂变?又或者是一个在线抽签的小程序?虽然外在形态上不复杂,预期用户规模也不大,但是因为历史原因,我们有面向几亿用户的架构设计,我们的服务之间也是尽可能松耦合。如果公司是一步一步发展成现在这样的,我们大概会称它为过度设计,但既然是已成事实,那现在倒是也是一套不错的规范。
在描述组织形式之前,我花了这么一大段来写产品的目标,是因为我认为组织之所以有各种不同的形态,是因为没有一劳永逸的组织,它是人和目标之间妥协后的一个结果。
现在的组织形式分两个维度,按职能分:
  • 产品团队:定义产品、设计产品
  • 研发团队:前端研发、后端研发、大数据研发、算法研发、测试、外包
  • ------ 没有运营?对,目前并没有,所以谁操心谁来……
按产品分:
  • 产品1:产品总监、产品经理、研发、测试
  • 产品2:产品总监、产品经理、研发、测试
  • ……
  • 在最顶上还有一个领导,负责这个事业部的战略、资源、决策、对外撕逼等
但是完成最终的产品除了上面这些同学是不够的,前面介绍过,我们是一家大公司,有面向几亿用户的架构,所以在我们事业部外,还有UED、大数据团队、服务器管理团队等,这些也都可以理解为基础资源。
够了吗?还不够的,因为我们的产品也不是孤立存在的,我们一个事业部下面的产品1、产品2,可能是互斥的,可能是互补的,目标通常也都是服从事业部总体战略的,但整个公司,其实有一个更宏观的战略。就我们公司而言,我们对外统一有一个小程序,而我们的产品1、产品2,当然也不是所有产品,大部分也都是在这个小程序下面的,你可以理解成不同的功能或者模块。而这里说的小程序,是另一个事业部。
至此,我所描述的关于组织形式,甚至包括我们的“地形”也和你描述清楚了。

现状

我觉得任何主观地评论都不如客观地陈述更适合我这种管理学菜鸟,但我可以把我看到的写下来,咱们一起讨论。

案例A:

现在产品经理会负责定义产品,并获得产品总监的认可,然后和研发、测试的同学宣讲,研发的Leader会同意研发的同学接手这个项目,并自行确认研发细节和产品的同学沟通,同时测试的同学会形成测试用例,并和产品的同学进行确认。前面提过,我们没有运营,而且我们的产品同学表示,我们不会。
虽然他们嘴上说不会,但是他们可能更多想要表达的是不愿意,他们所指的运营,可能更多的是产品上线后的推广和使用。至于产品形态在实际生产中的应用,他们脑子里有个简单的雏形,也基本都通过实际行动体现在产品中了。为了便于读者理解,我这么类比你可能更容易理解。以一个公司撒钱发红包的例子来说,用户需要扫一个二维码,然后微信发个红包给用户,这里需要有线下二维码,他们会在大街小巷出现,它应该是呈现在一个易拉宝上面的,然后放在路口而不是放在垃圾桶后面。到这里,我们的产品同学大概都能想明白,但是,具体这个产品,是否要有个活动主题,是应该结合春晚还是结合元宵晚会,奖品是每次扫码都给吗,还是扫几次给一次,还是多试试做个ABTest?这些是我们的产品觉得不应该去思考的。
这大概是关于如何造出产品的一个案例。

案例B:

产品总监(我):我觉得有个问题咱们讨论一下哈,咱们这个项目虽然形态上是要发红包出去,但是我们其实对收上来的数据是有要求的,我们要求同一个用户,要领多次红包,这样的数据才对我们的数据建模有帮助。我们之前有个假设前提,是用户都是贪婪的,用户会到处去找不同的二维码扫,但是用户第一次在我们的产品里面领取到红包后,我们并没有任何提示让用户去扫第二个,那么按照大部分产品,比如支付宝的用户习惯,用户可能扫完就走了。因为线下活动的条件限制,我们只能在收银台摆放我们的二维码,这就导致这些二维码的曝光率会大大降低。既然是收银台,那么正常的用户行为,可能是一次游逛,仅去了一次收银台,那么用户去下一个收银台就缺乏动机,我们就得把这样的动机,在我们的产品里面表现出来,我们不指望那些不喜欢钱的用户去领,但是我不能让那些其实想要领钱,却因为我们没有告知他,导致他压根不知道居然还能再领钱的事情发生,举个简单的例子,我们在领到钱之后可以给一个用户提示,让用户知道。从这点讲,我们现在还有需要改进的地方,否则真的数据收上来,质量不行,咱们这笔钱就白花了。
产品经理:我们现在的产品就两个页面,没有地方可以加什么提示了,真的加了,也没有人看的。
产品总监(我):我只是希望你想一想这个问题的解决方法,不一定是我说的在扫码后加个提示。
产品经理:我觉得你想要让数据有效,你就得砸钱啊,你说数据不好看,你就砸时间长一点,你现在只有两万块钱,我当然没有办法保证质量,我觉得有人扫这个红包,这个产品就是个好产品了。
产品总监(我):你知道我们现在客观情况是不可能无止尽砸钱进去,而且好像并不是钱多钱少的问题,而且我的权限也改变不了这个钱的多少。但是我觉得目前这个产品有很多可以做的事情:
  • 在你的扫码二维码上,把咱们缺失的信息传达出去,也是一个简单实际的方案
  • 在你的页面末尾加个提示,也是可以的
  • 在你的页面前置一个今日扫码资格次数,也是电商常用的伎俩
  • 或者你做个应急预案,咱们就算现在不改产品,也可以在上线后实时监控数据,如果数据不行,我们可以把这批用户的手机号拉出来,给他们群发短信告诉他们还可以再去别的门店领钱,这也是个方案,不过如果要这么做的话,我们现在就得提前让研发的同学准备查询语句、找短信网关的同学去协调资源,到时候怎么看,什么时候需要启动这个策略也都需要提前明确。
我们估计也只有这么一次撒钱的机会,我们都不希望这个东西因为数据不行再做第二遍,如果真的到了那一天,人家只会认为我们的产品有问题对吧?
产品经理:继续辩解……短信也没人看、不会领的人就是不会领、第一次数据我觉得不好很正常、一开始让我做这个的时候,我就提出来了,这个东西不可能数据会好,你又没有钱,你要做这种砸钱的产品,你有钱了再说,你想要数据好,你就多申请点钱啊。
产品总监(我):就这样吧,我觉得咱们上不上线感觉意义不大了……
产品经理:最好别上
产品总监(我):(冷静了一会)你这么理解啊,如果用户扫一次,我们算是解决了拉新的问题,但是第二次、第三次再扫,其实是解决我们产品活跃度的问题,如果我们大部分数据没有这样的活跃度,我们的这个方案,就还需要去优化。
就这样一次又一次地循环讨论,然后大概在我的领导路过之后,这个话题变得缓和了一点,后面会怎么样我还不清楚,我非常期待有一个比我想出来的方案更好的方案,或者哪怕是上面的方案,也尽可能落地一点。
这大概就是一次真实的交流,当然,有时候我会被说服,因为人家说的很对,我也虚心接受,或者在讨论时,我意识到自己追求的那一点完美,似乎无伤大雅,我就自动终止了。

案例C:

产品总监(我):嘿,我也不太清楚你们实现后的细节,你给我说说憋。
前端研发:好啊,我给你说一下,%*&(**(……)*——
产品总监(我):对哦,我确认一下,这个LBS信息你记录了没有啊?我要手机的LBS,你们不要弄错了哟。
前端研发:哦,这个我不知道啊,不是我记录的,是后端的同学。
产品总监(我):那你回头帮我和他说一下吧。回头如果我们被薅羊毛了,这个数据可能会很有用。
前端研发:记录这个干嘛,咱们产品是为了发红包,这些无关的就不要了。
产品总监(我):呃%%%%%,再见

这里我做个检讨,我们产品团队,并没有在一开始,刻意去强调应该记录的内容、字段,以及这些数据的用途,可能我们讲清楚了项目的目标、暴露给用户的功能,却漏掉了最后在后台要做分析所需要的这些素材,但这些数据一旦没有存,在未来想要复盘的时候,将出现重大的缺失,虽然凭借我们的聪明才智,总能把后续的“总结”工作做得很完美,但我还是希望未来将这部分需求定义,也作为前期沟通需求的一部分,提前加进去。
当然,上面这位前端的同学这么说,除了因为和我太熟了之外,也客观暴露出一个问题,那就是前端潜意识认为,我没有做错什么,因为我做的都是产品的同学让我做的,所以我不接受修改。

故事先讲到这里,这大概就是我所要破的局。
你有什么高见?

2016年3月6日星期日

Markdown

Markdown作为流行的标记语言,已经火的一塌糊涂了,你只顾写你的,反正标记就那些,然后剩下的交给转化软件和CSS去格式化吧……
GitHub上的READMD.md足以证明它火的程度。

The key design goal is readability 
Markdown理念:

  1. 简单写、容易读
  2. 字符化
  3. 极简主义

Markdown原理:

  1. 标记语言——by Author(人)
  2. 转换程序——by Markdown Program(各种Markdown程序)
  3. 最终呈现——by Viewer Program for Humers(HTML/pdf/txt/RTF)

Markdown展示:(by Ulysses)



不同的Markdown系统Markdown标记也有所区别,不过都大同小异,找一个适合自己的即可。

Markdown收益:

其实HTML也是标记语言有木有,不过因为它被掺杂了太多的样式、脚本,显得不太纯粹了,而且是基于xml的语言,天生冗余就会比较多,如果你打算在写文章的时候自行html,那你不仅要学习html还要花时间在每一次敲击标记这件事上。
Markdown则简单地多,它尽量只表达最简洁的那些样式,剩下的事情,交给程序去做吧。
所以当你开始写它的时候,请不要回忆那些生成的效果,标题就是一个#,段落就是两个##,请不要像我一样,把两个星号表达为**粗体**,而应该叫它为强调,至于你用粗体来表达还是用斜体来表达强调这件事,都是后面的事情了。

Markdown与可视化编辑:

有了上一节的铺垫这一节就容易多了,Markdown强调的是事情本身,作者认为重要的内容,就打上**标记,中国的读者,喜欢用粗体表达重要,美国的读者可能喜欢用斜体表达重要,没关系,作者不用为不同的用户写两遍。
而可视化编辑器,不论是在线编辑器还是Microsoft Word在你看到它的杰作之时它就已经定型了。

但是,就单纯从方便的角度,则是仁者见仁的,毕竟我们还是喜欢直观的东西,但这丝毫不影响Markdown成为一种选择。

Markdown延伸玩法:



在此引入两篇文章:

  1. 一篇导引文章,简要讲述了一些简单的标记:http://markdowntutorial.com
  2. 一篇非常好的文章,不仅讲了Markdown的来龙去脉,还说清楚了它的工作原理:http://lifehacker.com/5943320/what-is-markdown-and-why-is-it-better-for-my-to-do-lists-and-notes
引用文章里面的一个Web Markdown系统,供大家练习:http://hashify.me/




2016年3月4日星期五

如何编译MongoDB?

本文将在Linux环境下编译Mongodb。
您可以选择已经编译好的版本直接使用,也可以尝试自己编译。https://www.mongodb.org/downloads#production


动手开始:

1、Linux,本文选择Ubuntu 14.04 LTS 64bit,下载地址:

2、包依赖:编译器 gcc g++ clang 安装方式:

# sudo apt-get install gcc (4.8.2以上版本)
# sudo apt-get install g++ (4.8.2以上版本)
# sudo apt-get install clang(3.4以上版本)

3、包依赖:python (2.7以上版本) 安装方式:

# sudo apt-get install python

4、包依赖:scons (2.3以上版本) 安装方式:

# sudo apt-get install scons
5、包依赖

# sudo apt-get install aptitude
# aptitude install scons build-essential
# aptitude install libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev

6、源代码:从GitHub上面下载:https://github.com/mongodb/mongo 直接选择一个分支,右侧Download Zip,解压缩到目录:

# mkdir mongodb-master-src
# unzip mongodb-master.zip mongodb-master-src/
# cd mongodb-master-src/

7、新建一个 version.json 文件在 mongodb-master-src/ 目录下:在大部分能搜索到的文档中,大家都是直接下载好后就编译,但是会报一个scons错误,原因就是因为缺少这个文件。

# gedit version.json
然后输入以下内容后保存: 
{
    "version": "0.0.1-fake-"
}

8、编译源代码:
# sudo scons all -j 4
这里-j 4 是指你所使用的CPU核数。也可以直接:
# sudo scons all  
或者仅
# sudo scons mongod
# sudo scons mongo
# sudo scons mongos

9、编译后验证,执行下面语句,你将看到版本提示信息。

# ./mongod --version

10、编译后配置,新建相关目录及配置文件
# mkdir mongodb_sample
# cd  mongodb_sample/
# mkdir bin
# mkdir data
# mkdir log
# mkdir conf
# cd conf
# gedit mongod.conf
在打开的端口内输入:
port = 12345
dbpath = data
logpath = log/mongod.log
fork = true  
其中:port代表访问该数据库的端口号,fork表示是一个后台进程。

11、复制编译好的文件到bin目录
# cp ../mongod mongodb_sample/bin/

12、启动mongod:
# cd mongodb_sample/bin/
# ./mongod -f conf/mongod.conf
13、检查log和data目录将看到文件夹内有新的文件。
14、停止mongod,这里因为没有连接到mongod服务器,所以直接使用kill的方式进行关闭,关闭的时候,不使用kill -9,可以使用kill -15:

先查找进程ID:
# ps -A | grep mongod
然后
# kill 32759
关于kill命令后面的参数,详见:https://en.wikipedia.org/wiki/Unix_signal#SIGTERM

2016年2月29日星期一

Hadoop技术内幕——深入解析MapReduce架构设计与实现原理 读书笔记(1)


Hadoop 1.0.0 源代码阅读,需要先安装以下软件。
很可惜,即便一切照做了,导入的文件也各种报错。

1、Java 1.6.0下载
http://www.oracle.com/technetwork/java/javase/archive-139210.html

2、Apache Ant 1.6.0下载
http://archive.apache.org/dist/ant/binaries/
http://archive.apache.org/dist/ant/binaries/apache-ant-1.6.0-bin.zip

3、Eclipse下载
http://www.eclipse.org/downloads/packages/release/Galileo/SR2
http://archive.eclipse.org/technology/epp/downloads/release/galileo/SR2/eclipse-jee-galileo-SR2-linux-gtk-x86_64.tar.gz

4、Hadoop 1.0源代码
http://svn.apache.org/repos/asf/hadoop/common/branches/
http://svn.apache.org/repos/asf/hadoop/common/branches/branch-1/
https://archive.apache.org/dist/hadoop/common/hadoop-1.0.0/
https://github.com/apache/hadoop/tree/branch-1

2016年2月15日星期一

Google的Bigtable学习笔记(不保证正确性)

Google的Bigtable学习笔记(不保证正确性)
1、首先是一个列式存储的简单数据模型的数据库,它比键值对模型/文档模型NoSQL数据库复杂点(也就更强一点)。
2、它的分布式存储性能依靠于GFS也就对单机房网络有硬性指标。
3、它同时提供了相对均衡的顺序读写操作,也就更适用于这样的应用。
4、保证SSTable不变的结构简化了读写冲突所产生的问题复杂性。同时允许不同的tablet共享一个SSTable。
5、memtable的设计减少了大量的读写冲突,双线程+序列允许归并写入,鉴于较小概率的读恢复操作,major compaction在排序时候借助写时候留存的序号进行去重,简化了写操作。
6、高级别的缓存针对访问相同数据进行的缓存服务比较容易被想到,但是块级别的缓存解决了顺序读的读写效率,是值得学习的。
7、因为row key是依照字典序进行排序的,所以在应用级别对row key的选择就是设计的一个重心。
8、字典序的设计对跨行更新以及分布式事务都提出了挑战,但是这个系统并不适用于解决类似的问题。
9、提供了无限的列结构以及column families,是它强于键值对模型/文档模型NoSQL数据库的地方,等价于自建了各种索引。也就是所谓的半结构化数据。
10、Tablets服务器对于主服务器的依赖较低,因为主服务器仅与有限的Tablets服务器进行通信,只负责解决它们的生存问题,而不用解决直接的来自于用户的请求。
11、利用Chubby进行分布式锁机制,使用了文件句柄的冲突检测来实现对于分布式服务器的管理,并配合了主服务器对Tablets的心跳检测,实现了完整的检测,在加上自杀和他杀技术的使用,使得整套系统得到了较高的可靠性。
12、两段式压缩对于类似于不同的时间点对相类似的数据进行存储后的压缩能够做到较好的压缩比,因为内容重复度比较高。

http://research.google.com/archive/bigtable-osdi06.pdf

2016年1月27日星期三

软件开发到底是怎么一回事呢?

人生得一良友不易,友人是做数据库DBA(运维方向)出生,对软件开发算是没有什么经验,但是最近手头却有点儿事让它对软件这件事开始有了兴趣。于是就问我这个问题。我呢,水平很差,这么大的标题丢过来,怎么回答呢?好在友人给明确了方向:
代码管理,版本控制,补丁管理,架构设计,模块划分,接口设计,报错编码制定,日志设计,测试方法,安全管控,性能规划
然后我就根据这些,作答如下,既然写了这么多,就拿出来和大家分享。

1、代码管理,版本控制,补丁管理
对于单一产品的公司,其实问题就是各种迭代和这些迭代的管理。
首先是坐下来讨论一下影响我们代码变化的因素是什么?需求、bug,计划内、计划外?
传统的软件管理,通常会把需求分成很多期,然后针对每一期制定版本计划,然后按着计划做。
但是现代软件偏向于敏捷的管理方式,用用户故事将需求分解成不同的场景,进行故事管理,然后通过迭代的方式向前,然后及时修正项目的整体目标。
回到代码管理,我有个原则,就是你不管是需求还是用户故事,在你打开你的电脑开始写的时候,就要明确你在为什么功能而coding,然后你每一次提交版本必须和你的代码库,task(一种集成在项目管理工具里面的任务,你也可以理解为excel里面的一行需求)一一对应。比如你今天就是做了一个接口,接口只完成一个功能,比如修改密码。那就写清楚你在做什么,然后和你的需求哪些相关。简单地说,就是每一次提交是一个原子提交。然后提交的时候,至少需要保证你的代码是可以编译通过的。
版本控制呢,通常需要考虑到分支的管理和标签的管理。其实我有一个保证它安全的好办法,那就是不用版本控制工具。它们不如复制粘贴/压缩包来的可靠。如果你确定一个分支要发布,首先你需要用版本工具进行分支发布,然后针对分支的补丁就在上面继续,然后适时往主分支合并。但是于此同时,请做一件事,将它们下载下来,把它压缩起来,然后放到一个文件服务器上。然后一旦出现问题,找个文本比较工具,你通常就豁然开朗了。
补丁管理这件事,刚刚也提到过了,你真对哪个版本出的问题,就在哪个分支上面去改,然后适时合并,适时当然是你在差异没那么大的时候做是最好的。
这里插一句题外话,敏捷的核心我个人认为不是在怎么说清楚用户故事,而是你要有单元测试,没有这个都是扯淡……当然其它也很重要,但是UnitTest是必要级别的。这也就是外包软件行业通常做不到敏捷的一个重要原因,因为不是那么容易做到。

2、架构设计
架构设计这可不是那么牛逼的一两句能说明白的事情,不过有几个个人认为还是比较重要的原则。
a、适度设计,其实拿捏这个度,何其难,在一个人开始看待一个问题的时候,自然就有自己的观点在里面,你的视角一定不是世界的中心,那么合理拆分就可以了,本着实用主义的精神做架构设计,通常能在成本、智力等方面都能取得一个还不错的平衡。
b、合理,其实面向对象编程最牛逼的地方就是让一段代码试图去模拟一件事的本身,这就像数据库设计里面的关系表一样,它一定要表达的是正确的关系,那么哪怕它性能上有缺陷。这些其实和什么代码可读性等都是相通的。这就是为什么大部分人都认为多线程程序会比较难,因为它通常不是人类思维。这样的合理设计通常从数据库的设计上面就开始影响你整个复杂度了。这一条通常随着架构师见识和对问题的理解程度不同,在项目进展的不同时期会有不同的体会,一开始合理的东西,在项目后期可能就不是那么回事了。
上面说的都是废话,因为不具备操作性,就是在你要做决定的时候去回想一下才有帮助。那么有什么规律可循呢?
其实通常我们都是习惯带着问题去解决它们的,比如你的性能要求很高,你要求达到一个特定的SLA,那么你在开始选择技术和框架的时候就要在这些方面都比较小心,然后用你熟悉而不是你似懂非懂的技术来解决,这样就算出问题,你至少能知道怎么去思考这个问题,而不会去怀疑那个东西不靠谱。然后就是包括所有影响这些的点,既然说的是性能问题,那么数据库、索引等都是需要考虑的,还有一些可以从业务上分开的,也可以从业务上解决,比如明明一个页面用户只想看到一个数值,但是你总是在页面上带一个大列表,而大列表刚好又查询了一个大表,那么这个页面必定有问题。

3、模块划分
模块划分其实就是你把你的功能合理分拆的过程,你能把你们家的主卧、次卧、厨房卫生间拆分开,你能搞清楚为什么电商分类里面不会把电风扇放到数码产品里面,就说明你掌握了模块划分的基本规则。这些都是纵向划分,按照领域进行细分。
我觉得你这里是不是想要知道的还包括分层管理,软件是个上下叠加的层次结构,其实从你下面跑的硬件到操作系统这一层级通常被做好了,然后就是做好你的软件的部分,所以接触你的操作系统的通常是软件公司给的各种框架,比如.net framework和java虚拟机等,然后就是那些架构框架,什么asp.net、servlet等,这些都不涉及到你的业务,通常是解决了技术层面的问题,然后你现在看到的成熟的解决方案通常都从界面开始(也许是个接口,总归和外界有个交互),然后从这一层中向下,到刚刚那层底层框架之间就需要你自己来分了。看看你是不是需要访问数据了,比如数据库,不管是sql还是nosql,总归需要去联一下了,这里多是考核你层间接口的设计能力,然后你想象你设计的接口就像插座上面的标准插口一样,上层不再关心下层的实现细节,如果下层有问题,让下层去改好了。然后一层一层往上剥离,就到了你刚刚想要做的对外的那个界面了(也许是接口)。什么三层架构什么的,也只是对这些的一个大致归类。
不过按你的思路,也许你的脑子里是个VisualStudio里面的Solution的Panel,你想知道的是一个大的解决方案中各种程序集(dll/lib)的分类方式,那么你回到你最熟悉的Windows/linux下面好了,负责网络的就是网络驱动,管它怎么实现的,我反正负责网络的,你找我就可以了。然后负责IO的,就负责IO就好了。程序集的划分差不多也就是这样的,以SSO举例,加解密我们会有单独的模块,然后做具体业务逻辑的也会有,然后一些辅助的小代码(比如查一下ip地址啊什么的),大概也就是这样一点点分出去。

4、接口设计
上面的很多思路其实在接口设计中都是相通的,其实就是职责分明,一个接口尽量完成一个原子操作,不要完成很多件事,除非你把它当作一件事来做。这个粒度的把握也需要思考清楚。比如修改密码的接口,你就不要再加入重置密码的逻辑,哪怕你背后的代码恨不得调用同一套,也需要暴露两个接口。接口之所以被设计出来,就说明它是相对稳定的,任何对接口的修改,都是一次玩命,原则,约定的功能是不可以减少的,哪怕是不合理的,这个才是接口最难的地方。就像你发布了电灯底座接口,然后全世界都在为你生产电灯,然后你说不行,圆的你不喜欢你喜欢方的,我改了哈,然后,你懂得,上街不要被人打。那么接口的设计就非常需要合理,哪怕你留下一个没有用的参数,内部你压根不用,你写死都可以,但是一定要合理,只有这样,未来使用这套接口的标准程序才不会受到影响。然后单元测试的思想就很重要了,接口永远要保证之前测试的场景在每次升级后还能正常被跑过,否则你的接口随时有可能产生涟漪反应。
5、报错编码制定,日志设计
万物归本,这件事就是你确定一个列表,然后把它吐出来的过程,Windows那么多弹错,无非也是一堆编码,出了问题到kb里面一搜就出来各种编码了。至于这个规则是按类似手机号或邮编的编码方式还是按照条形码的方案来,这个仁者见仁场景也不一样,哪怕你毫无规律地来编,它们都只是起到了一个Id的作用。
这里可能需要提到的一点,这个编码和日志设计通常都在一起,其实在你程序需要记录的时候,哪怕你觉得它八百年才会发生一次,你也要需要给人一个合法的编码和完美的解释,那么你就不至于当系统弹出“有错”的时候,你一看有十几处一样的错误。我倾向于错误始终唯一的方式。
在现代软件编程中,可以借助AOP的思路来将它们收集起来,这个思路和程序横向切片差不多,它在代码上的体现通常是,你的代码明明只是做了业务逻辑,但是它自动会帮忙记录日志,而且能告诉你到底是哪个程序第几行在什么地方干了什么。当然这个也是有代价的,就像你在水龙头上安装了过滤器,那么水流自然要小一点。
现在有nosql了,海量存储变的更方便了,然后分析这件事借助离线计算的方式,总归是能算出来的,但是记得,一定要把信息尽可能多地记录下来。

6、测试方法
传统的测试当然非常重要,什么冒烟测试、用户验收测试、回归测试、集成测试等都非常重要。
这里要提到的更多的是自动化测试,虽然我在项目中很难用到这一点,但是它的思想我非常认同,因为它是用代码来测试代码,代码是什么,是你经验的积累,你找个妹子上去点一遍,点的过程就是经验,你让妹子点20遍也许妹子能朝你踹一脚,但是代码一旦完成,只会越来越趋近精确。现在软件工程上面对类似界面点击这些都已经有了成形的工具,但是说实话国内软件业掌握的还不怎么样。当然也因为有很多不完善。
通过持续的反复测试,说白了不管是人还是机器,更多的经验和体力投入都能获得更好的效果。

7、安全管控
安全管控,现在安全组做的那些事情,包括用安全工具来扫描、找红帽组织来,其实都是基于行业经验来做到监理的角色。当然软件开发,本质还是一个智慧的事情,比如你家盖房子,你知道安装了窗户,需要有锁,而且锁必须在房子里面,不能在外面,低楼层需要安装防盗窗,防盗窗必须比一个正常的人要窄,这些都是经验。有很多现成的经验,需要在程序员开始干活之前就要掌握,其实不应该假设程序员什么都懂,其实他们很萌的。我刚开始写web的时候,那个时候没有往安全方面去想,因为之前一直做的是windows界面,不同窗口之间无所谓安全的事情,但是做web的时候,真的做了那种除了登录页面之外的页面也可以不要登录,敲个地址就能进去的low事儿,后来自己发现了,才从web的原理着手去了解了这样的问题,但是这个事情,终归是个意识和见识问题。大部分不干坏事的人不知道怎么干坏事,所以大家还是需要多学习。
然后就是一个好的基础框架,开发规范,很多公司程序员并不太了解这些,但是它们也不出轨,比如单点登录就帮他们解决了这个问题,因为架构上要求一个用户至少是登录的。
这里特别要提到接口,通常很多人做完接口就不管安全了,因为它不好测,也看不见嘛,但是这一块通常需要被重视。不过像什么WebService的标准里面都有一整套安全规范,当然除了大公司用之外,大家可能掌握的也不多。

8、性能规划
性能,是个数学问题吗?你先知道一共有多少的性能压力,你把小轱辘的轮子放在卡车下面自然是承受不了的。现在比以前好多了分布式计算让性能从单一计算机性能瓶颈上分解出来,但是分布式。。。。通常适用于可以分布式的事情。。。
其实在我们常见的场景中,无非是web性能和数据库性能,web性能现在大家都是用负载均衡来分开的,其实,很多时候傻逼的程序员干的蠢事需要服务器cpu来买单的事情也不少见。性能出问题,大多出现的问题,比如耗时的程序在工作,比如网络慢了,进行IO操作了,访问数据库了,跨边界的操作通常容易导致性能问题。比如访问内存的速度通常和访问数据库都不是一个量级的。那么在一个for循环里面访问数据库就是一个比较不合适的做法。那么一次性读取后再for也许能帮到你,当然也不是所有的场景都如此。还有就是良好的算法功底,比如一个循环的算法复杂度是O(n),而一个哈希表的算法复杂度是O(1),通常大家都不需要自己去写这些,但是选择合适的数据结构来处理问题,变得很重要。
至于你说你的服务器应该买多牛逼的,那我就不知道了,压力测出来之后,看着买能买得起的最贵的,然后调程序去吧。














2011年12月5日星期一

过程与结果之于文档

平生见过的文档不多。个人认为一个过程中的文档应该是一个做事的书面化。格式、范围也都是用来完成「做事」这个目标的。明确了目标就容易了。
有人说,有个文档,描述结果就可以了。这里的结果不是最终的结果,而是中间结果。举个例子,今天内幕提高准备金,你让人正飙涨的股票火速抛售。于是你就跟人说:全抛!大概就是这样。
就这事,有几个风险?
1、他信不信?
2、消息准不准?
3、他有没有其他干扰?
第一点,明明疯涨,为何要抛?你被怀疑羡慕嫉妒恨!
第二点,消息准吗?会不会是假消息?中途有没有变数?万一继续涨,怎么跟人解释?
第三点,你确定他一无所知吗?他是否比你知道的还多?万一你们的消息有冲突?
看到这个中间结果,问题就涌上来了。文档也类似,你拿到文档去做事却不知道为何这么做,结果会怎样?
文档里一定有很多你都没想到的细节在具体操作层面才会暴露出来。这时候去追诉为什么就显得尤为重要。不仅如此,过程还代表了一种思维方式,阅读文档的人也会因此而获益。当然,文档里的字就多了,但不代表你多想了,因为那些本来就要想。反而那些只有结果的文档不知道是不是灵感乍现的杰作?