转 关于Learning Uliweb的邮件回复--uliweb区别于其它框架的特点

写得很匆忙,也有不少错字,主要是基于我对django和web2py的体验,其它的象tg, pylons实在是没有用过。贴在下面:

-----------------------

> 首先向Limodou表示一下敬意。能够长期从事开源软件开发的爱好者不多,而其中大多数人往往更愿意写code而不太愿意写好文档。Limodou为 Uliweb动手著书,实在是有大气。
>
> 关于Uliweb,想提个问题。我不止一次在Limodou介绍uliweb的片言只字里看到这样的提法:“我用过xx框架,但后来有许多设计上的观点不 被接受,于是我渐渐远离了xx”。那么能否先高屋建瓴地对比一下uliweb与其它框架的不同之处、uliweb的某个特别设计又好在什么地方呢?


在uliweb的文档architecure.rst中我描述了uliweb的整个架构。说简单也简单,就是将app的管理机制尽可能的做到独立。一个 app就是一个开发单位,这种设计并不是uliweb新创造出来的,也是在我学习了django之后学过来的。正象在书中许我地方,我也会强调某个点是从 哪个框架学来的,这是很正常的。除了app的机制外,还把其它框架中我认为好的地方尽可能的集中起来,不能说uliweb就一定比其它的好,只不过从个人 角度来说,我认为是不错的。

1. app管理。 django的app管理正如你下面所写的,我认为不完善。这一点其实在邮件列表中也有多次讨论。当然也并不是大家都赞同,许多人还是认为django的 好。所以,选择一个框架最重要的是先要选择它的思想,思想对路的话,你可能会接受它的缺点,但是思想不对路,你可能只看到缺点。而uliweb也是这样 的,它只是我个人web开发经验(其实我的经验可能不如你们许多人,只不过我希望把我的一些开发经验通过框架形成一种重用的形式,再尽可能让大家利用这种 重用来积累经验。许多框架也都是这样,但是重用与重用是不同的,有些易于重用,有些不易于重用。这就是设计上的区别了)。对于django(0.97版之 后就没有怎么研究了),app只能重用象template, views, urls,而static,配置都没有重用的机制。所以uliweb在这点上做了扩展。主要原因就是一个app是开发单位,而一个功能的实现除了有模 板,view的处理,url的映射,还有象css, image之类的资源文件和配置信息。这些能做到重用,才会使用app的重用更方便。这里与django的比较主要是从哪个更方便来说的。

再说一说与web2py的比较。web2py也有阵子没有关注了,虽然我经常在看。它的app是运行单位,不是功能或开发单位。所以app之间的重用很麻烦,不符合我的要求。这是最主要我离开web2py的原因。

2. views的方便性。这一点是从web2py来的。在web2py中不需要定义request, response等变量,可以直接使用。这就减少了象django中的要定义request参数的麻烦。也许不是一个很重要的变化,但的确可以减少代码。 同时,response也是自动有一个缺省的,这样你可以直接使用,并不需要象django一样,一定要定义一个Response对象。所以这块也有简 单。再有就是模板的自动映射。在web2py和uliweb中,当返回一个dict时,会自动查找一个同名的模板文件,因此非常方便。而django是要 指定的,我认为麻烦一些。同时response.template可以更换模板文件。最差的也可以调用模板函数手动去处理,就和django没什么区别 了。

3. url的映射。我使用的是werkzeug的route模块。它的定义类似于django,但是它基本上不需要写正则表达式,比 如<filename>这就是一个匹配,在django中是要写成正则式的,这一点比较麻烦。同时werkzeug还支持一些参数,如定义 GET,POST等,可以实现REST的方式。还提供了url_for这种机制(这是后来django才有的)。所以从url的定义上,我认为 django的还不够方便,许多route库都不需要定义原始的正则式。这块django做得还不够方便。

再说一说映射。我是定义了一个decorator,可以在views中对view函数进行修饰,也支持自动生成urls.py,在urls.py中集中定 义,因此没有单独的urls.py,也不存在include的功能。因为url的绑定是放在views.py中的,因此当复用app时,并不需要修改集中 的urls.py(一般也没有)。另django则需要修改。

但是web2py的方式我也不喜欢。首先它是controller/action/function的方式,你并不需要绑定url,它是固定格式。但一旦 你想写的话,就是写一个route.py的文件,里面面用正则式来写如何转换。曾经我写过一个使用其它的route的模块来处理url,但是要修改核心, 作者不同意。

4. 模板。这是我在邮件列表中讨论过多次了。django的模板看上去是挺好,但是由于象if, for,基于是不能动态创建变量这种基本功能的缺失,在处理复杂处理时,而这些处理正好是为了显示才做的,非常麻烦,甚至要手写tag。现在django 的tag不可谓不多了,已经是一门独立的语言了,看一看djangosnippets就知道了,有好有坏,django的团队我看是基本上不关注的。我还 曾经想,会不会定期把一些好的tag合到django中去,但是没有见过有这样的行为,也许是我没有看到。为此我还写过一些tag,还有一些外国朋友问把 我的expr之类的tag加入他们的项目需要什么样的license。如果django的模板稍微多一点工作,我写的许多的tag都没有存在的必要。所以 我最终选择了web2py的模板。它支持python代码的嵌入,支持必要的tag,如extend, include等。语法一致,如都是放在{{}}中的。而django是使用{%%}和{{}}来区分。在web2py中都一样。同时使web2py,不 用关心缩近,它会自动处理,但是要在块结束的位置加上pass,这是python的空语句。

但是web2py的模板不支持block,我认为这是django模板中一个非常好的功能,于是我做了扩展,加上这一功能,但是这一功能我在一个 web2py的邮件中作了回复,没有感兴趣。现在我还扩展了支持自定义tag,不过比较简单。因为可以使用python代码这一功能基本上不需要。你也可 以向模析台注入新的方法和函数在模板中直接使用。另外web2py的模板可以编辑成py代码,象mako一样可以存在一个临时目录,不过这也是我扩展的。 现在的uliweb的模板是从web2py模板发展来的,但是做了许多的改进。

5. settings 在django中是使用python源码,很多人都喜欢。我原来也喜欢。但是前面说到了一个原因是每个app没有自已的setting,因此限制了重用的 方便性。同时python源码造成它的形式会非常灵活,而不方便通过程序进行改写,如果你想写一些安装工具时,这种方式非常困难。其实许多的框架都使用 ini形式的配置文件,如tg, pylons。我曾经向django建议,结果得到了很强列的反对。tg有阵子来考虑使用我的dict4ini来处理ini,不过没有使用,后来使用了 ConfigObj,后来就不太清楚了。最早uliweb也是使用py文件,但是后来我还是改成了ini格式,不过可以支持基本的python语法,只不 过不能使用import之类的。所以可以看成是ini与python表达式的结合。而且还支持了#coding=这种编码的定义和_()的国际化处理支持 (当然要与uliweb相结合)。web2py这一点不让我满意,因为它的一个设计思想就是0配置,在我看来,一个灵活的框架与配置本来就不可分,0配置 表示用户很难灵活的架建自已想要的框架,所以这也是我离开web2py的原因。再有就是web2py的作者过于强调语法的向前兼容,在我看来这是很好的, 但不应是一种教条,一旦绝对化,对于以后的优化没有什么好处。

6. ORM其实这倒没什么。web2py和django都是自已的。于是uliweb也搞了一个,基本语法是参考GAE的,许多代码是从GAE学来的,而 GAE又是学Django的。不过我的低层是使用的sqlalchemy。所以语法也基本上是sqlalchemy。目前也支持manytoone, onetoone, manytomany,不过开发时间不长,还没有人使用,所以可能与其它的比不了。功能也不一样完整。不过与django的区别是:在django中,表 级别的操作要通过manager,即Model.objects来操作,而Uliweb的ORM是直接Model.all()之类就可以了。因为它使用了 descriptor来处理,所以可以直接在model类上进行,而django没有使用,所以不得以使用manger的方式,当然这也造成,你可以构造 新的manager。不过在uliweb上想做也是可以的,就是在类上定义一个类方法就好了。web2py原来叫ORM,但是后来是认没有ORM的功能, 所以改为DAL(数据库抽象层)。可比性不高。

7. i18n。都有这功能。uliweb的i18n是自已做的,但对于翻译函数的处理是学django的。不过因为uliweb的模板可以转换为python 代码,所以处理上要比django简单。而web2py的国际化处理并没有使用标准的gettext,是通过定义一个T,然后自动抽取,处理模式不同。 uliweb的i18n处理学习了django的,可以从cookie,
session, 配置中得到语言设置。

8. uliweb有一个form库,是自已写的。可以不用。支持象django一样的定义,校验,validator的使用,比效OO。而web2py则看上去是HTML代码与form处理的一个混合体,不是很OO。

9. 其它uliweb的特点。有一些是别的框架已经有的:

* django风格的middleware
* wsgi middleware的支持,目前测试比较少,现在的staticfiles就是一个middleware
* app之间可以定义依赖,放在config.ini中,这样在导入一个模板时将自动将依赖的app自动添加。而django没有这种机制。这样可以简化对settings.ini的修改。
* 部分地方使用pkg_resource进行处理。django从使用setuptools后来放弃了,改成原来的disutils。

> 就目前我从《Learning Uliweb》中感觉到的,貌似Uliweb的重点在于追求重用,实现这一点的手段就是settings.ini。不知道这个理解是否片面?
>
> 摘录《Learning Uliweb》中的一小段。
> 在前面你看到app可以有自已的settings.ini,可能你会问为什么这样设计?答案是:为了重用。在Django中你做不到,甚至django中 不提供static目录的支持。那么这样的结果是:所有的app的配置信息都放在了settings.py中,所以有app相关的静态文件被放在了一起。 对于单个项目是没有关系,但是一旦你想把其中的某个app拿出来复用就会非常麻烦,你可能很难找到哪些是与这个app相关的。而一个app的功能是
> 多方面的,需要的资源也是多样的,配置信息就是其中一种。因此,这就是Uliweb的设计。


重用在其它的地方,如GUI之类的似乎要容易得多,而web开发要复杂得多,因为一个功能可能涉及到许多的内容,如css, images, template, views, url等等。虽然它们分散存在,但是却是为了完成一个功能。所以这就是uliweb对app的理解。而前面所说的app的依赖的处理也是充分了考虑重用也 设计出来的。为什么软件开发做不到象盖房子那样,一方面创造性,不缺定性造成的,另一方面我认为可能还是重用性设计得不够。

以上只是匆忙想到的,主要是个人主观感受。一个框架必然有它的思想在里面,所以uliweb不会适合每一个人。


update 2009.3.1 又新添加了些回复,主要是针对于web2py的:

> 谢谢Limodou推心置腹的交流。我没有用过Django,近期用得多的是web2py,所以以下对Limodou提到的方面,说说我在使用web2py过程中的理解或者处理手法,请Limodou指点。
>
> 1. 关于app的管理,或者说关于“重用”。不错,和GUI相比,WEB开发之中, 涉及到"css, images, template, views, url等等,虽然它们分散存在,但是却是为了完成一个功能”。而我觉得app就是包含以上各
> 个内容的超集,所以完全可以把完成某种通用功能的一批css,images,template,views等东西组织在一个通用app之中,然后其它的业 务app通过类似webservice的方式来调用通用app中的内容。感觉上这样的效果也许用起来不如uliweb本身内建重用机制那么天然,但最终实 际效果差不多。况且从我的个人体会来看,web开发要用到的个把css或image之类的,不就是几个文件嘛,大不了就手动copy一个副本,这样至少有 一个好处是一个app按自己需求调整个把css,也不会影响到其它的app。追求重用是好,但如果过了头,那么紧耦合的一些缺点也会出现。


重用并不表示不可以调整。就象我前面所写的,重用与重用不同,有些重用简单,有些重用要手工改许多东西。易用性的差别往往就那么一点。这么多的框架,从功 能上讲那个都差不到哪里去,但是为什么有人喜欢这个,有人喜欢那个,可能就是因为这一点点。web2py的service是应用级别的重用,从更高层的划 分它只是一种重用的方式。其实在许多时候我们只想要重用一些静态文件,功能,并不是一个完整的service级别的重用,因此web2py的这种重用对于 这种情况很麻烦。所以效果差不多要看具体的情况,我不认为差不多。至于拷贝文件,正是许多人认为无所谓破坏了易用性。对于已经非熟的人,你怎么做都会认为 无所谓,因为everything in the control,但是对于初学者这之前的差异就很大。甚至到了一些UI的交互设计上,甚至要考虑如何减少一次点击,少一次按键。也许是过头,但是如何表示 这种设计就是过头了呢?何况这种设计,你可以看到,并不是很困难。许多时候,开发者多想一点,多做一点,就会给使用者非常大的方便。让别人方便我不认为是 过头。而紧耦合性的缺点也只是理论上,如果有,自然要想办法去解决了。所以有问题并不可怕,这正好是设计与实用性的一个平衡问题。

>
> 另外,如果Limodou有持续关注web2py的话,可能也已经注意到它先后发展出的T2、T3插件。简单来说就是从“模式”的高度去定义并实现了 WEB开发过程当中的一些常见需求,例如用户认证、极限管理、数据搜索、分页呈现……等等。看来web2py不是不重视重用,但走的是另外一种路子,重用 的是模式。
这些我了解得很少T2我看了一点文档。未来uliweb可能也会向这方向来走。不过我以前在blog也说过,框架应该是分层的,最底层是给平台构建人员使 用的,将用来构建满足自已团队需要的环境。然后是最终用户,他们将在新的平台上进行工作。所以uliweb目前还主要在完成底层的构建,对于平台还在摸索 和积累中。而web2py已经在开始提供我认为的平台层了。这是更高层的复用,这一点我并不否认。只不过要看它是以何种方式来复用,是通过app还是别 的。这一点我的确没有太多了解。因为web2py的app是独立可运行的,从这一点它很难做到细粒度的功能复用。因为它里面的功能并没有分开,所以与我的 要求不满足。

>
>
> 2. uliweb的view方面和web2py的controller看来是差不多,就不说什么了。
>
>
> 3. url映射。django的url映射要用到正则表达式,这是我从一开始就没有选择学习django的最大原因。:) 正则表达式的功能是强大,但学习起来的门槛也较高。君不见咱这python-cn列表,问django里怎么写某个URL或者问怎么写正则的邮件,多了去 了。在合适的场合用正则,事半功倍;在不必要的场合用正则,自讨苦吃。
>
> 扯远了。说回web2py的url映射,固然是固定了只能用/app/controller/function的方式,但实际使用之中也没觉得有什么不方 便呀。无非就是对于那些访问了不存在的路径的请求,无法全部捕获并转到某个通用的错误处理函数罢了。也基本不影响使用,因为正常情况下用户是在我们app 的菜单之中选择操作,不应该需要自己输入某个错误的URL的。在这里我没有领会到要有更灵活的url映射机制的必要性,权当是一种锦上添花的功能吧。


web2py也支持将/app/controller/function映射为其它的url的形式,但是需要定义一个route.py,而且要使用正则 式。uliweb则使用简单的route规则,比正则式要简单,所以我认为是一个比django正则式更好的方案。而且uliweb的expose函数, 有一个特点,比如

@expose
def index()

可以看到,我并没有指定url,但它可以直接映射为/app/views/function,很象web2py。灵活性是功能的要求,而不是个人的要求。 当然也可以看到是我的要求。虽然你不需要,但并不表示我或其它人不需要。在django中专门就url有一个说明,它说好的url是设计出来的,我很赞 同。另外就是uliweb的expose支持一些方法,如是否只匹配GET或POST,可以实现REST的风格。这又可以让一些人高兴。框架虽然不会让每 个人高兴,但是如何可以让更多人高兴,为什么不去做呢?我反正是很少坚持我个人的哲学(当然我也会有),但是如果改动不大,我很乐意考虑加入一个新特性。


>
>
> 4. 模板。web2py的模板倒是有extend和include的指令,本来就是用于扩展缺省layout模板的。和block的效果有点接近吧。
>
> 另外就是可能在MVC(或MTV)分层思路的角度,template里通常不应该存在太复杂的业务逻辑,所以估计不支持block的实际影响也不大。
>


extend和include在django中也有。但它是文件级别的。而block是一个文件中的一部分。在web2py中处理起来很麻烦。因为它只能 定义一个{{include}}。但是一个模板可能有许多地方是可以让用户来替换的,在web2py中就不方便。这并不是什么业务逻辑,这是模板替换的要 求,在实际中有这样的需求。这一点是我认为django不错的。所以我也扩展了一下。对我影响很大。比如我有一个layout模板,上面有一个 {{block title}}untitle{{end}}。这个意思是说我希望title是可以替换的。但是在这个模板中至少还有{{block main}}{{end}}用来输出页面的内容。因此一个页面就有两个内容可能需要替换。那么在web2py中会怎么做?

用函数吗?如果子模板没有定义怎么办?使用block时,如果子模板没有定义相应的block,则可以使用block中原来的内容。所以block一方面是指定了可以替换的内容块,另一方面还起到提供缺省值的作用。

>
> 5. settings。估计你说的setting是指配置文件。虽然web2py没有显式的setting机制,但事实上由于它在每次执行一个app时都会先 导入所有相关的model文件,所以客观上开发者可以定义额外的model文件,在里面定义当前app范围内的配置项,当成配置文件那样使用。
> 这在web2py圈子已经是惯例了,事实上web2py的作者Massimo自己也这么干。:) 所以setting的问题应该是互相等价吧。
你说的model是指什么?是数据库定义的model还是什么?这一功能是与app复用相关的,但是由于web2py不支持细粒度的复用,所以这一功能对 于web2py的意义不大。因为它的一个app就是一个运行单位,而且一个app内部又没有细分,所以不存在我说的情况。

>
> 至于说web2py是否“过于”强调语法的向前兼容,这个见仁见智了。不过要看到,web2py在承诺保证对1.0版的所有语法都永远保持兼容的前提下, 也以极快的速度增加新功能。手法很简单,新的东西以新的API出现,但旧的东西保持不变。我认为这很好地平衡了兼容性和扩展性。
>


这一点我曾经向作者建议过。有时候为了引入新功能,兼容性的破坏是可以接受的。甚至如果用户都说无所谓,作为开发者一定要坚持是否有必要,更何况以前的版 本还有多少个人在用。是否兼容我看是要看以前的版本是否还需要继续支持,不然,没人用的东西我还坚持它作什么?现在的软件更新都很快,大家也喜欢用新的版 本。特别是对于一个新生的框架,用的人没几个,考虑太多反而没有必要。所以坚持不坚持要看实际的情况,不是一成不变的。如果以前的版本仍然有许多人在用, 是可以考虑兼容性的。我并没有说一定不兼容,只不过不希望兼容变成框架发展的一个限制而已。

>
> 其它的好象差别不大,就不多说了。

谢谢交流。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值