Python AOP概览

Lightweight Python AOP
http://www.cs.tut.fi/~ask/aspects/aspects.html
足够简单,因此也很像个玩具或者随意的练习。
喜欢这个方案中把函数作为第一类对象的做法,wrap_around函数会动态complie一段代码来创建新函数来替代原有函数,并在新函数中调用方面(aspect)的代码和原函数。
缺点是当需要多个方面时它采用嵌套的方法来进行织入(weave),也就是说如果想在织入后从织入链中去掉一个方面会非常困难。而且把原函数改名保存的做法虽然直接看起来却不够优雅――如果类中恰好有和修改后的名称同名的函数怎么办?而且把改名后的函数(也包括其他一些需要的属性,比如方面调用时的堆栈)保存在函数所属类中,也就是说虽然在这个方案中把函数作为第一类对象来看待,但并不能把一般函数作为连接点(join point)。而对实例(instance)的织入会影响该类的所有实例。

Pythius.aop
http://cvs.sourceforge.net/viewcvs.py/pythius/pythius/pythius/aop.py?rev=1.36&content-type=text/vnd.viewcvs-markup
用metaclass实现的Aop,如果对应到Java上Aop的实现可以说是非常相似了――或者说很像是实现了Python版的动态代理。pythius.aop.Metaclass(这个名字起的可够糟糕……)作为元类(metaclass)其实例化的类会修改__getattr__、__setattr__的实现在其中拦截全部调用――包括函数、变量等等。它提供的例子是这样的:
>>> class Square:
        __metaclass__ = pythius.aop.Metaclass    # This is constant!

        # This changes!  Note that we are referring to an *instance*
        # of an Aspect, not the Logger class itself.
        _aspect = my_logger
        …
这里织入的声明包含在类声明中,于是类和方面间是有很强的耦合,实际上这是完全没有必要的。完全可以把这个织入的声明抽象出来
>>> SquareWithLogger = pythius.aop.Metaclass(&aposSquareWithLogger&apos, (Square,), {&apos_aspect&apos:my_logger})
这会产生一个很像Decorator的子类,值得注意的是如果用动态代理来实现Aop那么动态代理其实不如叫作动态装饰器。这个实现方法支持方面extend来合并多个方面,不必非要进行嵌套织入,理论上也可以修改织入链――但没有提供对应的方法。
问题在于不支持对一般函数的织入。不支持实例的织入。Metaclass对类的改动太大,有些直觉上是不必要(比如已经通过修改__getattr__实现拦截为何还要从类中删去连接点的声明),可能导致一些依靠反射程序无法正常运行。另外类中具体的函数连接点实际上是被定义在方面中的,这个耦合很糟糕。

Aspects
http://www.logilab.org/projects/aspects/
定义了一个抽象方面AbstractAspect在其中保存原函数和方面――用户可以扩展这个方面,然后定义一个创建函数的函数在被创建的函数中依次调用方面和原函数。这个和Lightweight Python AOP的思路很像,但是因为用抽象方面把信息抽象一致地保存所以就不需要动态compile出新函数――相比之下Lightweight Python AOP通过一个递增的数字拼接处字符串来记录原函数和方面的做法就太过粗糙了。支持实例的织入。而且这个方法的思路本质上是可以支持一般函数的织入的,可惜在构造AbstractAspect时默认传入的参数是成员函数――但是可以很类似实现出支持一般函数的织入的抽象方面和调用函数。
另外,Weaver作为一个Singleton实现其不仅提供织入的功能同时还保存了被织入函数和方面的信息(比如防止一个方面被织入同一函数两次――不过我觉得这个假设毫无道理),这个Weaver很像是个容器。好处是虽然也采用了嵌套织入的方式但根据Weaver中的信息可以实现方面的拆卸――但我认为应该有依赖性更小的方式。
这个方案可以说十分注意不影响连接点,比如新函数替换连接点函数时保持__doc__仍然可用,值得借鉴。

PyContainer
http://pycontainer.sourceforge.net/
实现了Interceptor,还算不上Aop。另外实现的方式很奇特(如果不是奇怪),利用container的优势返回包装过的实例,这个实例重写了__getattr__方法当调用存在拦截器的函数时就会返回这个实例自身……因为这个实例同时实现了__call__方法其中依次调用拦截器和原函数。整个项目还是一个很粗糙的版本而且已经一年多没更新过了。

AOPTutorial–Doing AOP With TransWarp (Under Construction)
http://www.zope.org/Members/pje/Wikis/TransWarp/AOPTutorial
不知道这个该不该算成一个Aop的方案,因为看这篇文档感觉主要是在讲Mix-in。其中的Aspect像一个可以动态添加的基类。有趣的概念是如果Aspect包括一个类体系那么它每次混入的结果都会产生一个新的类体系。具体看文档吧,一两句话说不清楚。另外没看到代码不太清楚是怎么实现的,因为实在懒得下一个Zope了。

理想中的Python AOP
   方面和类不应该存在任何耦合
   支持函数、属性作为连接点
   支持把各种函数都作为连接点,包括function, unbound method,  instancemethod, class method, static method
   支持before, after, around, throw
   织入后除了连接点之外不会对程序的其他部分产生影响,比如dir()、__doc__应该还能正常工作
   支持运行时刻连接点上方面的添加和卸载
   不依赖容器

Asp.net vs JServlepts+

"JServlepts+"是"Jsp + Servlet"的一个拆拼,学习"Tom Marvolo Riddle"=>"Lord of Voldemort",嘻嘻

servlet像个开瓶器,不过切水果极不好用。Sun发现这一点之后就搞了个水果刀jsp专门用来切水果。本以为这样就好了,可惜不久很多人发现水果刀也能凑活用来开汽水瓶,于是他们嫌麻烦就用水果刀开瓶,结果总是弄伤手。

Sun一看这样不行呀就弄出一堆指南“开汽水瓶用开瓶器”、“切水果用水果刀”、“吃饭的时候饮料上来就拿出开瓶器,水果上来就拿出水果刀”,这些写了许多本书(core j2ee pattern,etc)

有些人说这也太麻烦了,就把水果刀、开瓶器组装起来弄成一把“瑞士军刀”(MVC),这样就不会出现手头上没有合适工具的情况,但是这也不能避免误用,而且携带起来也太笨拙了。

M$说你们这也太没有发明创造性了,于是他把开瓶器的两端磨出刃来,说这是个叫WebForm的颠覆性万能工具――其实在M$提出之前很多人都有这个创意了,不过M$从来也没有什么创意,只是在把一个想法实现成一件精美的产品方面,M$无出其右。

好了Asp.net这个东西轻便了很多,而且对于Sun的那一堆指南,asp.net几乎在大多数情况下都能出于本能地对应(事件处理函数对应应用控制器,behind code对应视图助手等等)

虽然个人觉得能在事件处理函数中同时调用Model操作并且控制View控件(只要你愿意那么这些可以以一种OO的方式来进行)绝对是一种进步,但这不能否认asp.net带来的好处使它极为复杂――相对servlet+jsp。比如如果你不搞清楚asp.net的页面生命周期,那么你几乎总会犯错;而对于servlet+jsp来说可能了解http协议的一次响应流程就足够了。所以这可能反而引发更多的误用,特别当M$似乎从不喜欢出一些有条理的指南(相对于一本对知识进行系统描述的书来说MSDN就是一锅粥)或者人们还没总结出有条理指南的时候,这一切尤为明显。

M$,也许你认为身为一个开发人员理应有能力弄清这一切,可反过来说你不是一直在着力让隔离的玛格丽特阿姨来抢大家的饭碗吗?这真是一件奇怪之极的事情。

ADO.NET乱弹

随手写的数据库课作业,可能有错,看看就好

—————————————————————-

ADO.NET是M$最新的数据访问技术。在windows 2000的技术体系中数据访问技术被称为ADO+――类似于COM+、Form+、ASP+,但是2000发布时只携带了COM+的实现。而随着M$的.NET战略,ADO+最终被用基于.NET的语言所实现,表现为.NET Framework中的一组类库,并命名为ADO.NET。
因为M$善于混淆完全不同技术的特长,ADO.NET被命名了一个类似ADO的名字,然而我们注意到实际上ADO.NET与ADO几乎没有任何关系,这是一个不同的新模型。ADO.NET遵循更通用的原则,不那么专门面向数据库。ADO.NET集合了所有允许数据处理的类。这些类表示具有典型数据库功能(如索引、排序和视图)的数据容器对象。从总体设计上来看,ADO.NET不像ADO模型那样以数据库为中心,这是 ADO.NET 的一大特点。
ADO.NET包含两种数据访问方式――在线的以及离线的。在这里是存在争议的,因为有人认为这两种方式是同样重要的。然而个人观点是,在线模型更多的是为实现离线模型而存在的。当然不否认在线模型在访问小量数据以及悲观并发时的作用(另外当ADO开发人员尝试过渡到ADO.NET上时在线模型可以起到让他们误以为两种技术相似的混淆作用),但从.NET的技术体系上讲离线模型才是被推荐的。以下只讨论离线模型。
DataSet是ADO.NET(1.0版本中)离线模型中存储数据的核心类。DataSet的重要之处在于它不仅包含DB中的data,还包含DB的meta-data。DataAdapter连接数据库填充DataSet时,它同时将DB中的结构信息填充入DataSet,这包括列数据的类型、约束等等。这样就等于在内存中建立了一个数据库的副本――当然只包含小量的数据。而操作这个内存副本就像操作数据库一样――比如可以使用Sql来对其进行检索。
另外DataSet的重要特性是它在其中数据发生修改后,它会保存数据为修改时的副本。这样DataSet天生就是乐观并发的。实际上在DataAdapter连接DB更新DataSet中的数据时,它默认使用乐观并发的策略。
除了在运行时刻填充DB的meta-data外,M$提供一种称为强类型数据集的方式来访问。通过VS.NET中提供的一系列Wizard来在静态时创建一个类型安全的数据库结构映像――强类型数据集。这样我们就可以避免了大量诸如:
r[‘count’] =  (int)r[‘count’] ?C 1;
的操作,而以一种直观的方式来使用DataSet(在.Net语言的Property特性的帮助下):
r.Count = r.Count ?C 1;
然而使用向导的一贯问题在这里依然存在。任何对向导生成代码的修改,在每次重新生成后都不复存在。而且这种代码生成方式给程序员带来测试困难以及不可控感一直广遭诟病。当然如果我们考虑到M$的主要精力总是放在降低程序员的门槛以及不断加强所谓的“快速开发”上,那么以上的行为全都不难理解。
从上我们可以看到在一定程度上ADO.NET超出了一般的数据访问技术。DataSet(特别是强类型DataSet)在DataGrid的辅助下就足以构建一个解决方案。但正如Martin Fowler在PEAA中谈到的,人们经常批评M$的解决方案中没有对象。DataSet实际上是一种被Martin Fowler称为表模块(以及表入口)的业务层+数据源模式,然而在OO被广泛证明价值的今天,想用DataSet+DataGrid来完全代替OO+O/RMapping,可以认为是可笑而愚蠢的――当然我们还是要注意M$的精力主要放在“快速开发”上。
值得注意的是一个多月之前,在Channel9上Ander向我们展示了一个被称为DLINQ的疑似O/RMapping方案(在TSS上有争论)。在ObjectSpace失去音信的时候,这也许是值得每一个.NET开发人员期待的。

LINQ,C#想干嘛……

以成为世界上最复杂的语言为己任?呵呵。不过看C#3.0(VB9)还是有点启发。

记得原来说python要加入静态接口的时候,以为在动静融合这条路上动态语言有动态类型可能是要方便一下。不过现在C#3.0要把这些原来CLR不支持的特性在轻度修改CLR的基础上,大部分职责全推给编译器来搞,倒很是让我想起C++静态多态(泛型)的做法来,充分发挥编译器能力这一点上来说,静态语言倒是拥有长足的优势,虽然

var i=new A()

写出这种东西,然后让编译器来推理类型,不如动态类型那么自然,但是效率上的得益在这里又不能忽略了,而获得的能力(匿名类型、匿名方法,还有传说中VB9的动态接口)又足以实现DLINQ这种东西了(虽然不怎么喜欢这个方案)。效率和表现力的比拼,在这方面可能更大程度上要去看硬件的表现了――真的有一天能略掉反射的损失的话,哼哼……

Java的跨平台性

今天突然被问为什么大家推崇Java时经常提到跨平台性,当时没想明白……回来又想了想,大概是这个意思:

Java刚推出时,当时C/S架构仍然是流行的,这个时候Java跨平台的优势是很大的。毕竟如果真能做到“一次编写,到处运行”,那么这是非常诱人的。但是问题在于当时awt、swing在客户端上的拙劣表现,另外就是运行速度的问题(假设如果当时有eclipse或者SWT,而PC的运行速度有现在的高端机的表现,那么估计历史就会改写了),这些使得这个Java编写跨平台Client的想法并没有被广泛执行过,加上C/S架构一些固有问题(比如客户端的部署和升级),终于第二次浪潮(B/S)以不可逆转之势来临了。

也许不能否认Java的跨平台特性为Java积攒了不少人气(事实证明人们对任何有可能或者至少看起来像能抵抗MS的东西从来都保持一种宽容的态度),但而后Java(或者说J2EE)在企业级开发方面占据主导,这些可能更归功于Java语言本身的表现力(一些语言的特性)加上J2EE本身的先进性(当时还没有一个类似的完善的企业级解决方案)以及成功的商业运作。

而现在的J2ee应用虽然没绑到os上却被绑到中间件上了;至于桌面应用有没人用java来做很难说;倒是J2me貌似很是得意于跨平台型,不过我不了解这部分,所以也是妄下断言。不过总体感觉上现在Java的流行和跨平台特性联系是不怎么大的。

Ajax ―― Asynchronous JavaScript and XML- –

最近关注了一下,因为提得比较多。觉得这个东西根本的特征――正如嘟嘟老窝上说的(http://www.duduwolf.com/post/webdev_by_ajax.asp)――在于异步。相比传统web应用,ajax应用一样是无状态、断开式连接(虽然javascript的应用可以在客户端维护一些东西,不过我认为这里所说的“利用客户端的计算能力”根本不是什么值得赞扬的),但XmlHttpRequest允许客户用另一条线程去提交Request,这对用户体验提高的好处是很大的。

考虑一个桌面应用,在执行一个极为费时的操作时,如果程序变成“无响应”状态这是极为令人厌恶的,所以这种情况一般建议用另外一个线程来执行费时操作。然而在web应用中,考虑到信息在网络中的往返,我们可以认为哪怕一个最简单的操作都是极费时的。很长一段时间以来面对这种情况用户只能等待这个往返,这就好比桌面程序的“无响应”。由此我们可以类比出另一线程提交请求的好处。

至于有些人说ajax就是aj,ax不过是赶时髦强加上去,开始我是赞这个观点的(google suggest的返回就只是一个字符串,参考这个链接的返回值http://www.google.com/complete/search?hl=en&js=true&qu=ajax)。然而前几天看《程序员》上有人说ajax体现了一个SOA的思想,发现这个说法也很好玩,如果服务器端只是暴露web services接口,browser变成一个使用services的程序,那还真是优雅得可以。可惜如果客户端仅凭javascript+DOM来类似构建RIA的解决方案,那未免太勉为其难了一点。总之把ajax看成一种过渡技术,关注avalon比较合理一点。

Process Programming

Osterweil说对于Process Software,单单Modelling是不够的,要Coding要精确。

问题在于Process是个高度并发的东西,而像编程语言这种东西确实线性的,并发则是语义外的(其实对于人类的语言也是如此,所以我们总是说“……,同时……”。当然七只桶语言是例外,呵呵)。

所以Osterweil的那个JIL就成了个图形化的语言——如果还算是语言的话。

结论是我们需要一种天生描述并发的语言来描述Process Software,如果没有这种东西就造一个。

Dynamic or Static?

这两天用C#编码,一旦考虑向后兼容性,突感静态类型的不爽。模式上无论如何努力,实际上一旦系统成型就结构上的改变都代价很大(可能我对重构的理解还不好)。

而动态类型缺乏编译时期的类型检查,小系统还可以,3-5人的团队。如果是构件级的开发,无法描述接口的影响将是灾难性的——文档都不知道应该怎么生成。

想来不久前Guido说要在python中引入可选的静态类型检查,当时一片NIMP(Not In My Python)的声音。不过仔细想想很有道理。

当Java、.Net都在虚拟机上引入字节码兼容的动态语言,动态语言爱好者们就往往陶醉在Helj那句“针对动态语言的特点,静态语言能做的反击是非常有限的”。实际上静态语言在努力吸收动态语言的优势。反过来动态语言的动作却很少。如果将来Python真的加入了可选的静态类型检查,可以算是一种尝试。

设想一下,如果将来是模块用静态接口包住,但模块内可以有动态语言的表现力。可爱至极。总之,动静之间就是融合、融合。

ps:感觉没有范型的静态类型太可怕了。Bjarne说把一切都继承自一个统一的object来实现容器是愚蠢的,有点偏激,但也有点道理。到处是向下类型转化,不知道java们这些年是怎么坚持过来的。

我大学以来看过的专业书籍

发现人事情一多不知道该干什么的时候,反而容易干起无聊的事情来……

下午烦得很,结果把上大学以来看过的书总结了一遍。看看还挺有意思的,哪天有空再加上批注

大一第一学期
《C程序设计(第2版)》谭浩强
《C++程序设计教程》钱能 董灵平 张敏霞
《VC++6.0技术内幕(第5版修订版)》David J.Kruglinski,Scot Wingo,George Shepherd

寒假
《深入浅出MFC(第2版)》侯捷

大一第二学期
《Windows 程序设计(第5版)》Charles Petzold
《C++编程思想(第2版) 第1卷:标准C++导引》Bruce Eckel
《C++程序设计语言(特别版)》Bjarne Stroustrup
《Essential C++中文版》Stanley B.lippman
《标准模版库自修教程与参考手册——STL进行C++编程(第2版)》David R.Musser,Gillmer J.Derge,Atul Saini

暑假
《数据结构与算法分析(C++版)第二版》Clifford A. Shaffer

大二第一学期
《Effective C++中文版 2nd Edition》Scott Meyers
《Exceptional C++中文版》Herb Sutter
《.NET大局观》David Chappell

寒假
《Compilers:Principles,Techniques,and Tools》Alfred V.Aho,Ravi Sethi,Jeffrey D.Ullman
《现代操作系统》Andrew S.Tanenbaum

大二第二学期
《数据库系统概念(第3版)》Abraham Silberschatz,Henry E Korth,S.Sudarshan
《Java编程思想(第2版)》Bruce Eckel
《设计模式——可服用面向对象软件基础》Erich Gamma,Richard Helm,Ralph Johnson,John Vlissides
《软件工程——实践者的研究方法(第5版)》Roger S.Pressman
《TCP/IP详解 卷I:协议》W.Richard Stevens
《人月神话(20周年纪念版)》Frederick P. Brooks
《人件(第2版)》Tom DeMarco,Timothy Lister
《Learning Python》Mark Lutz,David Ascher

暑假
《UML用户指南》Grady Booch,James Rumbaugh,Ivar Jacobson
《Python Standard Library》Fredrik Lundh
《Programming Python, 2nd Edition》Mark Lutz
《Thinking in Python——Design Patterns and Problem-Solving Techniques》Bruce Eckel
重读:《设计模式——可服用面向对象软件基础》
重读:《现代操作系统》

大三第一学期
《Rational统一过程——实践者指南》Per Koll,Philippe Kruchten
《敏捷软件开发——原则、模式与实践》Robert C. Martin
《测试驱动开发(中文版)》Kent Beck
《C#技术揭秘》Tom Archer, Andrew Whitechapel
重读:《软件工程——实践者的研究方法》
重读:《人月神话》

寒假
《UML和模式应用(第2版)》Craig Larman

大三第二学期
《重构——改善既有代码设计》Martin Fowler
《JUnit In Action(中文版)》Vincent Massol, Ted Husted
《统一软件开发过程》Ivar Jacobson,Grady Booch,James Rumbaugh
《Spring Reference》Rod Johnson等(太多了)
《Effective Java(中文版)》Joshua Bloch
《软件过程管理》Watts S. Humphrey
重读:《敏捷软件开发——原则、模式与实践》