杂记

Posted by & filed under Life Diary, Programming.

本来要学老王,取名叫乱炖,老王一直执着的用这个词,那我就换一个吧。一个多月没写博客了,前面一段时间是因为实在太忙,后面是懒,疯狂加班之后回家就什么都不想动,过了经过差不多一个多星期的正常人生活,现在终于缓过神来了。这个项目差不多是我加入以来我做过的最大的项目,很累,也很疯狂,项目还在继续,迭代一轮一轮的进行中。留下点笔记,记个印象。 1、项目开始的时候往往思想很宽泛,这个想要,那个想要,每一个功能都是无敌的,每一个功能都是必须的。我一直不赞同一开始就把产品设计的看上去很大很全,主要基于两个理由: 第一,产品一开始设计得大而全,会导致开发周期被拉长,在没有经过市场检验或者最终用户使用的时候,过长的周期会导致开发人员效率降低,没有人愿意做一个看不到前景的产品,没有来自最前线新的需求刺激,没人知道这个东西是不是靠谱的,很长的开发周期还会导致开发人员的疲惫,当然这个可能有些公司不一样,如果人手充足,这个情况或许不那么明显,但据我所知,所有的公司都是缺人的,特别是IT公司,为项目加班是常事,如果这个项目周期再长一点的话,估计就崩溃了。 第二,产品一开始就设计得大而全会导致设计出很多无用的功能,每个人都知道一个产品存在的意义在于其20%的功能,或许有人要反驳,我不预先搞多一点功能,我怎么知道那20%的功能是什么。这个疑问是有道理的,问题就在于,如果我们不能找出最精华的20%功能是什么,那么我们或许可以把圈子放大到30%,40%,甚至更大一点的范围,我们的工期也会缩短很多,避免做无谓的工作。 2、关于开发周期,我觉得最好不要超过一个自然月,一个月20个工作日,除掉UI和页面部分设计,再除去测试和修Bug时间,留给研发的时间大约40%~60%,也就是8~12个工作日,如果只需少量页面方面工作,留个研发的时间会多3~5个工作日。研发工作大约两个星期的,大部分正常上班时间是完不成工作的,不可控的因素有很多,所以这个阶段,可能会加班加点,稍微放松的时刻留在bug修复阶段和后续迭代的UI及页面设计阶段,这个阶段如果稍作控制,可以避免研发人员加班,有至少一个星期的时间让心情得到释放。 3、以上两点基本上接近了敏捷开发的管理流程,敏捷开发在最大限度的保证质量和兼顾项目人员之间的平衡,套用一句话,如果实施了敏捷开发,员工没有离职,那一定是加工资了,如果没有加薪,那一定会离职。需求的不断刺激和短周期的迭代,会导致项目人员情绪的紧张和工作的高压。 4、关于Zend DB,这个玩意的可移植性确实不错,稍作整合,就能嵌入其他框架,但是这玩意最好还是别用在复杂的项目中,而且由于Zend DB本身的设计问题,很多东西你不得不去搞个很变态的方式去解决,比如计算符合条件记录总数。可能由于出于降低耦合度的目的,Zend DB 本身不自动设置缓存,每次需要在action,在新建的每个Model中都要去写和缓存相关的代码,当然解决办法也是有的,就是自己在为Zend DB增加一个组件,将接口和数据库操作给整合进去,然后新建的Model不再继承原先的Zend_Db_Abstract,而是继承你增加的那个组件,从而做到相对优雅的使用缓存。不过我还是推崇,直接写SQL,虽然看起来不那么优雅,但是更容易掌控,对项目日后的调优,非常有益,在复杂逻辑的时候表现优越,如果只是单表操作,ORM依然是不错的选择。至于怎么选择,取决于你的需求,和你项目组人员的整体水平。 5、关于Zend Cache,这个玩意是个好东西,让我们在本地写程序的时候可以方便的使用文件缓存,到服务器上也很方便的改成memcache缓存,少排了好多二氧化碳,Zend组件最优越的地方就是可以轻松的整合,偷懒少写了好多代码,唯一用的不爽的地方是Zend Cache的Tag功能,这个功能本来是个很cool,很有用的功能,但是因为大部分key-value缓存不支持这个玩意,这个东西变成了只有文件缓存时可用,但是在每次save一个缓存的时候,如果需要给这个缓存加个过期时间的话,就得这样写:$cache->save($data, $cache_key, $tag, $expire),因为memcache不支持这个玩意,这时候每次传入的tag就是一个空的数组,我就一直不明白为啥$tag不放到最后一个参数,毕竟所以的缓存类型都支持过期时间,而只有文件缓存才支持Tag 6、关于Tornado(被墙了),我不知道国内用的人多不多,源代码hosting在github上,从邮件列表来看,似乎国内用的人不多,在华莽用户组这样的Python社区里面都几乎没有人提及,这个玩意非阻塞性的Web Server,集成了Web Framework 和 Web Server,我有幸能在我的试验性项目中使用这个东西,提供一组数据,没啥用处,供需要的人参考,单个进程大约能支持1.2K左右的活动链接,当然,要在Linux服务器上,并且支持epoll,多进程可以到2K,占用内存在100M以内,服务器没有任何异常,有进一步挖掘的潜力,我估计能超过3K,当然不建议你这么做,因为Server的后端可能处理不过来了,如果你想动手实现一个Web IM 之类的应用,Tornado是最佳选择之一,另外,如果用来做Web游戏的Server,也是非常合适的,Tornado的Web Framework这一块还很简陋,非高级人员+非Geek人员,不建议用来做产品开发 7、如果你还在寻找一个项目管理工具,我建议你使用Redmine,这玩意能够显著帮助你的团队减少抱怨,减少无效沟通,能够让上下游的同事更自如的安排计划,当然,这一切还需要你做一个布置,平台是死的,需要大家往里面填充属于自己的东西

超级简单Python Socket Server一例

Posted by & filed under Programming.

中午,公司太吵,闲着无聊,用python自己跟自己说话,算是YY吧,hoho server端代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 # -*- coding: utf-8 -*- from socket import * import sys, time, encodings   if __name__ == ‘__main__’: if len(sys.argv) < 2: print u’请输入端口号’ else: sockobj = socket(AF_INET, SOCK_STREAM) sockobj.bind( (”,… Read more »

Windows平台安装Python2.6 和 MySQL-Python

Posted by & filed under Excellence Article, Programming.

Python 版本:2.6 下载地址:http://www.python.org/download/releases/2.6.1/ 下载msi文件并安装 MySQLdb版本: MySQL-python-1.2.2.win32-py2.6.exe 下载地址:http://home.netimperia.com/files/misc/MySQL-python-1.2.2.win32-py2.6.exe 参见:http://sourceforge.net/forum/forum.php?thread_id=2316047&forum_id=70460 常见问题: 1.ImportError: DLL load failed: 找不到指定的模块。 —————————————————————————————————- D:\Program Files\Python2.6>python Python 2.6.1 (r261:67517, Dec  4 2008, 16:51:00) [MSC v.1500 32 bit (Intel)] on win32 Type “help”, “copyright”, “credits” or “license” for more information. >>> import MySQLdb Traceback (most recent call last): File “<stdin>”, line 1, in <module> File… Read more »

类设计

Posted by & filed under Programming.

最近几乎天天加班,周末依然加班,好久没有更新博客了,非常累。不过此累非彼类。 在现有的很多面向过程开发的代码中,对我这个涉世不深的玩家来说,简直就是灾难,或许很多代码连面向过程都算不上,连函数都没有包装。一个函数可能会超过500行代码,语义不名,名称更不名。我曾经试图改造这些代码,并非技术上不可行,而是实现需要太多的时间,一个不可能完成的任务。 让一个缺乏面向对象的团队掌握面向对象很困难的,也许是我智商低,当年我花了两个月才能意会什么是对象,什么是面向对象编程,到现在也不会言传。 如果不能转向到面向对象,那么我们先转成类吧,或许技术上更能解决一点。类的最基本功能就是封装,如果我们撇去面向对象的东西,那么类就是把具有相似性的东西做一个集合,外部在使用这些功能的时候不需要知道具体实现,只要给类中的方法确需要的参数值,如果非要理解成一堆具有相似属性函数的集合,那也是可以的,毕竟这个比一个文件中的几千行代码,连个function都没有的代码好得多。 如果我们想得到更好的类,需要遵循一些基本的原则, 其中之一就是类应该短小,短小并不是说不完整,这和很多人学C的时候,老师告诉我们,函数要尽可能短小一样,到底多短小的类算是合适呢?我觉得根本无法用代码行数来描述,这取决于这个类所完成的功能,比如你要封装一个操作文章的类,那么至少需要,增删改查四个函数,也许还有基于这四个函数的别名和封装,以及必要的公共属性。 第二个重要原则就是单一权责(SRP),这个原则要做到非常 不容易,因为比第一条更难衡量,一般认为,衡量单一权责的标准是:类或者模块应该有且只有一条加以修改的理由。SRP实际上能给出控制类长度的指导方针。简单的理解就是一个类只有一个功能,假如你修改博客标题或者设置的时候,都要改动文章类,显然违背了单一权责的原则。 第三个原则–内聚。类应该只有少量实体变量。类中的每个方法都应该操作一个或者多个这种变量。通常而言,方法操作的变量越多,就越内聚到类上,如果一个类中的米一个变量都被每个方法所使用,则该类具有最大的内聚性。通常,创建一个这样极大化的内聚类是非常不容易的,也是不可取的,因为类的内聚性过高也就意味着类中的方法和变量相互依赖,互相结合成一个逻辑的整体,当修改类中的变量或者方法时,可能影响或者需要修改其他的方法或者属性。一般认为,类的内聚应该保持在较高的位置,但不是最高的位置,这样有利于降低维护成本。 前面提到在我目前的项目中,我碰到很多超过500行代码的函数,假如把数字降低到300,那么符合标准的函数将会增加十倍以上,在一个面向对象的团队中,一个单纯函数或者方法超过100行几乎都是不可接受的,因为这意味着这个函数可能包含过多的权责。其实我们如果真的遵循类的内聚和单一权责的原则,就会导致很多短小的类的产生。 一般程序员在拆解过大的函数的时候实际上就是将原来的代码复制出来,放到新建的函数中去,然后把需要的参数传递过去,实际上导致超大函数的产生的动机常常是因为有很多变量在这个函数的中被使用到,看似这个函数似乎是一个整体,因为拆分会导致新建的函数参数很多。为啥他们不想用一下类呢,假如拆解函数导致需要传递很多的参数,那么这个函数其实就是一个类,需要传递的函数需要提升为实体变量,这样就可以将函数拆成很小的小块,这样看起来似乎丧失了内聚性,因为堆积了越来越多的只为允许少量函数共享而存在的实体变量。如果这些函数想要公司向某些变量,为什么不让它拥有自己的类呢?当类丧失了内聚性,就应该拆了它。所以,将大的函数拆分为小函数,旺旺也是将类拆分为多个小类的时机,程序会更加有组织,更为透明的结构。 实际上很多时候,当你完成所有的功能的时候,产品经理会跑过来跟你说,我们不能把这个功能改成这样,这样用户体验更好,很可能你需要改动很多的代码很逻辑,甚至数据结构,所以如果我们能在设计的类的时候,注意一下可能的需求改动,我们可以借助接口或者抽象类来隔离修改细节对原来代码产生的破坏性更改。

django Settings cannot be imported 错误解决

Posted by & filed under Programming.

在命令行中直接敲入Python命令进入交互模式,然后使用 from django.template import  Template ,Context t  = Template(“Test is {{test}}”) 会导致:ImportError: Settings cannot be imported, because environment variable DJANGO_SETTINGS_MODULE is undefined.原因是django的配置信息没有初始化 有两种解决方法, 一种是切换到你项目或者APP所在的目录使用manage.py shell命令启动交互窗口 还有一种是手动将django的配置初始化: >>> from django.conf import settings >>> settings.configure()

JavaScript完美验证URL正则

Posted by & filed under Programming, Tools.

这个url的正则表达式判断的JavaScript!比较全面的。它验证的情况包括IP,域名(domain),ftp,二级域名,域名中的文件,域名加上端口!用户名等等信息,貌似作者也是在网上找的,我从一个项目代码中扣出来的,是我见过的最强最全面的url验证方式!太猛了,贴在这里与大家共享先,以后不记得的时候来博客上找找,URL的验证实在是很频繁。 function IsURL(str_url){ var strRegex = "^((https|http|ftp|rtsp|mms)?://)" + "?(([0-9a-z_!~*'().&=+$%-]+: )?[0-9a-z_!~*'().&=+$%-]+@)?" //ftp的user@ + "(([0-9]{1,3}\.){3}[0-9]{1,3}" // IP形式的URL- 199.194.52.184 + "|" // 允许IP和DOMAIN(域名) + "([0-9a-z_!~*'()-]+\.)*" // 域名- www. + "([0-9a-z][0-9a-z-]{0,61})?[0-9a-z]\." // 二级域名 + "[a-z]{2,6})" // first level domain- .com or .museum + "(:[0-9]{1,4})?" // 端口- :80 + "((/?)|" // a slash isn’t required if there is no file… Read more »

记忆(memoization)在JavaScript中的应用

Posted by & filed under Programming.

函数可以用对象去记住先前操作的结果,从而能避免无谓的运算。这种优化被称之为记忆,英文叫做memoization。关于memoization可以参见维基百科的解释。JavaScript的对象和数组要实现这样的优化是非常方便的,比如说,我们要递归计算著名的fibonacci数列,一个fibonacci数字是之前两个fibonacci数字之和,最前面两个数字是0和1. var fibonacci = function (n) { return n <2 ? :fibonacci(n-1) + fibonacci(n – 2); }; for(var i = 0; i <= 10; i++) { document.writeln(’//’ + i + ":" + fibonacci(i)); } 这样的算法是可以工作的,但本身做了很多无谓的运算。fibonacci函数被调用了453次。我们调用了11次,而自身调用了442次去计算可能已经计算过的值。如果我们让该函数具备记忆功能就可以显著减少运算量。 我们在一个名为memo的数组中保存我们的存储结果,存储结果可以隐藏在闭包中。当我们的函数被调用时,这个函数首先看是否已经知道存储结果,如果已经知道,就立即返回这个存储结果。 var fibonacci = function () { var memo = [0,1]; var fib = function (n) { var result =… Read more »

解决file_get_contents的超时问题

Posted by & filed under Programming.

file_get_contents一步就做完了打开,读取,关闭的三个动作,过程相当自动化,并且可以读取远程内容,非常方便,在网络状况差的情况下,可能会导致程序执行陷入停滞或者过慢,因为不停的重试和等待PHP进程本身的超时才会退出。晚上再次阅读了PHP手册,发现可以用一个比较变态的东西来解决,就是创建一个可以控制的资源句柄,通过控制资源句柄超时来控制file_get_contents这个方法的超时时间,使用起来很方便,也很简单。 $opts = array( ‘http’=array( ‘method’="GET", ‘timeout’=1, //设置超时,单位是秒,可以试0.1之类的float类型数字 ) ); $context = stream_context_create($opts); $contents = file_get_contents($url,false,$context); 得到内容之后该怎么处理就怎么处理了,关于tream_context_create这个方法的更多HTTP协议参数,请参见:HTTP context options,其他协议,请参见Context options and parameters Update 09-09-17: 我测试的时候使用的g.cn的首页,非常快,把timeout设置为1,没有超时的感觉,我以为是分钟为单位,感谢的Lightning$指正,单位是秒。

正则表达式匹配中文符号(GBK编码)

Posted by & filed under Programming.

事实证明,网上的很多东西都是扯淡,不过原理还是有的,我碰到一个需求,给定一段文字中(GBK编码),去除所有符号,不相干符号,包括标点,日文片假名之类的,于是我在网上搜啊,搜啊,得到的结果要么就是错的,要么就根本好不相干,被抄袭得最厉害的是http://community.mybbchina.net/thread-212-post-507.html,可怜的作者,我也不知道这些人为什么抄这个,我就没测试成功过,连GBK的字符集区间都没弄清楚。 其实指定字符编码匹配中文很简单,GBK编码表中很明确的规定了所有的符号位置,而且刚好是一个区间,在维基百科上有详细的介绍,比如我要把类似 addd中华ds,#¥%…&((212))}}A■g民国ds中-啊国fjsd,【】啊Y 这样的字符串中所有非中文、英文、数字字符全部去除掉,姑且叫去除的字符为火星文,去除火星文的PHP写法为: preg_replace("/([\xA1-\xA9].{1}?)*?/", "", $str); 这样所有在全角状态下输入的非中文,英文和数字将被替换掉,如果还需要进一步处理英文状态下的,那就判断一下ASCII码值吧,或者你怕麻烦也可以把所有的都列出来,然后替换,可以参考下面,在网上找来的,非我写的,忘了出处了 /** * 清除所有常见标点符号 * @param $pointer * @return unknown_type */ function clear_point($pointer) { return str_replace ( array(’ ‘,"~","!","@","#","$","%","^","&","*",",",".","?",";",":","’",’"’," [", "]","{","}","!"," ¥","……","…","、",",","。","?",";",":","‘","“","”", "’"," 【","】","~","!","@","#","$","%","^","&","*",",","."," <", ">",";",":","'",""","[","]","{","}","/","\","《","》","-","_"),   array(”,”,”,”,”,”,”,”,”,”,”,”,”,”,”,”,”,”,”,”,”,”,”,”, ”,”,”,”,”,”,”,”,”,”,”,”,”,”,”,”,”,”,”,”,”,”,”,”,”,”, ”,”,”,”,”,”,”,”,”,”,”,”,”,”), $pointer ); } 这个东西有更好的写法,而且全角状态的符号在之前已经过滤了,在此可删除,我懒,抛砖引玉吧