使用django的ImageField和forms from models快速制作上传图片表单

No Comments

需求描述:

做一个简单的注册页面,使得用户在注册页上传头像。

解决办法:

以前用java写这个的时候,在action上面需要用IO接受文件,然后生成一个文件名,再将文件相对路径保存到user表的img字段中。而在django的model层上,有一个叫做ImageField的字段(还有FileField,两者几乎一样),看了文档中对于这个字段的描述,大致意思就是自动将文件保存在media的文件夹里面,然后产生的文件路径保存到一个var char的字段中。如果一个model有ImageField字段,则在其对应表里面就会有一个var char字段,正是用于保存路径的。

 

1.设置setting中的MEDIA_ROOT:

如果使用django的快捷方法,那么所有用户上传的文件应该都会被保存到MEDIA_ROOT定义的文件夹中去。注意这里需要绝对路径。我的设置是:

# in settings.py
HERE = os.path.dirname(os.path.abspath(__file__))
MEDIA_ROOT = os.path.join(HERE,'media').replace('\\','/')+'/'

这样就能将MEDIA_ROOT设置为项目目录下的media目录。注意最后的斜杠,如果不加最后的斜杠,那么在保存的时候会出现奇怪的错误。

 

2.设置model:

为了方便,自己建了一个User的Model:

# in myapp1/models.py

class User(models.Model):

    name = models.CharField(max_length=30)

    password = models.CharField(max_length=30)

    GENDER_CHOICE = (

        (u'M', u'Male'),

        (u'F', u'Female'),

    )

    gender = models.CharField(max_length=2,choices = GENDER_CHOICE)

    birthday = models.DateField(null=True,blank=True)

    img = models.ImageField(upload_to='photo',null=True,blank=True)

    phoneNum = models.CharField(max_length=13,null=True,blank=True)

    email = models.EmailField(null=True,blank=True)

    hobbies = models.CharField(max_length=100,null=True,blank=True)

    regTime = models.DateTimeField(null=True,blank=True)

    bio = models.TextField(null = True,blank=True)

    def __unicode__(self):

        return self.name

这里要注意的地方是null=True之后,要也要加上blank=True。其中null=True是针对数据库的,而blank=True是针对validation的。如果blank=True没加,那么在下面做form的时候,省略字段的话验证不会通过。

这里面有一个img字段,是ImageField类型的,这个在快速制作上传图片的表单里起了至关重要的作用。里面有一句upload_to=’xxxxx’,是指文件保存在MEDIA_ROOT中的哪个子目录下。

 

3.设置forms from models:

django有一个form类,这个类抽象出了html的form。用在view里的话,就能在template里生成form的html。但是可以发现用户注册时,表单的字段和model的字段非常相似,所以可以通过model生成form类。

而model类里面并不是所有的内容都需要用户填写,比如regTime就不需要。这时候可以指定那些字段会成为form字段(使用fields=(xxxx)),或者可以指定哪些字段不会成为form字段(使用exclude=(xxx))。这里,我们似乎只有一个regTime不需要显示。

另外,我们的model里面password字段是CharField,django不会聪明到通过变量名的意思来生成form,所以默认生成出来的会是input type=”text”的表单,我们需要通过一种方法修改掉它。综上所述,最后的form代码是这样的:

# in myapp1/models.py

from django.db import models

from django.forms import ModelForm

from django import forms

class UserForm(ModelForm):

    class Meta:

        model = User #通过上面的User Model生成表单

        exclude =('regTime')#将regTime字段排除在外

        widgets = {

            'password':forms.PasswordInput(),#将password字段的input type设为password

        }

这样就能生成一个简单的form了。forms from models和普通的form类有一个区别,就是它有save()方法,这个方法在view中将会被使用。

 

4.在view里调用form

这里,假设注册页面为/reg/。如果使用get方法,则浏览器中给出注册表单,如果用post方法,则将表单内容保存到数据库。

如果使用forms from models,则在view上面将会非常的简单:

#in myapp1/views.py

def reg(request):

    if request.method == 'POST':#提交表单

        form = models.UserForm(request.POST,request.FILES)#如果表单中要传文件、图片,则需要传两个参数

        if form.is_valid():#这个is_valid通过model的配置定义,这里显现出blank=True的意义了

            form.save()#这一句save,不但保存了各个字段,而且自动将上传的文件保存到指定目录,并且生成文件路径,保存到user表的img字段中了。

    else:#显示表单

        form = models.UserForm()

    return render_to_response('reg_form.html', {'form': form})

 

5.template中的使用:

<body>

    <form enctype="multipart/form-data" action="/reg/" method="post">

        {{ form.as_p }}

        <input type="submit" value="Submit" />

    </form>

</body>

这里和普通form是一样的。当然也可以手动设置格式,详见文档。

最后再配置一下urlpattern,就能在这个表单上传图片了。

 

不足:

单单这样做注册表单有个不足之处,就是没有confirm password这个字段。不过我们可以在UserForm类中增加一个表单字段,最后结果会是:

 

不过这样一来,template中生成的表单,会把confirm_password字段放在最下面。所以得手动设定格式。另外,form.is_valid()也不会监测password和它是不是一样,需要在后面手动加逻辑。

上面的方法不一定是最好的,不过也提供了一些思路。另外,即便是不使用forms from models,也可以方便的使用ImageField保存图片:见http://www.nitinh.com/2009/02/django-example-filefield-and-imagefield/

 

class UserForm(ModelForm):

    confirm_password = forms.CharField(widget=forms.PasswordInput())

    class Meta:

        model = User

        exclude('regTime')

        widgets = {

            'password':forms.PasswordInput(),

        }

访问media目录:

media文件夹里的内容需要使用urlpatterns映射才能访问。在urls里面添加:

urlpatterns += patterns('',
        url(r'^media/(?P<path>.*)$', 'django.views.static.serve', {
            'document_root': settings.MEDIA_ROOT,
        }),

HTML tags 可包含关系问题

No Comments

昨天提交xhtml assignment的时候被问到标签p和标签div之间嵌套关系问题,简短地说,为什么这样是对的:

<div>
    <p></p>
</div>

而这样是错的:

<p>
    <div></div>
</p>

起先一直找不到为什么,网上也没有什么文章,后来在stackoverflow问了问题,也向人人的好友问了,于是得到了解答。

首先从现象来看,浏览器碰到第二种错误写法时,读到<div>这个标签的时候,自动会将上面的<p>标签结束。所以会被解析成如下的形式:

从原理来讲,<p>标签内不能嵌入div是由dtd规定的:

在xhtml1-transitional.dtd的时候可以发现这些语句:

<!ENTITY % inline "a | %special; | %fontstyle; | %phrase; | %inline.forms;">
<!ENTITY % Inline "(#PCDATA | %inline; | %misc.inline;)*">
<!ENTITY % block
    "p | %heading; | div | %lists; | %blocktext; | isindex |fieldset | table">
<!ENTITY % Flow "(#PCDATA | %block; | form | %inline; | %misc;)*">
<!ELEMENT p %Inline;>
<!ELEMENT div %Flow;>

这些语句意味着p里面能放%Inline类的内容,而div里面能放%Flow类型的内容(Flow包含了%inline的内容和%block型的)。
所以p里面不能放div标签。同理,所有标签里面能放哪些标签,也可以从定义里面看到。

 

占课现象以及一个可能解

No Comments

占课现象现在日趋严重,几乎到了没有关系就选不到好课的地步了。

之所以有占课现象,在制度上是由两条规则引起的。一条是年级优先权大于绩点优先权,另一条是第二轮选课的时间优先制度。

对于第一条,是无可厚非的。因为要保证高年级同学可以正常毕业。但是两条规则合起来,则变成了占课漏洞。

分 析占课机制,其本质是使用了信息不对称方法。即高年级的A和第年级的B互相协定在第二轮选课的某一个时刻交换课程。按照时间优先制度,在A退课到B选课的 这段时间里,全校学生抢占此课程的几率是一样的。但是通过信息不对称方法,全校只有B知道在这个几秒中的时间段里是可以选课的,这样就大大提高了B抢占课 程的几率。这样的话,除非B的运气实在很背,被恰巧抱着试试心态的C刷到课了,不然一定能抢占这个课程。

解决这个问题方法,就是打破这个信 息不对称,让全校学生都知道在某个时间段是有均等几率刷到课的。一个可行解就是将第二轮选课的规则做如下修改:以n分钟为时间间隔(比如30分钟),在第 一个30分钟内只能退课不能选课,在第二个30分钟内只能选课不能退课,以此类推,循环往复,直到第二轮选课结束。

这样,A和B就无法协商在某一时刻利用信息不对称来快速交换课程。因为所有学生都知道只有在某一个时间段才能刷课,此时所有人刷课的几率几乎是一样的,这样就大大降低了占课成功的几率。

此方法有一个副作用,即每次到了可选课时间段,必然有大量的同学尝试刷课,对教务处的服务器有非常大的压力。但我认为这个副作用并不会持续很长时间。因为大家都会知道占课非常困难,那么自然不会有人去选择占课了。

个人逻辑能力有限,无法证明上面的方法没有漏洞,也暂时举不出反例。

以上方法灵感出自GFW间断性干扰Gmail。

关于这几天的面试、笔试

1 Comment

除了上次参加了腾讯的笔试之外,还参加了携程的笔试、面试,新致软件的笔试、面试,大众点评的笔试、支付宝的在线评测。其中腾讯、支付宝和大众点评都在笔试后就被刷掉了。这也是在意料之中,腾讯笔试的时候自己根本没有复习过,所以虽然题目都见过,但是就是做不出来。大众点评和支付宝都有大量的限时数字、图形推理题,基本上是测智商的那种,我智商也不是很高,所以基本上没什么戏了。

下面具体讲一下每个笔试的内容:

 

支付宝网测:

基本上是智商题。关于智商题,可以参考欧洲标准智商测试这类的题目,我觉得如果训练一下的话应该可以得到很多提升。另外支付宝的第一部分竟然是高中物理题,基本上是中等难度的大题目,不过要求一分钟一道实在是吃不消。

 

大众点评:

分为两部分,第一部分是纯粹智商题,和支付宝一样,略简单一些。智商题细分了三部分,语言逻辑(比如“xx之于xx就像xx之于xx”),数字推理(各种形式的数列等等)以及抽象逻辑(图形的推理)。第二部分是编程题,一共两道题。第一题是“有一个不重复数组,数组里的数字的值在1~N之间。求出数组中数对的个数,这种数对满足两个值加起来等于N+1”.这题如果用O(n2)的穷举法是肯定可以求出的。我算法不好,写上去的就是穷举法。。。第二题是关于海量数据排序,原题是“2亿个数据排序,写出可行算法以及伪代码”。对于这个,我没接触过,就瞎写了,当时写的是用归并排序,不过后来想想归并排序最坏情况的时候还是要把所有数据放到内存中的。

 

携程:

携程是唯一一个让我进入复试的大公司。今天下午刚刚复试完回来。

我并没有应聘携程的软件开发,而是应聘了前端(因为他们后台全部是微软的产品,不太喜欢)。一共笔试了两次(两场,中间隔了一个星期)。两次笔试完全没有专业题,他们的技术总监讲是因为学校的东西和实用的脱节太厉害了,所以不考专业。

第一次笔试是给HR初选用的,第一部分也是智商测试。但是携程的智商测试难度和支付宝完全不是一个等级,里面的数字推理基本上一眼就看出答案了。第二部分是乱七八糟的简答题,三个问题:1.你对枪打出头鸟的看法;2.你对前端工作的看法;3.你最喜欢的官网是什么,并说出理由。这个显然就扯扯淡了。

第二次说是面试,结果也是先笔试。笔试有两道题。第一道题是所谓的“palapala表达式”。也就是定义一些“palapala”表达式以及对应的数学公式。比如$x.x+1就是f(x)=x+1;($x.x+1)4就是4+1=5等等。然后给出一些一长串的表达式要你化简。如果心细的话,死做一定能出结果的,如果聪明的话肯定能找到窍门。而我是一个粗心的笨蛋,所以第一道题有一小题做错了。不过这道题做错的人特别多,而且错误答案跟我一样。我不知道是答案错了还是我们错了。第二题是设计题,给出一个表格,把用户按键时间、移动鼠标时间、手从鼠标到键盘来回移动时间、心理反应时间等全部量化,设计出一个程序的界面,该程序用来把华氏度换算成摄氏度,或者从摄氏度换算成华氏度,要求用户所用的时间最少。这道题我首先想到了google翻译,输入即时出结果,全程键盘操作,本来想应该是最优解了,不过考官说不是最优解。然后我又想了很久,终于想到了一种方法,可以再减少0.1秒的时间,考官说这确实是最优解。另外,这次是一边面试一边笔试的。也就是做完了给考官看,考官跟你说你做错了,或者不是最优解,然后再回去做。就我目测,第二道题作出最优解的也有不少。有一个同学当场就被录取了,而我则是回去等电话的(基本上是没戏了)。

 

新致软件:

这是目前为止唯一录取我的公司。是一个外包公司,之前属于软件作坊,现在好像挺大了。

这个公司来我们学校开宣讲会的时候,加上我一共才4个同学去了。然后当场就笔试+HR的面试了。笔试题目是数据结构、C#、Java、C、数据库、逻辑题。外加一份性格测试。数据结构相对比较简单,因为之前复习的缘故,应该都没什么问题。C#和Java也非常简单。而C语言的问题就恶心的不得了了。全部是各种指针,各种花样,后来看了成绩基本上没做对过。数据库的题目有一道没做出来。逻辑题一共两题,全部做错。

逻辑题的第一题我还记得:4个人在黑夜里过河,桥上一次只能过两个人,过河时必须有手电筒,而且现在只给一个手电筒。A过河需要1秒,B过河要3秒,C过河要6秒,D过河要8秒,E过河要12秒。那么如何让这些人在30秒内过河。

接下来是HR面试,两个面试官面4个人。我和一个延长学籍的学生一起面试,显然对比起来我就非常的有优势。这位延毕的同学技术似乎也不怎么样,所以我就开始用开源实验室成员的名义乱扯淡了。这位HR似乎也不怎么懂技术,最后只问家住哪里、想往什么方向发展之类的。我说我想往架构师发展。于是过几天电话打过来,要我去二面(技术面),把我分配到研发部面试了。研发部面试的时候,不小心把话套到Rain and Cloud项目里面去了。这个项目服务器部分确实是我设计整体框架的,也基本上起了一个架构师的作用,不过因为这个项目的思路比较怪,有些设计比较幼稚和混乱,所以也不好意思讲。而我最熟悉的Java Web项目没讲到。不过好歹也用到了Spring和Hibernate,也就讲了讲他们怎么用。然后考官问我有没有看过底层代码,答没有。然后就开始讲工资了。过了几天就说我被录用了。这也是我碰到的最水的面试。主要是这家公司门槛真的不高。顺便说一下研发部的工作,就是开发一套自己的Java Web框架(像Struts那样)。另外,这位技术官竟然把Struts读成Struct了,让我有些汗颜。

2011腾讯笔试(技术类)概况

No Comments

选择题

图论,给出一个图,求经过所有的节点后回到出发的节点所需要最短的路径。

操作系统,磁盘读取的问题,求的是最长需要多少时间。

操作系统,三个进程,需要CPU和R1,R2两个I/O设备。可抢占式schedule,求R2的利用率。

网通,TCP的send/receive函数的问题,大概是C++的函数,没碰到过。

可靠性问题,大概是概率论的问题。

求哈夫曼树以及带权路径长度。

PV操作。

一些很简单的C、C++语法问题。

and so on

 

程序填空题

1、用链表实现的栈。

2、算个人所得税

 

附加题

背景是吃豆人游戏,其实和游戏没什么关系。就是从某点出发用最少的时间(路程)经过几个节点。当然,里面有墙壁之类的东西。只要写算法思想就行。显然我算法不行,这个胡乱写的。

 

web开发专用题

这些题目我没做过,因为我不是选web开发的。基本上是javascript。比如鼠标点一下变颜色什么。jQuery写上去应该可以吧。都是非常基础的,没有什么特别难的地方。

 

基本上基础题都是非常基础的,很可惜我没复习过,基本忘记的差不多了,只是记得这些题目以前学校的考试都做过,至于怎么做就不知道了,所以很多题目是蒙的。

虽然签过保密协议,不过觉得笔试题也没有什么特色的地方,基本上是学校里的题目,所以在这里发一发。

Macbook pro 8,1引导ubuntu的方法

No Comments

按理说,在macbook中安装ubuntu应该像在macbook中安装windows一样简单,刻张光盘,然后引导就是了,可是偏偏2011年的MBP机型使用的硬件使用现有各种版本的ubuntu都引导不起来(包括linux3.0内核的ubuntu 11.10 beta1)。如果简单地使用光盘引导,在splash screen之后就会看到:

“(initramfs) Unable to finda medium containing a live file system”

这个问题困扰了我很久,在ubuntu.org.cn的论坛中提问也没有得到满意的答案。后来在国外网站上google了很久,才发现这是Linux内核在这个主板上面的一个bug,引导一半之后,系统就不认识光驱了。这个bug至今还没解决。

不过国外论坛上面已经有人给出了一个非常山寨,但是可行的解决办法,这个方法的操作如下:

解压ubuntu的iso镜像,将里面的文件全部拷贝到U盘里(注意ubuntu 11.10采用了新的技术,可能使mac os x认为iso镜像是损坏的,只能自己想办法把里面的内容提取出来了)。然后插着U盘开始用刻录好的ubuntu的光盘引导。引导到一半,系统不认识光驱了,但是它会发现U盘里存有live CD的文件,于是开始从U盘读取文件了,这样就能顺利地进入Ubuntu,并且可以进行安装。

当然,这只是在Mbp中使用linux的起点,安装好Ubuntu之后,你会发现各种各样的驱动问题。Ubuntu 11.10 beta1开始有专门的for mac版本,看说明似乎是对mac电脑进行过优化,所以推荐使用这个版本的镜像。就我今晚的测试来看,键盘和摄像头的驱动是可用的,无线网卡驱动无法找到,google了一下发现现有的内核还没法支持这个网卡,触摸板驱动是正常的,但是触摸板在Ubuntu下面的表现跟一坨屎一样,不知道怎么调整。

That’s all. Enjoy yourself.

昨天了解到的一些经验之谈

No Comments

  1. 使用思维导图来整理笔记。
  2. 当实际编程的时候突然想不起一些细节的时候,使用cheat sheet来帮助回忆。
  3. 使用轻量级的IDE,在使用配置文件的时候尽量不要依赖IDE生成,因为IDE自动生成的东西人工改起来比较讨厌。
  4. 如果有人在使用maven的时候,在pom.xml文件里面把所有依赖库全部写进去了,那他就把maven当成ant了,这是及其错误的用法。
  5. 使用komodo + zen coding插件来写html和css会很快。
  6. 前端开发要用firefox+firebug+web developer。
  7. 做Web项目开发的需求规格说明书,不要用例图和用例描述,而是要网站草图和草图中每个功能的描述,最好是做出一个静态html来,之后的后台设计都要围绕着这个界面来做。
  8. 要在写代码前做好URL的设计,之后的模块都要以URL的设计为准。
  9. 使用IM工具来开会效率很低,而且在成员之间在理解上会有偏差,尽量要有真实的会议,或者电话会议。

玩玩XBMC

1 Comment

之前我的华硕笔记本屏幕坏掉以后一直想把它专用为电影播放器,接我房间里的那个电脑。

一开始我是直接进windows,用无线鼠标控制电脑进行播放。但是这样看电影非常非常不爽,因为windows的文件管理器字都非常小,坐在床上基本看不见,而无线鼠标距离一远也有点失灵。

最近在做ST的那个项目的时候,把之前玩过的XBMC又拿出来做例子,于是萌发了用XBMC配置一个真正的HTPC的想法。由于XBMC是全平台支持的,而我也是主要使用Linux的,所以可以完全抛开windows建立这个HTPC。

安装XBMC是很简单的,我使用ubuntu,所以只要添加PPA源就行。不过stable的XBMC是不支持ubuntu 11.04的,必须使用unstable版本。当然,XBMC是有Live CD的,是基于Ubuntu 10.04的。不过我拿来跑的时候不知道怎么连接无线网络。而且它的安装方式是alternative的,我用U盘引导时会找不到光盘(光驱是彻底坏了)。所以干脆在原来的ubuntu基础上装一个XBMC。

装好XBMC之后,还要做一些配置,否则中文是没办法显示的,最简单的办法就是找到系统里面文泉驿微米黑的ttc文件,复制到xbmc的配置目录的Media/fonts下面,并且改名为arial.ttc。并且在XBMC中设置字体为arial based(不知道这步是不是多余)。然后在就可以把language调成简体中文了。并且顺带在视频的选项里面把字幕编码改成GBK,这样字幕不会乱码了。

做完这些步骤把电脑接到电视机上面就行了。接下来就遇到遥控的问题。我不知道MCE的遥控器是不是能够工作,反正我没这个玩意儿。Google了一下,发现XBMC有android手机遥控软件,通过局域网就能遥控XBMC工作了。下载了一下蛮好用的。

另外,XBMC还支持从uPnP media server上面读取多媒体文件。所以我也试了一下配一台media server。

Media server依旧是Linux配置,也是使用了ubuntu 11.04。用的软件是MediaTomb。这个软件在ubuntu的软件源里面是有的。安装之后发现UI没开,得修改/etc/mediatomb/config.xml:

<ui enabled=”yes” show-tooltips=”yes”>

<transcoding enabled=”yes”>

接下去打开软件,就能出来web ui界面。可以添加文件到数据库。而客户端的XBMC能够自动检测到upnp服务器,到时候添加目录就是了。

关于夏季学期的项目思考

No Comments

鉴于Rex同学至今没有找到什么项目,而我这边又不知道怎么找,所以可能会做一个我之前的一个想法:模仿一遍pip.io。

主要实现的是pip.io的channel功能。至于外接微博功能,如果学有余力的话会试着实现。不过看暑假本团队成员都是实习的实习,考研的考研,很可能都没有精力去做了。

目前有一个很大的困难是,pip.io的js成分非常多。而我们团队又不太会js,就连后台的java ee都没有碰过,所以我不清楚到时候能不能把功能做全了。

另外的一个小问题是,pip.io这个网站已经关掉了,所以得凭印象去模仿。而本组只有我一个人用过这个网站,所以需求分析大致就是我写了。

技术上我大致想使用Spring为基底,至于MVC框架和ORM框架目前还没有定。MVC框架候选的有Struts 2和Spring MVC。哪个简单用哪个,目前我还没研究过。ORM框架本人用过Hibernate,但是我也在考虑使用JDO。这个到考试之后再决定吧。

IDE方面可能会使用IntelliJ IDEA。因为这个IDE在代码补全方面比较出色,用起来比eclipse和netbeans要舒服一些。(而且我已经搞到注册机了^_^)

另外,在软件设计(ER图 etc.)这块我还是不清楚用什么软件比较好。软工的时候用过astah community画过UML图,感觉蛮好的,但是ER图它是不能画的,一定要购买professional版本才行,这玩意儿的注册机我就没找到过。argoUML在Mac OS X下面有bug,画出来的图基本上不能看的,还是算了。不知道这方面大家有什么推荐的。

其他方面我会继续求教各位高人指点的。。。

The END

 

自由软件的适用领域探究

No Comments

节选自我的“Linux内核”课程论文的第五章

5自由软件的发展前景

5.1软件的分类

在此,我先将软件以如下形式分类:

首先将软件分为开源软件(自由软件)和闭源软件。然后将自由软件分为有资金支持和无资金支持。再将有资金支持的自由软件分为有盈利模式的和无盈利模式但有大公司作为支持的。本章余下的部分将在这个分类下进行讨论。

5.2软件走向闭源和商业化的原因

软件走向闭源的原因最主要的就是软件受众的变化。计算机诞生初期,由于使用计算机不普及,所以使用计算机和计算机软件的,都是科学家和程序员。他们有对自己所使用的软件进行修改的能力。而当计算机越来越普及,主要受众开始成为政府、企业、学校中那些可能不懂编程的使用者时,情况就变了:他们没有对自己所使用的软件进行修改的能力,他们对软件源码的支配并不感兴趣,只是希望软件可以运行,并且给出正确的结果,他们需要软件的原作者对软件的Bug修复或是扩充新功能。这样,很多软件作者就看到了商机,将软件闭源卖给消费者使用,而自己则承担修复Bug或扩充新功能的义务。这样,现代软件业就形成了。

可以看出,新的受众群体和闭源软件之间是一个互惠共赢的良好关系。他们之间产生了良好的生态关系,使得越来越多的软件走向闭源。

5.3GNU运动的原宗旨

从历史上看,GNU运动恰好出现在受众转变的历史转折点上。从上面的分析来看,良好的生态圈子使得更多的软件商和实验室开始融入闭源生态圈。这引起了以RMS为主的老一辈程序员的不满。因为他们无法拿到软件的源代码,对他们来说,买一个闭源软件只能拿到软件的使用权,其它的权利,比如修改、分享修改成果,被剥夺了。他们认为这不公平,也不自由。在这个情况下才提出GNU计划。GNU计划的原宗旨就是保护软件的使用者原本该有的对软件的完全的支配权。

5.4CopyLeft体系与传统CopyRight体系的根本区别

CopyLeft体系的许可证与闭源软件的传统CopyRight是有根本性不同的:它们所保护的对象不同。从上一节可以看出,CopyLeft体系许可证的保护对象是使用者,它强调使用者以合法渠道得到软件后,必须对这个软件有完全的支配权。而CopyRight保护的是软件作者,它通过对软件使用者的权利做种种限制,达到对软件作者通过该软件获利的保护。

5.5两类软件受众情况

从第一、二节可以看出,在GNU计划诞生之初,自由软件阵营的受众与闭源软件的受众是不一样的,即一个面向高计算机水平的程序员、黑客,另一个面向不懂编程的普通客户。

而在当前,我们可以明显地发现,在家用、办公领域,自由软件占的比重是相当小的。比如Linux桌面占有率在全球范围内一直在1%左右。而在服务器领域,自由软件所占的比重却非常高。再以Linux为例,其巅峰时期市场占有率超过了60%,而且除了Linux之外,业界常用的BSD系列的操作系统亦是自由软件的一种。

从这些简单的数据可以看出,自由软件与闭源软件的受众从GNU诞生之初就没有太大的变化。下面就着重分析这个现象的原因。

5.6为什么自由软件大多都是免费软件

虽然各种开源协议都没有规定自由软件不能被销售,但是事实上很少人会这么做。因为源代码是可以被任何人拿到的,所以对高手来说,只要对源码进行编译,就能得到一份免费的副本,根本不需要花钱。而只要有一个人将编译好的二进制副本免费公开发行,那么任何人都能得到这个免费的副本。即便是没有人免费发放副本,也会因为同样原因,使得几个人之间展开价格战,最后使原作者的收益为0。所以自由软件是无法卖高价的。

5.7无资金支持的自由软件在桌面领域的困境

所谓无资金支持的自由软件是指单纯依靠个人兴趣和信仰来开发的自由软件。虽然他们可能使用受捐助的方式从自己开发的软件中获得一点利益,但是这不是一个稳定的收入来源。

由于没有稳定的收入来源,所以开发者并不可能将自己的全部精力投入到这个软件中,而只是使用业余时间开发,所以功能相对比较少。而且,相对于大公司的闭源商业软件,这些无资金支持的自由软件大多是没有专业的人员去设计用户界面,而是编码的人以自己的想法进行设计,也没有经过大量的软件测试。所以设计出来的用户界面很可能不友好,也可能Bug非常多,这是普通桌面用户无法接受的。对桌面、办公领域的用户来说更加无法接受的是这些软件大多没有良好稳定的技术支持,而且由于你并没有花钱买软件或是买服务,所以软件作者是没有义务为你提供技术支持。

这样一来,无资金支持的自由软件在普通的桌面领域发展的并不好。

5.8传统盈利模式自由软件的困境

既然自由软件本身不能卖出高价,那么很多人都想到了出售技术支持来获得收入。对于开发者来说这样可以盈利,于是他们可以将自己的主业投入在自由软件的开发之中。这样对于不懂编程的,或者是没法完全以自己的水平去解决软件Bug的用户来说就得到了技术支持。这样看似是一个非常好的良性循环。

Red Hat公司就是以这样一种盈利模式生存的(当然Red Hat是将自己的Linux分成RHELFedora两种,对前者收费,由公司提供更新支持,对后者免费,由社区提供支持,实际上就是向企业收取技术支持费用)。

在很多时间里,Red Hat这种模式几乎是非常成功的。很多大的公司都采用RHEL作为服务器系统来用,RHEL在服务器市场的占有率相当的高。Red Hat公司推出的RHCE认证考试为众人追捧,成为服务器管理界的顶级认证,也能证明Red Hat的成功。

然而Red Hat公司在近几年却碰到了一个困境。由于他们要为他们的用户提供软件的更新,就要直接修改GNU/Linux系统。由于GNU/Linux系统下面的软件包是由GPLLGPL授权的,修改它们之后必须开源发布。所以Red Hat公司就必须发布他们修改之后的源代码。而Red Hat公司确实投入了大量的人力、财力在改进Linux,以至于长期以来一直是对Linux代码贡献最多的公司。这些被Red Hat改进过的代码,甚至是RHEL本身的代码都可以被别人拿来重新编译并发布。于是出现了像CENT Os这样的,将RHEL整个重新编译之后免费发布的发行版。当然这对Red Hat来说不是什么威胁,因为CENT Os是社区产物,并不提供付费技术支持,和Red Hat没有造成竞争的关系。然而当Red Hat的竞争对手Oracle公司也看中了Linux技术支持盈利这块,并且把RHEL的源码拿过来重新编译之后发行Oracle Linux,并且提供相同的技术支持收费服务。这对Red Hat来说打击是很大的。这就有点像中国之前的人民公社一样,干的多的人反而越是遭到不公平待遇。

为了解决这个问题,从RHEL6开始,Red HatRHEL做了很多改动,目的就是给竞争对手设置壁垒。然而,这只是暂时解决问题的小技巧,而不是制度上的长远之策。

造成这种问题的原因正是因为GPL这样的CopyLeft只保护了使用者的权利,却没有保护作者的权利。在一个有着跟明确的生产者——消费者角色分化的模式里,CopyLeft无法避免“人民公社现象”。

5.9兴盛的开源框架与服务器软件市场

现在做程序开发大多都是使用各种框架来开发。比如在大多数企业都使用的Java EE方面,目前最流行的是Spring(Apache许可证)+Struts(Apache许可证)+Hibernate(LGPL许可证)框架。新兴的开发工具、开发框架,比如PythonDjango(BSD许可证)Ruby on Rails(MIT许可证)以及诺基亚的QT(LGPL许可证)都是使用开源的许可证。

而在服务器软件市场,目前最为流行的组合是Linux, Apache或者nginx, Mysql套件,而这些也全部都是自由软件。

为什么在开源框架方面和服务器软件方面,自由软件的发展又会这么好呢?这是因为,在这些领域,软件、框架的受众无一例外都是计算机业内人士。这个受众的情况恰好与GNU计划提出之前,软件的受众是一样的。这并不是巧合,我认为,如果软件的受众是计算机业内人士的话,CopyLeft系列协议可以很好地保障所有人的利益。

以开源框架为例。使用框架来开发软件可以很好地节省成本,所以大家都乐于使用框架。而使用框架的用户必定是程序员,他们不仅有使用框架的能力,也有修改框架的Bug、提升框架性能、加入新特性的能力。这时,如果使用一个闭源框架,开发效率就会大大降低:程序员无法为自己的程序定制新的特性,也无法修改里面可能出现的Bug。而使用开源框架,他们就能做到这些。这时,开源许可证就会发挥重要的作用。比如LGPL会强制使用者对原框架的修改部分开源,而其他的开源许可证也能鼓励或促使新的代码开源。这样,开源框架就越来越健壮。这在服务器市场也是相同的。

之所以说开源许可证能保护所有人的利益,是因为在这个受众群体中,没有明确的生产者——消费者的角色分化。这个社区中,使用者又是作者,对于使用者的保护就是对作者的保护。虽然开源框架、服务器软件并不能赚钱,但是使用他们却可以省钱,这也是获利,而且是大家都获利的局面。这就是一个良性循环,也是开源理念在框架、服务器方面兴盛的原因。

正因如此,目前的一些大公司也迫切希望融入开源框架的开发社区中,这样他们就会赞助那些开源框架开发社区。于是,这些开发社区虽然没有盈利模式,却有资金的赞助,整个项目就进入可持续发展阶段。

5.10Google模式

Google公司近几年一直在不遗余力地推广他们的开源产品,最著名的就是Google Chrome浏览器和Google Android系统。这两个产品的受众都是普通消费者,是有明确的生产者——消费者模式的。

从上面的分析来看,在有明确的生产者——消费者模式中,自由软件应该面临困境才对。然而Google的模式却与以往的开源盈利模式完全不同。

android为例。Google围绕Android系统的盈利主要是两个渠道:一是靠对Android Market中付费软件的提成,一是靠移动平台的广告。这两个盈利渠道只是围绕着Android,却不是直接来自于Android

Google目前是互联网广告方面的绝对垄断者,互联网广告也是Google的主要收入。Google推出Android的目的非常明确,就是通过Android开放的特性,使之广为传播,而Google借助Android传播速度,快速占领手机广告市场。

一个Android软件开发者要盈利,主要通过两个渠道。一是在Android Market上发布付费软件,二是发布免费软件,在软件中贴上广告。如果选择第一种模式,Google便可以收取提成。如果选择第二种模式,那么开发者必定会选择Google这个互联网广告垄断者作为广告供应商。所以无论如何Google都能盈利。

Google不怕别人把Android源码拿来,复制一份在发布出去。因为别人传播的越快,它在手机广告市场的占有率也越快。

这就是Google模式:它本身的主业与自由软件完全无关,但是能通过自由软件的推广,拓展自己主业的市场。

除了Android之外,Google推出Chrome浏览器,赞助FireFox浏览器这些举措,也是同样的道理。

值得一提的是,GoogleAndroid的许可证把握的恰到好处。除了Linux Kernel之外,Android的大部分代码都使用Apache许可证2.0来授权。这样,对于开放手机联盟的别的成员,比如HTC,摩托罗拉等手机生产厂商,可以对Android原始版本进行比较大的修改而不必开源。这样有助于各个独立的手机制造商保留自己在软件上的商业机密,而Android依然在Apache许可证下广泛传播。

5.11本章结论

通过以上的分析,我认为自由软件在以下情况下会发展迅速且持久:

没有明确的生产者——消费者模式,即受众为拥有同样编程能力的程序员。

大公司核心业务与软件无关,但是自由软件能够促进大公司的核心业务,得到大公司支持。

 

Older Entries