分类目录归档:编程

用程序生成word文档(DOC)

很多程序都支持导出PDF文档,不过如果需要对导出文档进行编辑PDF就显得不那么方便了。就国内环境而言,导出word文档对有编辑需求的文档而言更为合适。
由于我使用python,因此这里只讨论python下可用的方案。目前找到的解决方案主要有下面几种

  • python-docx
    目前能找到支持word格式的库非常的少,就python而言只找到 python-docx 算是相对可用的解决方案。python-docx 的功能非常的弱,有很多的限制,比如不支持模板等。如果想生成复杂文档那就无能为力了。
  • POD
    POD是Appy框架的一部分,可使用ODF (Open Document Format)文件做为模板,并输出ODF格式的文件,并可调用LibreOffice将生成的文件转换成DOC等格式。相比python-docx,POD用于生成更为复杂的文档。但如果你需要动态生成一些复杂表格,POD可能会有些问题。
  • unoconv
    unoconv是个文档转换工具,可调用LibreOffice对文档格式进行转换。unoconv可将HTML转换为DOC格式。因此可先生成HTML,然后再将HTML转换为DOC。生成HTML对广大的WEB开发者而言无疑是轻而易举的,这也是我最终选择的方案。不过要注意的是用unoconv将HTML转换成DOC,遍地是坑-_-!。

    • 只支持有限的HTML语法。很多CSS语法根本就不支持,看到的和转换出来的效果完全不一样。解决办法:在LibreOffice中编辑文档,然后保存成HTML,然后对保存的HTML进行编辑。
    • unoconv的-t参数可传入.ott格式的文档模板。默认情况下LibreOffice转换出的表格的行高远大于文字的高度,更糟糕的是文字还是顶对齐,非常不美观。编辑个空文档,然后保存为.ott,转换的时候指定模板文件可解决该问题。
    • 生成的文档的左右边距不一致。恩…,这个我还没有找到解决办法。

单元测试的一些体会

以前发布开源项目时被国外的网友一阵鄙视,之后在自己的一些小项目中陆陆续续的有写一些单元测试。你一旦真正接受单元测试,并实行起来还是很容易体会到单元测试的优点的。只是尽管单元测试有很多优点,在国内的环境下写单元测试的公司依旧不多。
单元测试的好不是立竿见影,需要时间的累计。在最求“速成”的环境下,单元测试没法推行也是显而易见的。
单元测试的问题

  • 单元测试并是立即见效的
    单元测试代码的书写也需要花费一定的时间,有时还需要不少时间。如只是从一次测试的效果来看单元测试多半是不划算的。单元测试解决的是之后代码改动之后再测试的时间。如果时间进度紧张,即使知道单元测试的好处也难有心去写。毕竟要先解决燃眉之急,更何况某些代码的生命周期很短,还不足以让单元测试发挥价值。
  • 单元测试的基础测试数据需要积累
    一些复杂的业务系统业务数据之间的逻辑关系会比较复杂。比如你需要有基础的客户数据、员工数据后才可进行合同创建等功能的测试。如果没有前期测试数据的积累,你要直接给合同模块写单元测试。想到要将员工、客户等数据补上,立马就退缩了。(注:其实手动测试也要将员工、客户先创建好,只是因为之前手动测试时相关数据已创建好)

如何开始

  • 在一些小项目中先用,真正体会一下单元测试的优点。
  • 从项目的一开始就使用单元测试。单元测试的书写和项目的书写一样,都是一个循序渐进的过程。
  • 只写一些必要的单元测试,不要最求大而全。即使手动测试你也不可能测试到所有小概率情况,所以可以只写一些最必要的单元测试,让单元测试代码发挥最大价值。

douban的Android客户端

最近想给Android开发一个小应用,找了一些Android应用来做参考。感觉豆瓣客户端挺有意思。

豆瓣为小组、活动等功能开发了独立的客户端。在使用的时候有时候会在APP里直接调用douban的WEB站点或是WAP站点。Facebook放弃HTML5被看成是原生APP的一次巨大胜利。但是WEB APP在跨平台以及开发的便捷性方面都有着一定的优势。在人力资源不是太过充足的情况下采用原生+WEB的开发模式可能是个不错的选择。

在用户使用频繁对用户体验要求高,性能敏感的地方使用原生开发。一些相对简单的页面直接使用WebView即可达到原生应用同样的体验,对这些页面直接使用HTML开发。还有些用户不太常用的功能在前期可以先调用WEB版的原始页面。

PS:

  • 就目前而言用HTML5开发移动应用很难提供很好的用户体验。但我相信技术在发展,HTML5还将是趋势,主要问题还是时间,2年?
  • Android手机上Metro风格的应用越来越多了。苹果将模物化设计做到了极致,接下来是Metro设计极简的逆袭?

随机迷宫生成算法

在线迷宫游戏地址: lbmaze@sae
项目地址: lbmaze@github
最近研究了下迷宫的生成算法,然后做了个简单的在线迷宫游戏。游戏地址和对应的开源项目地址可以通过上面的链接找到。开源项目中没有包含服务端的代码,因为服务端的代码实在太简单了。下面将简单的介绍下随机迷宫的生成算法。一旦理解后你会发现这个算法到底有多简单。

  • 将迷宫地图分成多个房间,每个房间都有四面墙。
  • 让“人”从地图任意一点A出发,开始在迷宫里游荡。从A房间的1/2/3/4个方向中的任选一个方向前进。在从A房间走到B房间的过程中,推倒A/B房间之间的墙。
  • 如果方向x对面的房间已经走过,则选择其他方向。如果所有方向的房间都已经走过,则退回上一个房间看是否还有可选道路。
  • 走到真正无路可走时,说明已经走过了所有房间,迷宫也生成好了。

下面是该算法的python实现(核心部分)

def gen_map(self, max_x=10, max_y=10):
    """ 生成迷宫 """
    self.max_x, self.max_y = max_x, max_y  # 设置地图大小
    self.mmap = [[None for j in range(self.max_y)] for i in range(self.max_x)]  # 生成原始地图
    self.solution = []  # 迷宫解法
    block_stack = [Block(self, 0, 0)]  # 从0,0开始生成迷宫(同时将这点作为起点),将起点放到栈里
    while block_stack:
        block = block_stack.pop()  #取出当前所在的房间
        next_block = block.get_next_block()  # 获取下一个要去的房间
        if next_block:  # 如果成功获取下一走发,将走过的房间放回到栈里
            block_stack.append(block)
            block_stack.append(next_block)
            if next_block.x == self.max_x - 1 and next_block.y == self.max_y - 1:  # 走到终点了,栈里的路径就是解法
                for o in block_stack:
                    self.solution.append((o.x, o.y))
def get_next_block_pos(self, direction):
   """ 获取指定方向的房间号 """
    x = self.x
    y = self.y
    if direction == 0:  # Top
        y -= 1
    elif direction == 1:  # Right
        x += 1
    if direction == 2:  # Bottom
        y += 1
    if direction == 3:  # Left
        x -= 1
    return x, y
def get_next_block(self):
    """ 获取下一要去的房间 """
    directions = list(range(4))
    random.shuffle(directions)  # 随机获取一个要去的方向
    for direction in directions:
        x, y = self.get_next_block_pos(direction)
        if x >= self.mmap.max_x or x < 0 or y >= self.mmap.max_y or y < 0:  # 房间号在许可范围内
            continue
        if self.mmap.mmap[x][y]:  # 如果已经走过
            continue
        self.walls[direction] = False
        return Block(self.mmap, x, y, direction)
    return None  # 没找到有可用的房间

注: 由于采用该方法生成的迷宫道路的分支数量并不是太多,coffeescript版在生成迷宫的过程中增加了随机处理,对应算法也稍微复杂一点点。

让你的python程序同时兼容python2和python3

python邮件列表里有人发表言论说“python3在10内都无法普及”。在我看来这样的观点有些过于悲观,python3和python2虽然不兼容,但他们之间差别并没很多人想像的那么大。你只需要对自己的代码稍微做些修改就可以很好的同时支持python2和python3的。下面我将简要的介绍一下如何让自己的python代码如何同时支持python2和python3。

  • 放弃python 2.6之前的python版本
    python 2.6之前的python版本缺少一些新特性,会给你的迁移工作带来不少麻烦。如果不是迫不得已还是放弃对之前版本的支持吧。
  • 使用 2to3 工具对代码检查
    2to3是python自带的一个代码转换工具,可以将python2的代码自动转换为python3的代码。当然,不幸的是转换出的代码并没有对python2的兼容做任何的处理。所以我们并不真正使用2to3转换出的代码。执行 2to3 t.py 查看输出信息,并修正相关问题。
  • 使用python -3执行python程序
    2to3 可以检查出很多python2&3的兼容性问题,但也有很多问题是2to3发现不了的。在加上 -3 参数后,程序在运行时会在控制台上将python2和python3不一致,同时2to3无法处理的问题提示出来。比如python3和python2中对除法的处理规则做过改变。使用-3参数执行4/2将提示 DeprecationWarning: classic int division 。
  • from __future__ import
    from __future__ import”后即可使使用python的未来特性了。python的完整future特性可见 __future__ 。python3中所有字符都变成了unicode。在python2中unicode字符在定义时需要在字符前面加 u,但在3中则不需要家u,而且在加u后程序会无法编译通过。为了解决该问题可以 “from future import unicode_literals” ,这样python2中字符的行为将和python3中保持一致,python2中定义普通字符将自动识别为unicode。
  • import问题
    python3中“少”了很多python2的包,在大多情况下这些包之是改了个名字而已。我们可以在import的时候对这些问题进行处理。
try:#python2
    from UserDict import UserDict
    #建议按照python3的名字进行import
    from UserDict import DictMixin as MutableMapping
except ImportError:#python3
    from collections import UserDict
    from collections import MutableMapping
  • 使用python3的方式写程序
    python2中print是关键字,到了python3中print变成了函数。事实上在python2.6中已经带了print函数,所以对print你直接按照2to3中给出的提示改为新写法即可。在python3中对异常的处理做了些变化,这个和print类似,直接按照2to3中的提示修改即可。
  • 检查当前运行的python版本
    有时候你或许必须为python2和python3写不同的代码,你可以用下面的代码检查当前系统的python版本。
import sys
if sys.version > '3':
    PY3 = True
else:
    PY3 = False
  • six
    six 提供了一些简单的工具用来封装 Python 2 和 Python 3 之间的差异性。我并不太推荐使用six。如果不需要支持python2.6之前的python版本,即使不用six也是比较容易处理兼容性问题的。使用six会让你的代码更像python2而不是python3。

python3的普及需要每位pythoner的推动,或许你还无法立即升级到python3,但请现在就开始写兼容python3的代码,并在条件成熟时升级到python3。
注:

将VIM的配置文件切换到janus

janus是一个非常流行的VIM配置脚本,其中集合了很多优秀的VIM插件。
此前我一直都是用自己收集的VIM配置以及插件,到现在之前的某些插件已经出现了更优秀的替代品。索性将janus fork了一份(vicalloy’s janus),针对自己的使用习惯做了少许的定制。
janus具体加载了哪些插件,做了哪些默认配置,大家还是直接去看官方的README吧。
我主要做了下面一些改动:

  • 取消了Tab、空格等不可见字符的提示功能。
  • 取消行号显示。在vim中直接 :num 即可跳转到对应的行,所以我一直感觉行号显示并不是太有用。
  • 关闭supertab插件。这个插件似乎和某些插件有冲突。
  • 增加部分插件
    • FencView 国人写的自动识别文件编码的插件。
    • ZenCoding Zen Coding简单的说就是用css来写html,至于具体怎么用还是去找些Zen Coding的文章来看吧。
    • eclim 将Eclipse的功能集成到vim的插件。其中有很多很好用的vim scripts,比如htmldjango的语法高亮以及缩进处理等。将其中的部分脚本打包到了我的vim配置中。
    • jedi vim的代码补全能力非常的弱。jedi相比来说要强大很多,不过对动态语言来说补全想做到非常智能并不容易。
    • vim-powerline 状态栏定制插件

注:

  • janus并不支持windows系统,如果你需要在windows下使用janus需要自己做些小改动。
  • 加了一堆的插件后VIM的启动速度明显变慢,此前都是秒开,现在要个2~3秒的启动时间。

编程语言们各自的哲学

曾有同事打算将ZOPE和PLONE啃下,我是不建议的。同事说我不够开放,对自己不喜欢的技术都很排斥。我承认,每个人都会有自己的偏好。但我不赞成使用ZOPE恰恰不是因为偏好问题,我也不会因个人偏好而建议采用或不采用某项技术。
在我看来ZOPE是一个很变扭的技术。ZOPE引入了接口/容器等概念,给人感觉ZOPE在很多方面都在有意的模仿JAVA。Python和JAVA在语言哲学方面有着比较大的差异,试图以Java的方式来做一个Python的WEB开发框架无疑是有些别扭的。如果ZOPE真的学的特别象,那我为什么不干脆直接使用Java?
这世界上存在各种编程语言,每种编程语言都有着自己的特点,正是这些差异满足了各类人的不同需求。这些编程语言都有着自己最核心的思想,这个核心思想就是所谓的“哲学”。没有自己“哲学”的编程语言是无法在这个世界上存活的。有些编程语言看上去问题很多,却很流行。或许它的那些问题也正是它流行的原因。

PHP

PHP的使用门槛非常的低,而且通常用PHP写出来的东西代码都不是那么的“漂亮”。于是有些人将PHP看成是业余程序员用的东西。然而就是这么一个看似不怎么专业的东西统治了大半个互联网。PHP的“哲学”是“quick and dirty”。在一定程度上beauty和quick并不容易并存。PHP将quick和简单作为第一要求,代码的漂亮退居第二。dirty的代码并不容易维护,所以通常在系统在复杂后,复杂业务逻辑功能将交由其他技术实现。PHP则安心做着自己表现层的事。

Java

有人说Java是给笨人用的语言。这话虽然很难听,不过在一定程度上这还真就是Java的哲学。Java充分利用语言特性和IDE等自动化工具来避免程序员犯错,让人海战术成为可能。对于大多Java项目只需要少数的牛人来设计系统构架和主要接口,下面的具体实现用“笨人”来做就可以了。

Python

python的哲学是“quick and clean”。在一定程度上说python确实非常clean也很quick。不过python的clean可让也让python变的有些平庸。python号称什么都能做,却又没在哪个领域特别突出。

Ruby

Ruby强调人文关怀,编程是一件有乐趣的事,你可以按照自己喜欢的方式去使用ruby。相对而言ruby可能更容易发挥个人的创造性,但在团队协作时则容易遇到麻烦。

国内代码托管网站不完全列表

可以说GitHub的出现完全颠覆了以往大家对代码托管网站的认识。GitHub不但是一个代码托管网站,更是一个程序员的SNS社区。在GitHub出现后,国内外有的代码托管网站也都开始引入GitHub的某些元素。
GitHub真正迷人的是它的创新能力与Geek精神,这些都是无法模仿的。
有朋友想做基于HG的代码托管网站,所以对国内的代码托管网站有过一些关注。下面是我知道的国内类Github的代码托管网站。

要想在国内做一个成功的代码托管网站并不容易。如果你是一个小团队,且缺乏足够的魄力和觉悟,我是不建议去折腾这个的。

  • 对开发者而言GitHub已是一种流行文化,如果你的特色不够显著很难说动人来。
  • 小团队关门的事情经常发生,如何让人相信你的服务是长久可信赖的是一个挑战。
  • Github没有被墙,或者说不能访问的概率还是太低。如果之是速度快一点点,不足以做为卖点。而且对git而言,需要真正和服务器同步的时间很少。

MongoDB介绍以及Python的相关库

MongoDB是一个高性能,开源,无模式的文档型数据库,是当前NoSql数据库中比较热门的一种。MongoDB提供了比较丰富的数据库查询接口,是目前最接近关系数据库的NoSql数据库。
近两年MongoDB的发展速度非常的快,不少公司已经将MongoDB应用到实际产品中。在这些公司中最著名的应当是foursquare,国内的淘宝等公司也部分使用了MongoDB。MongoDB更完整的应用列表可以在MongoDB的Production Deployments找到。
技术人员普遍有追新的爱好,看到一个不错的东西就想在自己的项目中用少。在对MongoDB做了些了解后,感觉使用MongoDB作为普通web应用的主数据库或许并不是一个很好的主意。

  • MongoDB的优势是速度以及海量数据的支持,另外一个有点就是schemeless。真正需要用到schemeless的地方似乎并不是太多。目前很多 MongoDB 封装,也都增加了scheme的定义功能,基本上放弃了schemeless特性。另外如果过度的schemeless,日子久了后可能自己都搞不清楚自己到底在数据库里放了什么东西。
  • MongoDB的特性决定了某些关系数据库很容易做的操作在MongoDB中会很不容易实现(比如多表关联查询等,而且据说分页性能也不怎么样?)。为配合MongoDB,在构架设计乃至产品功能需求方面都需要做些调整。
  • MongoDB的另外一个问题是太费内存,在内存不够大的时候性能很可能还不如mysql。所以有人称MongoDB是有钱人用的东西。
  • 可能大多人都不太会有机会遇到真正需要MongoDB的海量数据。

在V2EX上发了一个关于MongoDB的帖子(有谁在用 MongoDB 体验怎么样),引来不少关于MongoDB的吐槽。不是说MongoDB不够优秀。MongoDB有着自己特定的应用场景,如果只是为了尝鲜而贸然使用,可能并不会得到预想的效果。
下面简单的介绍一下MongoDB相关的一些Python库:

  • PyMongo MongoDB的Python接口开发包。PyMongo提供了最原始的MongoDB访问接口,其他的Python MongoDB库基本上都是基于该库进行开发的。
  • MongoEngine 为MongoDB提供了类似Django ORM的API。支持定义Scheme定义,同时提供DynamicDocument类用于支持schemeless。MongoEngine内置了Django提供支持。如果你之前使用过Django,MongoEngine会让你觉得非常舒服。
  • MongoKit 和MongoEngine类似的一个库。个人更倾向于MongoEngine所以对MongoKit没有太多了解。

[django-ajax-validation]Django表单AJAX校验及提交的APP

项目地址https://github.com/vicalloy/django-ajax-validation
django-ajax-validation是一个使Django支持表单AJAX校验的第三方APP。我做了一些修改,增加了表单的AJAX提交以及twitter-bootstrap的支持。

安装

  • pip install git+git://github.com/vicalloy/django-ajax-validation.git
  • 在Django settings的INSTALLED_APPS中加上”ajax_validation”。

一个简单的使用范例

views.py

from ajax_validation.views import validate_form
from ajax_validation.utils import render_json_response
...
class TimelineForm(forms.ModelForm):
    class Meta:
        model = Book
def add_book(request):
    #创建表单并进行校验。返回表单以及校验结果。
    form, validate = validate_form(request, form_class=BookForm)
    if validate['valid']:#如果校验成功,执行保持操作
        book = form.save()
    return render_json_response(validate)//返回JSON

模板

进阶

django-ajax-validation的原始文档就写的非常糟糕,我也偷懒,所以想了解更多还是直接看代码吧。