Archives

  • 初涉敏捷编程

    我们都知道一个设计良好的程序是优雅的,我们也知道单元测试是很重要的,有充足的单元测试就可以尽可能的保证一个程序模块的正确性。这两部分是一直困扰我的部分,如何保证一个设计是尽可能的优雅的,还有就是让单元测试测试到尽可能多的测试点。以前的做法都是提前对程序进行设计,然后进行编码,然后编写单元测试代码,再根据觉得哪里不妥修改代码,修改测试用例。 这里我遇到的问题是 设计阶段不能设计的足够精细这一点非常令我恼火,有的想要给别人看的代码,比如开源,要求你的API设计来不得半点马虎,要设计的很合理。前期的脑纸笔的设计方式,会让细节偏差很大。而合理的API基本上都是通过不断的编码得到的。 单元测试用例并不能覆盖几乎100%的代码当你写好了代码之后,你就懒得写测试用例了,尤其是针对一些不总用到的功能。而写出的用例大多都是一个非常完整的场景,而不是针对某一个小模块的测试。针对性不强。 针对这两个让我极其愤恨的问题,我决定使用敏捷编程,测试先行。 我对测试的看法一直是测试(我承认这是一句废话),我以前都是写了代码(也就过了设计阶段)再写用例,这样程序的API设计大都是凭借对代码的理解捏造出来的,理解的深,功力深,API设计的就相对好一些,理解的不够深,捏造的成分就大,后期自己看着都恶心。但是Kent Beck和Uncle Bob告诉我们测试用例就是在进行程序的设计。其实,一个好用的API,都是经过实践检验的,这样自然要不断的编写和修改代码,而我们把这个过程提前,放在最初要设计的测试用例里面。一个测试用例,就是对一组API的调用的描述,也就是场景重现,这阶段已经就是在使用自己的API,也就是检验自己的API。当然,最初的这部分编码连编译都无法通过,因为你要求的所有东西都没有,但也正因为如此,你才能按照你最舒服的调用方式调用API,而不是受到什么限制。 例如 Query query = xxDAO.createQuery(“Target”); query.addExpression(Expression.eq(“name”, “Testing”); List l = xxDAO.doQuery(query) 这时候,我们没有Query,没有addExpression,没有Expression,什么都没有,但是这代码看着很自然。这就说明如果我们这样设计API就还算不差。下一步很自然的,我们要让这部分代码编译通过,增加Query这个interface[1],然后完成编译。 我认为,到了这个阶段,程序的设计已经完成了80%了,剩下的就是看哪里能够变得更加合理,让臭味更小了。至于所有的实现类的编码,我觉得就是体力劳动了,虽然体力劳动也很累很耗时,但毕竟能够找到解决方法。这时候剩下的事情就简单多了,编写真正的实现类代码,让单元测试通过。 我们应该在编写真正的代码的时候,都是针对测试用例里面使用的API进行编码。这句话的意思就是,我们编写出的方法,应该是测试用例用到的,而不是额外的编写一些暂时没有用到的代码。如果这些将要编写的类/方法没有被测试用例覆盖到,那么要么是这些类/方法暂时没有需求,要么就是测试用例覆盖度不够。哪怕是一个简单的setter/getter,也要有测试用例直接或者间接覆盖到。之所以这样,只是为了避免破窗原理,一个没写,就会有第二个,就会有第n个。 [1]:之所以增加的是interface,就是因为增加的interface更加抽象,行为更加的单纯,并且在测试的时候,可以充分的使用Mock。但是这不是绝对的,在一些纯粹的逻辑的东西,就完全是一个class就能代替的,而无需interface,比如例子中的Expression,用class就比interface好很多

    Apr 30th, 2008 | Filed under 程序设计
  • 如何使用svn进行merge

    svn 的 merge其实很好用,当然前提是你明白了svn merge这个命令,还好,我用了大约一年明白了这个命令 -___-!! 跟大家说一下用法,比如我们要把分支merge到主干上 # svn merge –help merge: Apply the differences between two sources to a working copy path. usage: 1. merge sourceURL1[@N] sourceURL2[@M] [WCPATH]        2. merge sourceWCPATH1@N sourceWCPATH2@M [WCPATH]        3. merge [-c M | -r N:M] SOURCE[@REV] [WCPATH] 我们以第一个为例 merge sourceURL1[@N] sourceURL2[@M] [WCPATH] 这个help里面提示,merge需要三个参数 sourceURL1,sourceURL2的含义并不是两个分支,或者一个分支一个主干,而是同一个分支的两个状态,或者说是两个版本。对这两个版本做一个diff,然后把diff的结果,应用到最后的参数WCPATH上,WCPATH代表是一个本地已经checkout的工作区 svn merge的思想是diff and apply [...]

    Apr 9th, 2008 | Filed under subversion
    Tags:
  • 网络安全通讯(5)—-支持客户端验证的python web server

    前面我们说道很多的场景是需要客户端验证(Client Certificate)的,而python的web server如何支持呢?大多数的python web server都是符合WSGI标准的,也就是他们提供WSGI标准支持的功能,也就是他们几乎都不支持WSGI不支持的功能。很遗憾,客户端验证不在此列。换句话说,Cherrypy,webpy等常用的python web server都无法支持客户端验证。 我终于找到了Twisted(他怎么一下从2.5就蹦到了8.0.1)的web模块可以作为一个单独的web server。而这个web模块是包装的很底层的,使用pyopenssl,并且不是WSGI的一个实现。也就是说,他很可能是支持客户端验证的。经过一番google,发现了支持的办法。如下:首先我们看一下如何让Twisted支持HTTPS,他需要执行reactor.listenSSL方法, class Hello(Resource) :    isLeaf = True    def render(self, request) :        return ‘Hello, SSL’root = server.Site(Hello())ctxFactory = ssl.DefaultOpenSSLContextFactory(    ‘/path/to/server.key’,    ‘/path/to/server.crt’    )reactor.listenSSL(443, root, contextFactory = ctxFactory)reactor.run() 这是最基本的支持HTTPS的方法,我们看,他需要一个contextFactory,深入到Twisted里面发现这个contextFactory是SSL进行设置。我们想要他支持客户端验证,就要从这里下手了。DefaultOpenSSLContextFactory的cacheContext方法是对context进行的操作。我们重写这个方法。 class SSLClientCertificateFactory(ssl.DefaultOpenSSLContextFactory) :     def __init__(self, privateKeyFileName, certificateFileName, sslmethod=SSL.SSLv23_METHOD) :        ssl.DefaultOpenSSLContextFactory.__init__(self, privateKeyFileName, certificateFileName, sslmethod)     def _verify(self, connection, x509, errnum, errdepth, [...]

    Apr 2nd, 2008 | Filed under python, 安全
Archive for April, 2008