作者归档:vicalloy

单元测试的一些体会

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

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

如何开始

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

Resolution 2014

已经有挺长时间没有更新blog了,上一篇还是2013年初。有时候想,写blog或许是一种状态,或许某天我的博客也会和互联网上的许多blog一样不再更新。这次这样长时间没有更新blog可能也是生活状态和之前有所不同,只是并不是我所期望的状态。
毫无悬念,2013依旧留下了很多未想做、要做却未做完的事。

  • 陆陆续续的看了一些英语,不过似乎并没起到什么作用,希望之后多少能有些进展。
  • 很早之前就已看过Android开发的东西,但一直没有真正动手做过什么。希望在2014年能做个小东西。

douban的Android客户端

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

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

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

PS:

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

京东夺宝岛抢拍脚本

京东的夺宝岛是京东的“瑕疵品”拍卖平台。试着拍了个物品,发现竞争还挺激烈。在拍卖即将结束的前几秒,大量买家争相出价,要想用心仪的价格抢拍到自己的物品并不是一件容易的事。
简单的分析了一下夺宝岛的页面,感觉要实现一个抢拍脚本并不麻烦。找了一下没发现现成插件,于是就自己动手了。
要实现抢拍功能,一般思路是做成浏览器插件。做浏览器插件固然不错,就是写起来稍微麻烦了些。更简单的方式是用“浏览器收藏夹”在当前页面执行脚本。将javascript:void(alert('执行当前脚本'))加入浏览器收藏夹,点击该条目时将在当前页面执行JS脚本。
利用浏览器的这一特性,我写了下面的脚本。修改脚本中的最高出价以及用户昵称,将脚本并成一行,添加到浏览器的收藏夹。进入需要抢拍的页面,点击,然后就会自动帮你出价了。

javascript:void(
  t=setInterval(function(){
    max=450;//你的最高出价,超过这个价格就不抢了
    uid='vicalloy';//你在京东的昵称(总不能和自己抢东西吧)
    did=$('.list-info>li.fore1').text().replace('夺宝编号:', '');
    url="http://auction.360buy.com/json/paimai/bid_records?pageNo=1&pageSize=1&dealId="+did;
    ct=$('.over-time>strong').text();
    if (parseInt(ct)>10) return;//在最后10秒开抢
    $.getJSON(url, function(d){
      p = parseInt(d.datas[0].price)+1;
      cuid = d.datas[0].userNickName;
      if (p>max) {
        clearInterval(t);
        return;
      }
      if (uid==cuid) return;
      $.get("http://auction.360buy.com/json/paimai/bid?dealId="+did+"&price="+p);
    });
  }, 1000))//一秒钟刷新一次价格,如果你希望提高出价的成功率,可将间隔改小。

让Mac启用休眠模式

在windows下除关机外还支持待机和休眠两种“关机”模式。考虑到有人可能并不了解待机和休眠的区别,这里简单的介绍下。

  • 待机
    计算机在待机状态时,内存中的信息未存入硬盘中,计算机可以被迅速唤醒。如果断电,内存数据将丢失无法常唤醒。
  • 休眠
    计算机在关闭前首先将内存中的信息存入硬盘,唤醒时将硬盘上的数据重写回内存。休眠状态下的唤醒速度比待机慢,好处是休眠后可以断电。

在Mac中就只有睡眠一种待机模式了。默认情况下Mac的睡眠相当于windows的待机模式。虽然Mac mini的待机功耗非常低,不过长期待机浪费的电加起来也不少,对产品寿命也会有些影响。实际上Mac已经提供了对休眠功能的支持,稍微做些设置即可将睡眠的默认行为由“待机”改为“休眠”。
Mac的睡眠方式说明:

  • 0 (quick): Default sleep behavior on most Apple computers. RAM is still powered on while
    sleeping. Wake up is fast. Safe sleep is disabled.
  • 1 (deep): Hibernation behavior. System is totally shut down while sleeping. RAM contents
    are dumped to disk. Wake up is slow.
  • 3 (safe): Default behavior on Powerbook HD and later computers. RAM is still powered
    on while sleeping. Wake up is fast. Safe sleep is enabled, so RAM contents are
    also dumped to disk before going to sleep.
  • 5 (deep): Same as mode 1 for systems with encrypted virtual memory.
  • 7 (safe): Same as mode 3 for systems with encrypted virtual memory
  • 注: 我使用5的时候无法正常唤醒,因此不建议使用5&7

查看当前的睡眠模式: pmset -g | grep hibernatemode
修改睡眠模式: sudo pmset -a hibernatemode X

2013年新年期望

龙年最后一天上班,写下对来年的期望。有如新春播下的种子,期待来年能开出绚丽的花朵。

  • 把英语提高些。达到在无字幕情况下轻松看懂美剧的程度
    英语是一种工具,它将影响你的视野。如果可以轻松听懂日常的英语会话,那会对读写等起到很好的正反馈。
  • 工作内容有趣些,认识些有趣的“家伙”,一起做能让自己满意的产品
    让最广大的用户使用自己的作品,解决用户的需求,是一个创造者最到的乐趣。能让用户满意,这至少需要先让自己满意。
  • 收入方面能有所改善
    我一直都没有太多的经济观念,过着一人吃饱全家不饿的生活。但现在已经不再是一个人了。生活的柴米油盐都和¥有关系。有时候¥会影响生活品质进而影响一个人的精神状态。
  • others
    ……

静待花开

随机迷宫生成算法

在线迷宫游戏地址: 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版在生成迷宫的过程中增加了随机处理,对应算法也稍微复杂一点点。

Mac初体验

经不住身边苹果迷们的忽悠,入手了个Mac mini。此前一直混用windows、ubuntu,初次使用Mac下倒也没感到什么太多的不适应。如果说真有什么不适应,主要还是一些windows下的软件没有Mac版,或是Mac版的功能要比windows版的简陋很多。
下面推荐些Mac下的软件

  • TotalTerminal
    命令行增强工具。增加多Tab功能,多个配色方案可选。
  • 启用命令行颜色显示
    在linux下不同类型的文件会以不同颜色显示,Mac下没有默认开启该功能。
# 在~/.bash_profile 中增加
export CLICOLOR=1
  • 安装 brew 为Mac增加类似apt-get的功能
  • 下面这个脚本,大家应当都懂的
#!/usr/bin/env bash
while true
do
    ssh -D 7070 -C xx@haoluobo.com
done

to myself

今日之日不可留,奈何多烦忧。只是作为凡人,难免会有些凡人的烦恼。
写下一些NOTE,提醒自己不要迷失。

  • 乐观
    负面的情绪从来都不会起到什么积极的作用。
  • 耐心&宽容
    对自己宽容,对他人宽容。在很多事面前,你是无力的。改变自己所能改变,然后给自己多些宽容,别让自己陷入负面情绪的包围中。
  • 目标
    纷繁的世界太容易让自己迷失,在纷繁的事情面前被其所吸引,被其所恼,渐渐忘了自己是为了什么。在遇到问题时先想想自己的目标是什么,如果无关大局就先放下,不必再被其所恼。
  • 原则
    没有原则也就没有底线,在底线一步步沦落的过程中也将迷失自己。给自己制定一些最基本的原则,在原则范围了行事。

让你的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。
注: