软件开发

创造需求,还是迎合需求?——兼答刘润老师《做比客户更好的产品经理!》

本文是关于我一个多月前在知乎上提的一个问题“计算机/互联网产品,是该创造需求,还是迎合需求?”的。原问题如下:

“俞军PM12条”里面有这么一条 :“用户是很难被教育的,要迎合用户,而不是改变用户”, 这应该也是一种很传统的产品设计和用户体验的思路。
这往往是因为程序员习惯用自己的思维去设计功能特性,或者设计出一些“食之无味弃之可惜”的功能或产品,造成用户不满。 但另一方面,正是苹果创造了我们对 PC 的需求,对智能手机的需求,对平板电脑的需求。类似地,正是很多颠覆性、创造性的新产品的出现,才引发了生活的新改变。
各位前辈在做产品时,如何权衡这两者?

这个问题一开始没得到多少回答,后来我因为家事、公务、项目、找实习等忙得不可开交,也就把知乎扔一边了,今天偶然地去看了一下,才发现很多朋友对这个问题作了解答,微软的刘润老师还特地写了博文《做比客户更好的产品经理!》 讨论这个问题。

刘润老师的意思大致是:所谓“创造需求”是不存在,实际上还是创造产品来迎合客户的真正需求。这个需求不一定是客户表达出来的,而是需要求发掘出来的。

对此,keso评论道:

我看了你的文章,但我觉得你把问题说得太绝对了。在纸烟出现之前,客户有抽纸烟的需求吗?在啤酒被引入中国之前,中国人有喝啤酒的需求吗?需求真的不能被创造吗?纸烟和啤酒所对应的真实的需求究竟是什么?为什么会被纸烟和啤酒这种产品满足?

确实是众说纷纭,也有不少人说我这个问题是伪命题,我想这样解释:

我把产品上的改进和创新定义作“迎合需求”和“创造需求”。这是狭义的,前者是一小步,后者是一大步,归结起来都应该是宏观上的“迎合需求”吧。关键是你把这个需求看成是客户表达的需求,还是客户真正的需要。“求”字本就有表达诉求之意。这或许也能说是文字游戏罢了,大家的意见差异并不大。

实际上,刘润老师可以说是从宏观或者说本源上讨论这个问题,他的观点我基本也同意,但是我关心的是,这如何做到?找到客户的真正需求,谈何容易。在操作层面上,产品设计者和决策者往往都会面临着我所提的这个问题,不管他们的称谓是迎合需求不是创造需求。

我认为问题可以这样分类讨论:

1)产品定位和设计上

正如上面所引Keso的话,有一些需求是原来想都没想过的,如果解释作“人们追求更美好的生活”之类未免过泛而变得没有讨论的意义。是设计一种与时下产品相近,具有代替性而又有所创新的产品,还是创造一下具有颠覆性的产品,从另一个角度来满足用户的真正需求?就比如原本市场上有MSN、QQ等IM,你是再做一个类似的IM,还是创造出一个Facebook、Twitter来满足人们交流、获取和输出信息的需要?

2)产品具体实现上

“需求”一词在产品设计中应是更趋向于满足用户直接需要。在软件工程的前期我们必须了解用户需要的是什么,用户虽然不关心或者不擅长于具体的实现,但他们可能已形成一些使用习惯,这让设计者和实现者往往不得不去迎合它们。

就比如Mircosoft Office2003到2007,应该说界面变化是比较明显的。这直接导致了很多初级用户在使用前期十分苦恼,至少我就经常在课堂看见很多老师对着Powerpoint2007手足无措,完全找不到那个地方点下去可以把PPT放映出来。

这算不算Office 2007设计上的欠妥呢?这真不好说。它确实比以往版本更人性化,更美观,但它终究给用户带来了学习成本。除了用户习惯的问题之外,还有很多类似的“向前兼容性”问题。这向来都让计算机、互联网产品设计者又爱又恨,如Intel CPU、Windows中就有很多涉及为了向前兼容而牺牲效率、效果的设计。

所以我这里的问题是:设计者如何在此时来权衡,是打破常规还是“微创新”?

当然这见仁见智,经典的“Don’t make me think”自有它的道理,但如果一直照顾用户的习惯和向前兼容显然会束缚位设计者和实现者的手脚,而且会让一些喜好新奇的用户觉得无新意,从而转向新的代替品。

希望能听到关于这个问题更多的讨论。

如非说明转载,本博文章皆为原创,转载请务必注明文章出处: 转载自慎思琐识录 作者:慎思

本文链接地址: 创造需求,还是迎合需求?——兼答刘润老师《做比客户更好的产品经理!》

一个有趣的编号问题的C语言实现

题目来自网友分享:腾讯算法面试题 算法与代码

题目如下:

给你10分钟时间,根据上排给出十个数,在其下排填出对应的十个数。要求下排每个数都是先前上排对应那个数在下排十个数中出现的次数。

上排的十个数如下:

【0,1,2,3,4,5,6,7,8,9】

题目是比较简单的,我用C语言实现如下(引文中有java实现),其中输出中间过程的结果,最后输出总次数:

#include <stdio.h>
#define N 10

int temp[N];

void printTag(int tag){
     printf("-----Tag %d------\n", tag); 
     int i; 
     for(i=0; i<N; i++) 
                printf("%d ", temp[i]); 
     printf("\n"); 
} 
 
int getNew(int index){ 
        int n = 0; 
        int i; 
        for(i=0; i<N; i++) 
                if(temp[i] == index) 
                        n++; 
        return n; 
} 
 
int main(int argc, char** argv) { 
        int chs, i, newN, count = 0; 
        for(i=0; i<N; i++) 
                temp[i] = i; 
        printTag(0); 
        while(++count) { 
                chs = 0; 
                for(i=0; i<N; i++){ 
                    newN = getNew(i); 
                    if(newN != temp[i]) 
                        chs = 1; 
                        temp[i] = newN; 
                } 
                if(chs==0){ 
                    printf("\nIt takes %d times.\n", count-1); 
                        return 0; 
            } 
            printTag(count); 
        } 
} 

这里我把10设作常量N,N是可以改变的,只要N大于3。若N为1、2,无意义,若N为3,效果等于N=4,但不能直接将程序中N设作3,不然会有死循环。

多试几个N值,就会发现一个通用的规律,即:

0位对应N-4,1位对应2,2位对应1,N-4位对应1,其他位对应0。

引文中提到“这个算法可以用到数据压缩领域”,我暂时没有想清楚这是如何实现,不知大家没有想法?

如非说明转载,本博文章皆为原创,转载请务必注明文章出处: 转载自慎思琐识录 作者:慎思

本文链接地址: 一个有趣的编号问题的C语言实现

The C Puzzle Book·C语言解惑

C语言解惑的评论
一、操作符:
1.+=,*=等符号是赋值符,优先级等同于=;C语言解惑

2.对于可能产生二义性的字符,如”x+++++y”,C语言编译器将按照”构成操作符的字符个数越多越好”的原则来作出选择,于是有”x++ ++ +y”;

3.对于“z = x / ++x”这样的表达式,编译器能给出不同的答案,这是由于C语言本身没有对这种情况作出规定;

4.定义宏
#define PRINT(int) printf(“%d\n”,int)
可对任何int进行替换;

5.同上一条,若改写为
#define PRINT(int) printf(#int”=%d\n”,int)
则在C语言的预处理器中,#int将被替换成int 所代指的变量名,并将入合并入后面的双引号中;

6.在对二进制负数进行右移(>>),正负是不确定的,结果依编译器而定;

7.对式子
z+=x<y?x++:y++
的解读应为
z+=(x<y?x++:y++);

8.对操作符优先级来讲,&&是高于||的,而不是同等级别;同理,&,^,|也是递降的级别顺序;

二、头文件与预处理器:

1.合理地使用宏定义,可以使程序简洁,编程方便,但使用不恰当常会带来难以调试的错误,在分析此类问题时,应把替换内容重现出来才更容易看出原因;

2.使用宏有如下规则:

1)只要一条宏定义语句是包含有操作符的,就应该用括号把它括起来;
注:特别是对于*,/,for(..,..,..),if(..)else(..)等符号语句,只读取与之相关联的一个字符或语句,更容易出问题。

2)宏定义越紧凑越好,表达式比语句好,单条语句比多条语句好;
注:在定义时可将”;”替换为”,”,使结构更紧凑。

3)在宏定义里一定要注意避免使用会导致二义性或副作用的C语言元素(如自增自减);

3-1)在定义里避免使用有副作用的表达式,比如:这些元素在宏定义语句里只出现一次,但在实际扩展中可能会出现多次,将使结果错误;

4)一定要让宏进行扩展而得到的字符串——不管它是一个表达式,一条语句(不包括表示语句结束的分号),还是一个语句块——成为一个完整的C语言元素;
注:若有else不对称问题,可以在定义中加上空的else子句。

5)宏越简单越好。如果无法得到一个简单的宏,就应该把它定义成一个函数;
注:##字符可以合并它的两个操作数。

如非说明转载,本博文章皆为原创,转载请务必注明文章出处: 转载自慎思琐识录 作者:慎思

本文链接地址: The C Puzzle Book·C语言解惑

第一次读它·数据结构(C语言版)

前后经过三个月的时间,终于把它看完了。好久没有这样看书的感觉了,自己从小学初中时代之后。一向学编程的方式就是Try,一直没有读书的习惯。昨晚还是在半夜睡不着的时候拿着手电筒在床上把它看完的。看完感觉一种解脱。 数据结构(C语言版)

这本书在读时就感觉到perfect,虽然它并不难读。说来见笑,里面最花我时间的是那些公式推算,自己推算竟都花了我不少时间,作为数学专业的学生实在惭愧。再者就是代码了。看看算法还是花一点思考时间。因为第一遍还不想上机打代码,所以有些算法一时想不通就只能自己写实例在纸上推演了。感觉还是不错的。确实一直以来就没有完整的算法思想,写程序都是根据直觉或者说一时的“灵感”,实在算不上规范化编程,更谈不上效率。所以读这本基础书对我来说作用会是很大。读数据结构也是学习其他众多计算机课程的前提,所以以后要多次地阅读、实践这本书所教的内容,直至将它吃透。

如非说明转载,本博文章皆为原创,转载请务必注明文章出处: 转载自慎思琐识录 作者:慎思

本文链接地址: 第一次读它·数据结构(C语言版)

Go to Top