前言:编程第一次大作业,海量字符串检索。C语言,并要求使用trie树结构以及bloomfilter两种技术实现,体会它们的特点。这里对Trie做些学习笔记。

Trie树

Trie树,又称单词查找树、字典树,是一种树形结构,是一种哈希树的变种,是一种用于快速检索的多叉树结构。典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高。

Trie的核心思想是空间换时间。利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的,例如邮箱的公共后缀。

Trie树也有它的缺点,Trie树的内存消耗非常大.当然,或许用左儿子右兄弟的方法建树的话,可能会好点.

特点

  1. 根节点不包含字符,除根节点外每一个节点都只包含一个字符。
  2. 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
  3. 每个节点的所有子节点包含的字符都不相同
    例如,给出一组单词:inn, int, at, age, adv, ant, 我们可以得到下面的Trie树

可以看出:

  • 每条边对应一个字母。
  • 每个节点对应一项前缀。叶节点对应最长前缀,即单词本身。
  • 单词inn与单词int有共同的前缀“in”, 因此他们共享左边的一条分支,root->i->in。同理,ate, age, adv, 和ant共享前缀”a”,所以他们共享从根节点到节点”a”的边。

实现

1. 插入过程

对于新的单词,从根开始,沿着单词的各个字母所对应的树中的节点分支向下走,直到单词遍历完,将最后的节点做标记,表示该单词已插入trie树。

2. 检索过程

从根开始按照单词的字母顺序向下遍历trie树,一旦发现某个节点标记不存在或者单词遍历完成而最后的节点没有标记,则表示该单词不存在,若最后的节点有标记,表示该单词存在。

3. 删除节点

很少使用,从该节点开始,释放它和所有子节点占用的空间。

4. 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

typedef struct TrieNode {
int count; //statistics
struct TrieNode* next[MAX];
}TrieNode;

TrieNode* CreateNode(){
TrieNode* p = (TrieNode*)malloc(sizeof(TrieNode));
p->count=0;
memset(p->next, 0, sizeof(p->next));
return p;
}

/*Insert new entry*/
void InsertTrieNode(TrieNode* pRoot, char *s, int flag){
TrieNode *p = pRoot;
int i,k;
i = 0;
while(s[i]){
//confirm branch
if(s[i] >= '0' && s[i] <= '9')
k = s[i++] - '0' + 2;
else if(s[i] >= '@' && s[i] <='Z')
k = s[i++] - '@' + 12;
else if(s[i] >= 'a' && s[i] <= 'z')
k = s[i++] - 'a' + 13;
else if(s[i] == '.' || s[i] == '-')
k = s[i++] - '-';
else if(s[i] == '_'){
k = 39;i++;
}
else
return;
if(NULL == p->next[k])
p->next[k] = CreateNode();
p = p->next[k];
}
//mark the trie string
p->count = flag;
}

/*Match certain string*/
int SearchTrie(TrieNode* pRoot, char *s){
TrieNode *p = pRoot;
int i,k;
i = 0;
while(s[i]){
if(s[i] >= '0' && s[i] <= '9')
k = s[i++] - '0' + 2;
else if(s[i] >= '@' && s[i] <='Z')
k = s[i++] - '@' + 12;
else if(s[i] >= 'a' && s[i] <= 'z')
k = s[i++] - 'a' + 13;
else if(s[i] == '.' || s[i] == '-')
k = s[i++] - '-';
else if(s[i] == '_'){
k = 39;i++;
}
else
return 0;
if(p->next[k] == NULL)
return 0;
p = p->next[k];
}
if(p->count > 0){
return p->count;
}
else
return 0;
}

}

运行结果略。

查找性能分析

在trie树中查找一个关键字的时间和树中包含的结点数无关,而取决于组成关键字的字符数。而二叉查找树的查找时间和树中的结点数有关O(log2n)。

如果要查找的关键字可以分解成字符序列且不是很长,利用trie树查找速度优于二叉查找树。如:若关键字长度最大是5,则利用trie树,利用5次比较可以从26^5=11881376个可能的关键字中检索出指定的关键字。而利用二叉查找树至少要进行约23.5次比较。

Trie树的应用

  • 串的快速检索:
    给出N个单词组成的熟词表,以及一篇全用小写英文书写的文章,请你按最早出现的顺序写出所有不在熟词表中的生词。
    在这道题中,我们可以用数组枚举,用哈希,用字典树,先把熟词建一棵树,然后读入文章进行比较,这种方法效率是比较高的。
  • 串排序:
    给定N个互不相同的仅由一个单词构成的英文名,让你将他们按字典序从小到大输出。
    用字典树进行排序,采用数组的方式创建字典树,这棵树的每个结点的所有儿子很显然地按照其字母大小排序。对这棵树进行先序遍历即可。
  • 最长公共前缀
    对所有串建立字典树,对于两个串的最长公共前缀的长度即他们所在的结点的公共祖先个数,于是,问题就转化为当时公共祖先问题(以后补上)。

Patricia Trie

针对,Trie树占用空间较多的缺点。可以对每个trie树节点做压缩工作,从而节省程序占用的内存空间。如果一颗Trie中有很多单词只有一个儿子结点,可以用Patricia Trie(Linux内核中叫做Radix Tree)压缩存储。由于#结束符标记被看作是一个叶子结点,那么一颗Patricia Trie的任何内部结点有2个或以上的孩子结点。

Linux radix树最广泛的用途是用于内存管理,结构address_space通过radix树跟踪绑定到地址映射上的核心页,该radix树允许内存管理代码快速查找标识为dirty或writeback的页。Linux radix树的API函数在lib/radix-tree.c中实现。

作为Trie树的优化变异,Patricia树也可进行Trie树的操作。实现略。

Trie树之外

除了Trie树,最常用的字符串检索有Knuth-Morris-Pratt算法(最长前缀匹配),以及Boyer-Moore算法(最长后缀匹配)。关于这两个算法,参考资料的6和7的链接是我见过介绍的最好的,深入浅出易于理解。这里就不再废话了。

参考资料

  1. http://blog.csdn.net/hguisu/article/details/8131559
  2. http://blog.csdn.net/sjjbupt/article/details/6758309
  3. http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=28977986&id=3807947
  4. http://www.cnblogs.com/ljsspace/archive/2011/06/27/2091771.html
  5. http://blog.chinaunix.net/uid-13245160-id-84371.html
  6. http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html
  7. http://www.ruanyifeng.com/blog/2013/05/boyer-moore_string_search_algorithm.html

许久未写过日志,实在是苦于终日碌碌无为的状态。更可悲的是,这种状态已经维持了近5个月了。我向来以做成事作为追求的目标。真正进入实验室后,却发现许多事还未做完,就被中途砍断。以至于重复做着机械式的工作,没有理由和时间踏实学习和做成一件事。自10号开学以来,情况并未见好转。趁着假期偷个闲,也寄希望于逃离琐事能把这些都看明白吧。

关于如何前进

回顾过去,初三、高三、大四的状态是我最满意的。那时,每天为做成一件事而努力着。最后也都能得偿所愿。大四上,我完成了两篇论文,远游两次颇有收获,岁末实习经验money双收。高三、初三的学习如鱼得水。略回想一下,那时努力时并不特别在意结果如何,只是专心做着该做的事。反倒之前不顺的几年,频繁的自我反省,最后收效甚微。也许,专注做事是目前最为迫切的了。该做的体育委员就真认真写策划,该负责的ONOS项目就认真看文档,做开发;看不到希望和前景的就果断放弃,不去希冀未来。简言之,该专注的就埋头去做,其余的就不去期待反馈。

我相信,以我的能力,埋头做的事即使不是设计的预期,也会有个妥当的结果。

有时候,解药并不一定长篇累牍,只是想太多。

关于择偶观等

晚饭后,与嫂子闲聊。从和表哥的认识到之后关心的处理,还是略有启发。这里先摆上结论:较为强势,有生活能力的女性对日后的家庭生活更有帮助。

诚如我们的共识,男人最后毕竟是要撑起整个家庭,在外挣钱养家的,不大可能操心家庭里太多。包括衣装,家务,做饭等等。这里并不是说不负责,只是主要精力不在这里。事业、家庭、社交几个方面,男人不可能全面涉及。从常规角度思考,重事业的男人会更有利于家庭的维系和发展。那么,一个精于或者说至少积极于家庭、社交的妻子就会更好的弥补这个角色缺陷。让男主人在下班回家后少操很多心。小鸟依人型的伴侣诚然在交往时,可以充分满足男人的大男子主义虚荣感,但在真实的生活面前就显得有些不够省心。

实际上,我的身边并不是没有这样的例子。嫂子就是一个,母亲又是一个。一个听在眼里,一个看在眼里。表哥醉心科研,短于社交,嫂子帮他完成家庭外的交往工作,察言,观色,为人,处世。在家庭生活里,也承担着几乎所有的家务,甚至包括维修家用电器等。无疑,表哥是幸福的。母亲从小就承担着我的教育责任和家庭的社交角色,并且精于此道。同时,在日常生活里,眼中有活,虽然由父亲承担了大部分,但是多半是母亲提醒的。设身处地地思考下,着实为表哥和父亲感到幸运。

一个眼里有活,精于察言观色的女性作为终身伴侣,从长远来看,会让家庭更稳定。而眼里有活,精于察言观色正是较为强势,会生活的外在表现。

的确,和这样的女性相处时,会出现矛盾。身边的无数实践已经提前证明了这点。不过多半的争吵是苦口良药,经过冷静的沟通后就会缓解。

说了这么多,纸上得来终觉浅。做了这么久的理论家,谁能来帮我圆一个实践家的梦呢?

关于其他

实际上,晚上的聊天内容还有很多。除了非普适内容和以上的核心论点外,就不剩多少了。谈到逆反心理这个话题时,有个点倒是异常有趣。表妹从小父母离异,由姑姑们培养长大。对姑姑们严格的管教多有怨言,而严厉的管教却还是依旧。逆反心理终会随年龄消退。但是嫂子提醒了一点:姑姑们虽然教育有方,不过孩子都是男孩。对男孩的教育方式真的同样适用于女孩吗?

虽说此话本身并没有什么可讨论的。不过阐发来看,平时许多我们习以为常的事,真的就是正确的看法吗?还是只是我们习惯了看问题的角度?这个我并没有找到实例,有待进一步讨论。

风扇摆着头,床头柜的台灯射出幽暗的光。风衣被挂在墙上,毛线手套一半搭在桌沿,利刃发出寒光,滴着血。乔是个杀手。


温热散去,乔收去风衣,带上手套,收起匕首,将书桌歪斜的书本摆直。“导演”欣赏利落的人,乔却从来不把这当作刻意。谨慎有序是他的天性。


在夜间思考,在白天沉默。乔支起双手,刚开的水在手边冒着烟。凡事总有为什么,乔只是想把它摸清而已。门口响起三声闷响,脚步远去。

订单又到了。


书架上摆满了乔的笔记。笔迹清晰整洁。他坚信,多人不成事。雨后的路灯下,乔避开光明的嘈杂。风衣滴着水,枪口还留着余热。人云亦云,厌恶之至。

一道锁,两道锁,三道锁,水温正好。一口水,两片药,三点整,思考结束。


街上的杀手不只乔一人,乔也并不愿认识所有人。朋友间少不了兵戎相见,乔手里攥着他们的鲜血,在街头,在小巷,在桥洞下。只可惜,没能分享自己的哲学。


屋顶闪过微光,乔又记起,那些曾与他四目相对的脸。就像两周前,屋里的猫走时看他的最后一眼。然后,就不再回来


乔也喜欢过春天,鸣鸟,微风,可以倚坐桌边,一整天。猫蜷卧在窗台做梦,一下午。

窗外,鹅黄柳绿。窗里,它刚搬来一周,水仙迎风跳起舞。


乔不怕失败,只忌惮那些说不出为什么的事。茶壶呼噜发响,茶叶上下翻腾。乔坐得规矩,跟猫讲着直就是直,弯就是弯,太阳就该在白天升起,然后才是月亮。猫也呼噜发响,翘起耳朵听着。


猫饿了,要吃食。水仙渴了,要喝水。乔一一满足。吃饱喝足,乔提起他的准则。猫默然,水仙默然,无人在乎。


这些日子,乔从未失误。手起刀落,干脆利索,只因不想太多,仿佛,回答了那些问题就能过好这辈子。

我是谁?我从何而来?我又将去向何方?


如今,乔空对水仙,泡茶呷茶。猫爬上他人房梁,依旧吃饱喝足,乐得逍遥。与它几次重逢,乔心里明镜儿似的知道。这道别,早就写好了。


又几次枪口的呼啸,又几次无出其右的表演。

最后,乔辞别了“导演”,走前卖了茶具,烧了笔记,放了水仙。

“导演”有点遗憾,说到,沿途保重,一路顺风。而乔蓦然莞尔。


猫走后的第六十天,乔开始苏醒。

午后五点十五分,乔飞奔在麦田边的路上。喊杀声常伴耳边,阳光把身影扯得老长。眼前的路恣意延伸着。

乔的心里很平静,他明白事情总有始有终,就像你我每天要吃饭一样简单。再见了我的刀,还有你滴过的汗。再见了我的枪,还有你冒过的烟。

天被撕裂,地在颤抖。夕阳流着血,注视着乔。而乔,曾是个杀手。

Docker

Docker

Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。总之就是轻便型的虚拟环境。

考虑到ONOS的实验环境搭建不易,Docker有助于我们移植搭建好的环境。

Docker安装

1、安装软件包apt-transport-https,使APT系统能够被https解析

1
$ sudo apt-get install apt-transport-https

2、添加Docker repository key到本地keychain

1
$ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9

3、添加docker软件仓库到软件源,升级软件源,安装lxc-docker包

1
2
3
$ sudo sh -c "echo deb https://get.docker.com/ubuntu docker main &gt; /etc/apt/sources.list.d/docker.list"
$ sudo apt - get update
$ sudo apt-get install lxc-docker

注:上述操作可以使用下面的脚本完成。

1
$ curl -sSL https://get.docker.com/ubuntu/ | sudo sh

4、验证docker安装完成,可以使用下面命令测试

1
$ sudo docker run -i -t ubuntu /bin/bash

-i interactive, -t tty, -p port可以多次使用指定多个Port映射, -P端口映射随机分配

ONOS(Open Network Operation System)

ONOS是首款开源的SDN网络操作系统,主要面向服务提供商和企业骨干网。ONOS的设计宗旨是满足网络需求实现可靠性强、性能好、灵活度高。此外,ONOS的北向接口抽象层和API支持简单的应用开发,而通过南向接口抽象层和接口则可以管控OpenFlow或者传统设备。总体来说,ONOS将会实现以下功能:

  • SDN控制层面实现电信级特征(可靠性强,性能好,灵活度高);
  • 提供网络敏捷性强有力保证;
  • 帮助服务提供商从现有网络迁移到白牌设备;
  • 减少服务提供商的资本开支和运营开支。
    下面介绍ONOS安装(Ubuntu源码安装)

1 系统要求

安装ONOS对操作系统有如下要求

  • Ubuntu Server 14.04 LTS 64-bit
  • 2GB or more RAM
  • 2 or more processors

需要安装如下软件,如果不用git获取源码,GIT可以不需要安装。

  • Java 8 JDK (Oracle Java recommended; OpenJDK is not as thoroughly tested)
  • Apache Maven (3.0 and later)
  • git
  • bash (for packaging & testing)
  • Apache Karaf (3.0.2 and later)

2 安装依赖

安装apache-karaf和apache-maven

apache-karaf的版本为3.0.2或以上版本,apache-maven的版本至少为3.0,这里使用版本3.2.2。创建/Applications目录。之所以要安装到这个目录,是因为onos源码中已经设置将apache-karaf、apache-maven放到/Applications目录。这个目录也可以通过更改~/onos/tools/dev/bash_profile修改,但是为了避免不必要的操作,这里按照默认创建文件夹。

1
2
3
4
5
6
$ cd; mkdir Downloads Applications
$ cd Downloads
$ wget http://download.nextag.com/apache/karaf/3.0.2/apache-karaf-3.0.2.tar.gz
$ wget http://www.apache.org/dist/maven/binaries/apache-maven-3.2.2-bin.tar.gz
$ tar -zxvf apache-karaf-3.0.2.tar.gz -C ../Applications/
$ tar -zxvf apache-maven-3.2.2-bin.tar.gz -C ../Applications/

安装java8

1
2
3
4
$ sudo apt-get install software-properties-common -y
$ sudo add-apt-repository ppa:webupd8team/java -y
$ sudo apt-get update
$ sudo apt-get install oracle-java8-installer oracle-java8-set-default -y

正确安装后,java -version和mvn –version打印的java版本应该一致。

3 安装 ONOS

下载ONOS源码

将ONOS源码下载到合适的目录(笔者放在/home目录下),切换到1.0.0分支

1
$ git clone https://gerrit.onosproject.org/onos -b 1.0.0

环境设置

安装ONOS之前,需要设置ONOS_ROOT和KARAF_ROOT等路径,切换到root权限用户,在/etc/profile文件的最后添加如下设置:

1
2
3
4
5
export ONOS_ROOT=/home/onos/onos-onos-1.0
export KARAF_ROOT=/root/Applications/apache-karaf-3.0.2
export JAVA_HOME=/usr/lib/jvm/java-8-oracle
export M2_HOME=/usr/local/apache-maven
export PATH=$PATH:$M2_HOME/bin

保存后执行

1
2
$ source /etc/profile
$ source $ONOS_ROOT/tools/dev/bash_profile

如果没有报错,则表示执行成功
可能的错误有:

  • No such file or directory
  • No such cell: local

构建ONOS

以上的步骤一切顺利后,可以开始构建ONOS,执行下列命令

1
2
$ cd onos/ //目录可能因人而异
$ mvn clean install

安装需要5~10分钟不等.

运行ONOS

需要编辑$KARAF_ROOT/etc/org.apache.karaf.features.cfg文件

添加下面的内容到 featuresRepositories:
mvn:org.onosproject/onos-features/1.0.0/xml/features

接着添加下面的内容到featuresBoot:
onos-api,onos-core-trivial,onos-cli,onos-openflow,onos-app-fwd,onos-app-mobility,onos-gui

之后就可以启动ONOS了:

1
$ karaf clean

启动时间较长,请耐心等待。

但是,Ubuntu源码安装并不总是能够成功的。在执行ONOS_ROOT/tools/dev/bash_profile和构建ONOS时,很容易出错。Docker在这时能发挥它应有的作用。

Docker搭建ONOS环境

声明:建议使用root用户做以下操作,可以省去sudo的麻烦

1
$ sudo -s

1 获取ONOS镜像

搜索镜像

执行“docker search onos”来搜索相关的镜像,可以从STARS来确定资源的好坏。因为ONOS刚出来不久,还没有最完美的镜像。这里我们选择“ywang1007/onos-buildenv”镜像。

下载镜像

下载选择的ONOS镜像到本地机器,这里需要花费一段时间。

1
# docker pull ywang1007/onos-buildenv

pull 后面加上 -a可以下载该镜像的所有版本

查看镜像

查看已经下载好的镜像

1
# docker images

里面已经包含了下载好的镜像

创建容器

为了展开实验,我们需要创建一个容器,进行镜像内的实验。

1
# docker run -i -t -p 0.0.0.0:6633:6633  -p 0.0.0.0:8181:8181 --name ONOS ywang1007/onos-buildenv /bin/bash

值得说的是,ONOS有web界面,端口是8181,为了可以页面访问ONOS,要做两个端口绑定。容器的6633端口绑定到主机的6633端口,容器的8181端口绑定到主机的8181端口。之后宿主机器访问“http://your ip address:8181/onos/ui/index.html”即可查看ONOS状态。

创建好后,可以使用“docker ps -a”来查看当前容器情况。

-a 全部 -l 最新
和Docker容器相关的命令有

  • docker start 启动某个容器
  • docker stop 关闭某个容器
  • docker attach 连接到某个正在运行的容器
  • docker rm 移除某个停止运行的容器

docker的相关命令可以通过docker –help来得到

之后的操作类似于上一节介绍的,搭建环境,建构运行ONOS。在宿主机器上运行mininet,使用pingall命令,可以证明onos已经在工作。过程略。

好不容易搭建好的onos环境最好用新镜像的方式存储起来,方便下次直接使用。

1
2
3
# docker commit xxx onos-1.0.0 //提交一个新的镜像
# docker save onos-1.0.0 &gt; /home/zinc-fnl/onos-1.0.0.tar //将新镜像保存起来
# docker load &lt; /hoe/zinc-fnl/onos-1.0.0.tar

此时再次查看本机的镜像

1
# docker images

就会发现刚才保存的新的镜像。

总结

本文主要介绍了docker的安装与简单使用以及ONOS的环境搭建。从中可以看到docker对于快速搭建实验环境有很大帮助,相信未来会有长远的发展。另外,这里对ONOS的性能并未做详细分析,笔者将在日后通过实验对ONOS进行考察。

副产品

实验过程中,因为对profile文件做过修改,曾出现过开机无法登陆的情况。orz..

问题:登录成功后,自动跳转回登陆页面

解决方法:

  1. Ctrl+Alt_F1切换到文本模式
  2. 将在profile和bash_profile做过的修改撤销掉
  3. find Xauthor* 将查到的所有文件要么sudo chmod 777 要么rm掉
  4. startx切换回来重新登录即可

2月2日,二月份第一个工作日。老大道佳和同事阳仔来了,技术组的三人总算全部到齐。再加上辰光大师兄,讨论时总算有了许多技术成分加入。此时,对产品未来开发的开发变得有了冲击和富有信息量起来。期间,道佳和阳仔(其实阳仔能力很强)提到了代码重构的概念。自己之前也有所感悟,这次找到共鸣有些高兴。

关于重构

有前几篇日记的缺点做借鉴,这里分点列出我的想法,力避废话和漫无头绪。

重构是经常出现的

起因是,身为技术的我们接手的是外包团队的一期作品,随着更高产品需求的提出,代码自然做了一番又一番的增删改查,渐渐地,我们愈发察觉到推倒重来似乎比继续修改来得更长远和轻松。今天对员工权限模糊问题的讨论是压倒骆驼的最后一根稻草。在讨论时,道佳提到重构是程序员避不开的环节,所谓两月一重构。我认为很有道理,诚如辰光在之前所说,产品的商业模式是会随市场反响改变的。这样,阳仔的事例就很好解释了——他在之前的创业团队当过技术,写代码时,他说到“我写的代码只能用2个月,这两个月后恐怕需要你们找跟你们一起做下去的技术重新写一遍。”

重构来自新需求或新思想

产品在推出后,导向不可避免受到外界的影响。补丁打多了,衣服自然变得不适合穿。老版的代码经常跟不上方向的迅速变化,重构是最理想也是最有效的解决办法,治标且治本。另外,这里新思想是指对数据结构或身份权限等基本模型有了更深的认识抑或外界因素迫使基本模型做出适应(如用户量的庞大将考验数据表的设计),这次我们将要作出的重构一部分就是因为这个原因。

重构是产品与技术的平衡点

产品设计和技术开发的思路刚好是两个不同方向。产品设计讲究MVP(Minimum Viable Product ),意为产品的最初设计一定要抓住核心,把产品的主要价值展现出来即可。拿给用户反馈后,再看情况做后续设计。因为,这样在成本上最节省,且成功概率最大。“迭代”一词在这里是最佳的形容,推出=>反馈=>复推出,如此周而复始,雪球越滚越大。归功于互联网的快速,可以“小步快跑”的传统行业互联网化将有很美好的场景(可惜的是,汽车等传统行业做不到),在短期内滚成很大规模。因此,初期产品追求短小而精悍,很忌讳全面。

理想化的技术恰相反,毕竟只有对产品有了全面细致的思考,才能使保证产品在技术上的长时间可靠性。如,模型设计,数据表设计。这些正像大厦的地基,地基牢固,楼才搭得高。可是,绝大多数情况,产品等不了那么久,没有全面思考调研的时间,只能像上文提到那样,先做出突出主体的一部分。这样技术就不得不在新需求的压力下,对地基进行小范围修改,以保证产品的可靠性。可以想见,这样搭上去的楼注定不会牢固。

重构恰好是两者中的平衡点。重构给了技术喘口气的时间,也能满足产品方面的新需求。正是由于它的普遍存在性。很多公司其实是一边打补丁,一边给自己铺后路设计新技术架构的。

MVP与产品成功三内因

上文中也提到了,产品的设计是有讲究的。在初期设计时,一定要把握住MVP的思路,只呈现核心价值,用最小可验证产品证明它的可行性。微信就是个很典型的例子,1.0只推出了聊天功能,之后的摇一摇,朋友圈,支付等都是一点一点加上去的。充分的缓冲时间和较快的互联网产品周期,让它能稳步上升。它的内因是,未来无法预知,最小代价实验,随机应变是最放心的。好的产品经理不用识别未来,只要能识别好产品现在的走向就不错了。反过来看初期,若有的产品设计的面面俱到或是团队承诺已考虑到未来,多半走不远。

产品在设计上有成功的三内因。一,满足刚需;二,用户黏性;三,用户体验。这里以师兄提到的找朋友出去玩的app来讨论。

满足刚需

刚需是什么?就是在某种场景下,满足某一部分人的必需。以例子为例,它满足了在找不到熟人却想进行体育活动等时的需求。刚需最好别无取代,当有所取代时,可以尝试缩小用户群,提高针对性。

用户黏性

满足了刚需,就会有人用。但这还不够,足够的用户黏性才能保证产品活下去。黏性的最好衡量因素就是使用频次。以例子为例,休闲活动对于大多数人来说一周一到两次,这样的频次实在不算高。

用户体验

用户体验即产品价值。价值=值 - 价,只有用户使用产品时的显性+隐性花费小于得到的体验,才会被留下来。即产品大于用户的预期。它是用户黏性的保证。

写了这么多篇日记,似乎以产品为多了。道佳、阳仔过来后,但愿在技术上也能得到真知灼见。

0%