<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Tin&#039;s Blog &#187; Tech.技术</title>
	<atom:link href="http://www.diamondtin.com/category/tech-posts/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.diamondtin.com</link>
	<description>you are coming a long way...</description>
	<lastBuildDate>Wed, 11 Aug 2010 09:43:26 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Leopard下如何让你的sudo不需要输密码</title>
		<link>http://www.diamondtin.com/2010/disable_password_for_sudo_in_leopard/</link>
		<comments>http://www.diamondtin.com/2010/disable_password_for_sudo_in_leopard/#comments</comments>
		<pubDate>Wed, 21 Jul 2010 08:21:52 +0000</pubDate>
		<dc:creator>tin</dc:creator>
				<category><![CDATA[Tech.技术]]></category>
		<category><![CDATA[leopard]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[terminal]]></category>

		<guid isPermaLink="false">http://www.diamondtin.com/?p=964</guid>
		<description><![CDATA[在Snow Leopard的Terminal里面用sudo的时候总是需要输入密码，而在单位的FreeBSD服务器上则不需要。我觉得从安全角度来说这个密码用处不大，有了反而会浪费时间。 搜索了一下，发现要这样做： ... ]]></description>
			<content:encoded><![CDATA[<p>在Snow Leopard的Terminal里面用sudo的时候总是需要输入密码，而在单位的FreeBSD服务器上则不需要。我觉得从安全角度来说这个密码用处不大，有了反而会浪费时间。</p>
<p>搜索了一下，<a href="http://mattdanger.net/2009/01/sudo-without-a-password-in-mac-os-x/">发现要这样做</a>：</p>
<p>修改/etc/sudoers文件（记得sudo vi它，存的时候要w!），去掉这一行前面的#号：</p>
<p><code>%wheel	ALL=(ALL)	NOPASSWD: ALL</code></p>
<p>然后执行下面命令，记得将your_username替换为你的用户名：</p>
<p><code>sudo dscl . append /Groups/wheel GroupMembership your_username</code></p>
<p>从此就不需要在sudo的时候输入密码了。</p>]]></content:encoded>
			<wfw:commentRss>http://www.diamondtin.com/2010/disable_password_for_sudo_in_leopard/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Cassandra的一致性级别</title>
		<link>http://www.diamondtin.com/2010/cassandra_consistent_level/</link>
		<comments>http://www.diamondtin.com/2010/cassandra_consistent_level/#comments</comments>
		<pubDate>Wed, 14 Jul 2010 05:53:44 +0000</pubDate>
		<dc:creator>tin</dc:creator>
				<category><![CDATA[Tech.技术]]></category>
		<category><![CDATA[cassandra]]></category>
		<category><![CDATA[consistency]]></category>

		<guid isPermaLink="false">http://www.diamondtin.com/?p=961</guid>
		<description><![CDATA[翻译Cassandra文档中的一段。 写一致性级别Write ZERO: 不保证一致。写操作在后台异步执行。除非CASSANDRA-685 修正，否则当太多写错作排队的时候，buffer会膨胀，后果很坏。 ANY： （需要0.6的Cassandra... ]]></description>
			<content:encoded><![CDATA[<p>翻译<a href="http://wiki.apache.org/cassandra/API#ConsistencyLevel">Cassandra文档中的一段。</a></p>
<h3>写一致性级别Write</h3>
<dl>
<dt>ZERO: </dt>
<dd>不保证一致。写操作在后台异步执行。除非CASSANDRA-685 修正，否则当太多写错作排队的时候，buffer会膨胀，后果很坏。</dd>
<dt>ANY：</dt>
<dd>（需要0.6的Cassandra）保证至少写入到1个节点中，包括示意（hinted）的接收者。</dd>
<dt>ONE：</dt>
<dd>保证写操作在回复客户端前至少已经进入1个节点的commit log和memory table。</dd>
<dt>QUORUM：</dt>
<dd>保证写操作在回复客户端前至少被写入到 （<复制因数> / 2 + 1）个节点中。</dd>
<dt>ALL：</dt>
<dd>保证写操作在回复客户端前已经被写入到 <复制因数> 个节点中。任何节点如果没有响应，则操作失败。</dd>
</dl>
<h3>读一致性级别别Read：</h3>
<dl>
<dt>ZERO：</dt>
<dd>不支持，因为没有意义。</dd>
<dt>ANY：</dt>
<dd>不支持，应该使用ONE来代替。</dd>
<dt>ONE：</dt>
<dd>将会返回第一个有响应结果的节点返回的数据。在使用ConsistencyLevel.ONE的时候，一致性检查永远是在后台线程中来修复一致性问题。这意味着如果开始的读取得到了旧数据时后续的调用可以返回正确的数据（这叫做读取修复 read repair）</dd>
<dt>QUORUM：</dt>
<dd>查询所有的节点，一但绝大多数复制节点返回了结果，返回具有最新的时间戳的纪录。其余复制节点的结果会在后台进行检查。</dd>
<dt>ALL：</dt>
<dd>查询所有的节点，一但所有复制节点返回了结果，返回具有最新的时间戳的纪录。任何节点如果没有响应，则操作失败。</dd>
</dl>]]></content:encoded>
			<wfw:commentRss>http://www.diamondtin.com/2010/cassandra_consistent_level/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>python里面检测内存容量</title>
		<link>http://www.diamondtin.com/2010/python_memory_usage_profile/</link>
		<comments>http://www.diamondtin.com/2010/python_memory_usage_profile/#comments</comments>
		<pubDate>Thu, 15 Apr 2010 03:16:28 +0000</pubDate>
		<dc:creator>tin</dc:creator>
				<category><![CDATA[Tech.技术]]></category>

		<guid isPermaLink="false">http://www.diamondtin.com/?p=917</guid>
		<description><![CDATA[今天要做一个python里面内存效率的测试，所以需要查看当前运行的python unittest的内存占用情况，查了一下发现psutil可以帮助你做这个事情，这样的代码就可以工作，需要安装psutil，我用的sudo pip... ]]></description>
			<content:encoded><![CDATA[<p>今天要做一个python里面内存效率的测试，所以需要查看当前运行的python unittest的内存占用情况，查了一下发现psutil可以帮助你做这个事情，这样的代码就可以工作，需要安装psutil，我用的sudo pip install psutil：</p>
<pre class="code">
class MemoryInfo(object):
    def __init__(self):
        self.current_process_id = os.getpid()
        self.current_process = Process(self.current_process_id)

    def usage(self):
        return self.current_process.get_memory_info()

    def print_usage(self):
        usage = self.usage()
        print '物理内存: %sKB, 虚拟内存: %sKB' % (usage[0]/1024, usage[1]/1024)
</pre>
<p>用的时候你可以实例化一个MemoryInfo()然后分多次调用它的print_usage方法。结绳记事。</p>]]></content:encoded>
			<wfw:commentRss>http://www.diamondtin.com/2010/python_memory_usage_profile/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Web as a platform</title>
		<link>http://www.diamondtin.com/2010/web-as-a-platform/</link>
		<comments>http://www.diamondtin.com/2010/web-as-a-platform/#comments</comments>
		<pubDate>Fri, 09 Apr 2010 22:48:49 +0000</pubDate>
		<dc:creator>tin</dc:creator>
				<category><![CDATA[Tech.技术]]></category>
		<category><![CDATA[web rest atom]]></category>

		<guid isPermaLink="false">http://www.diamondtin.com/2010/web-as-a-platform/</guid>
		<description><![CDATA[Matin fowler 大师在这篇文章 《Richardson Maturity Model: steps toward the glory of REST》，用一种伪成熟度模型的方式为我们揭示简单的Rest如何让Web成为未来软件开发的一个通用平台。其实我以前就职的Thoug... ]]></description>
			<content:encoded><![CDATA[<p>Matin fowler 大师在这篇文章 <a href="http://martinfowler.com/articles/richardsonMaturityModel.html">《Richardson Maturity Model: steps toward the glory of REST》</a>，用一种伪成熟度模型的方式为我们揭示简单的Rest如何让Web成为未来软件开发的一个通用平台。其实我以前就职的ThoughtWorks里面的同事早就在研究Web as platform这个Buzz，因为这是一种通过成熟的标准让我们日常的开发更简单更容易被Mashup的好方法。其核心思想就是利用Rest和Atom让应用程序API变成Plain web应用，这样所有现有的Web应用api就很容易被你的应用Mash up进来，这样我们的世界就真的成为了一个网。所以，坚持Rest best practice，争取早点让你的系统建在Web平台上。</p>
<p>Atom在让Rest api连接起来，让你的应用变为以资源为中心很重要：</p>
<ul>
<li><a href="http://atompub.org/rfc4287.html">RFC 4287: The Atom Syndication Format</a></li>
<li><a href="http://www.iana.org/assignments/link-relations/link-relations.xhtml">Atom Link Relations</a></li>
</ul>]]></content:encoded>
			<wfw:commentRss>http://www.diamondtin.com/2010/web-as-a-platform/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Python中的method_missing和*get*钩子方法族</title>
		<link>http://www.diamondtin.com/2009/method_missing_and_get_methods_in_python_object/</link>
		<comments>http://www.diamondtin.com/2009/method_missing_and_get_methods_in_python_object/#comments</comments>
		<pubDate>Fri, 11 Dec 2009 14:50:05 +0000</pubDate>
		<dc:creator>tin</dc:creator>
				<category><![CDATA[Tech.技术]]></category>
		<category><![CDATA[language]]></category>
		<category><![CDATA[meta programming]]></category>
		<category><![CDATA[method_missing]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://tin.zztin.com/2009/%e5%88%9a%e6%89%8d%e5%ae%9e%e9%aa%8c%e4%ba%86%e4%b8%80%e4%b8%8b%ef%bc%8c%e5%8f%91%e7%8e%b0python%e9%87%8c%e9%9d%a2%e5%a3%b0%e6%98%8e%e7%b1%bb%e7%9a%84%e6%97%b6%e5%80%99%e6%98%af%e5%90%a6%e9%80%89/</guid>
		<description><![CDATA[刚才实验了一下，发现Python里面声明类的时候是否选择继承objects还是有很大区别的。只有继承了objects，才可以使用钩子方法如&#8217;__get__&#8217;, &#8216;__set__&#8217;, &#8216;__getattr__&#8217;, &#8216;__getat... ]]></description>
			<content:encoded><![CDATA[<p>刚才实验了一下，发现Python里面声明类的时候是否选择继承objects还是有很大区别的。只有继承了objects，才可以使用钩子方法如&#8217;__get__&#8217;, &#8216;__set__&#8217;, &#8216;__getattr__&#8217;, &#8216;__getattribute__&#8217;这些方法。也就是说这些有用的钩子方法是所谓的new object里面的东西。今天我在项目的代码里面尝试了一下类似Ruby method_missing的写法，实验在Python里面加点元编程的东西。发现很相似的三个方法&#8217;__get__&#8217;, &#8216;__getattr__&#8217;, &#8216;__getattribute__&#8217;方法区别挺大。注意，一定要继承object才可以享用三个钩子方法。</p>
<ul>
<li>访问对象方法的时候首先会访问&#8217;__getattribute__&#8217;，它是访问类里面所有属性的时候都要经过的方法，包括创建对象的时候访问&#8217;__init__&#8217;, &#8216;_meta&#8217;这些都回经过&#8217;__getattribute__&#8217;访问。如果你什么异常都不抛出，它就不会访问&#8217;__getattr__&#8217;方法。
<li>
<li>如果&#8217;__getattribute__&#8217;方法抛出&#8217;AttributeError&#8217;，那么会继续尝试访问&#8217;__getattr__&#8217;方法。再有异常抛出，那么这个类就没有钩子再接住异常了。所以从这个角度来说它的工作方式非常相似于Ruby的method_missing。</li>
<li>我本以为&#8217;__getattr__&#8217;是系统内建函数hasattr(object, property)优先访问的方法。不过实验证明，实际上还是先走&#8217;__getattribute__&#8217;后走&#8217;__getattr__&#8217;的。也就是说hasattr这样的函数没有优先绑定&#8217;__getattr__&#8217;。</li>
<li>&#8216;__get__&#8217;方法是用来监视自己的类作为其它类的成员的时候被访问的钩子。对应的是&#8217;__set__&#8217;，是相应属性被赋值时的钩子。这个方法与&#8217;__getattr__&#8217;和&#8217;__getattribute__&#8217;完全不是一会儿事。刚才看《Python核心编程一书》完全没有解释清楚。<a href="http://users.rcn.com/python/download/Descriptor.htm">《How-To Guide for Descriptors》</a>这篇文章对解释&#8217;__get__&#8217;帮助很大，有兴趣可以看看，不过我倒是没有想到什么是合理的应用场合。</li>
</ul>
<p>我目前还没有调用方法的method_missing，目前只是访问一些属性。我们实际处理的是一个可以直接用属性名读取/修改对象里面的持久化json属性的方法，就是类持有一个{&#8216;property&#8217;: &#8216;value&#8217;}的json文本属性，我们就可以直接用Model.property访问和修改里面的方法，而不用特别的去生命json结构过来。是一个在Python中做meta programming的尝试。</p>
<p>测试刚才说的几个*get*方法的测试如下:</p>
<pre>
# -*- coding: utf8 -*-
import unittest

class A(object):
    def __init__(self):
        print 'init A'

    def __get__(self, *args):
        print '__get__ A', args

    def __set__(self, *args):
        print '__set__ A', args

class B(object):
    a = A()

    def __init__(self):
        print 'init B'

    def __getattr__(self, *args):
        print '__getattr__ B', args

    def __getattribute__(self, *args):
        print '__getattribute__ B', args
        raise AttributeError

    def __get__(self, *args):
        print '__get__ B', args

    def __set__(self, *args):
        print '__set__ B', args

class MeTest(unittest.TestCase):
    def test_simple(self):
        b = B()
        print b.a
        b.a = A()
        b.c
        hasattr(b, 'e')
</pre>]]></content:encoded>
			<wfw:commentRss>http://www.diamondtin.com/2009/method_missing_and_get_methods_in_python_object/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>在Mac下使用脚本重载proxy自动配置脚本（pac）</title>
		<link>http://www.diamondtin.com/2009/reloading-pac-script-in-mac/</link>
		<comments>http://www.diamondtin.com/2009/reloading-pac-script-in-mac/#comments</comments>
		<pubDate>Thu, 05 Nov 2009 00:53:43 +0000</pubDate>
		<dc:creator>tin</dc:creator>
				<category><![CDATA[Tech.技术]]></category>
		<category><![CDATA[great firewall]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[pac]]></category>
		<category><![CDATA[proxy]]></category>
		<category><![CDATA[script]]></category>

		<guid isPermaLink="false">http://tin.zztin.com/?p=825</guid>
		<description><![CDATA[Mac下对网络设备使用proxy自动配置脚本可以透明使用代理穿墙（可以配合ssh tunnel和tor）。但是我一直不知道如何用脚本让系统重新载入pac文件（在更新了pac的规则时我们需要重载配置）。昨天... ]]></description>
			<content:encoded><![CDATA[<p>Mac下对网络设备使用proxy自动配置脚本可以透明使用代理穿墙（可以配合<a href="http://tin.zztin.com/2009/ssh-tunnel-and-pac">ssh tunnel</a>和tor）。但是我一直不知道如何用脚本让系统重新载入pac文件（在更新了pac的规则时我们需要重载配置）。昨天一位叫做Dylan的网友留言告诉了我如何做，我在此记录一下。在命令行下面：</p>
<p><code>networksetup listallnetworkservices</code></p>
<p>然后会会返回一个网络连接服务的列表：</p>
<p><code><br />
An asterisk (*) denotes that a network service is disabled.<br />
Bluetooth DUN<br />
ADSL<br />
Ethernet<br />
FireWire<br />
AirPort<br />
Bluetooth PAN<br />
</code></p>
<p>我一般需要配置pac文件的是Ethernet和AirPort，那么相应的重载命令是：</p>
<p><code><br />
sudo networksetup -setautoproxystate 'AirPort' off<br />
sudo networksetup -setautoproxyurl 'AirPort' 'file://localhost/Users/tin/pac/tin.pac'<br />
sudo networksetup -setautoproxystate 'AirPort' on<br />
sudo networksetup -setautoproxystate 'Ethernet' off<br />
sudo networksetup -setautoproxyurl 'Ethernet' 'file://localhost/Users/tin/pac/tin.pac'<br />
sudo networksetup -setautoproxystate 'Ethernet' on<br />
</code></p>
<p>然后pac文件就已经被重载完毕啦！在此感谢Dylan。</p>
<p>顺便共享一下我在bash下的alias：</p>
<p><code><br />
alias px='ssh -qTfnNC -D 7777 tin<a href="/mentions/">@zz</a>tin.com'<br />
alias rpx="sudo networksetup -setautoproxystate 'AirPort' off;sudo networksetup -setautoproxyurl 'AirPort' 'file://localhost/Users/tin/pac/tin    .pac';sudo networksetup -setautoproxystate 'AirPort' on;sudo networksetup -setautoproxystate 'Ethernet' off;sudo networksetup -setautoproxyurl     'Ethernet' 'file://localhost/Users/tin/pac/tin.pac';sudo networksetup -setautoproxystate 'Ethernet' on"<br />
</code></p>]]></content:encoded>
			<wfw:commentRss>http://www.diamondtin.com/2009/reloading-pac-script-in-mac/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>DDD重构初步</title>
		<link>http://www.diamondtin.com/2009/ddd-refactory-first-step/</link>
		<comments>http://www.diamondtin.com/2009/ddd-refactory-first-step/#comments</comments>
		<pubDate>Wed, 04 Nov 2009 01:24:17 +0000</pubDate>
		<dc:creator>tin</dc:creator>
				<category><![CDATA[Tech.技术]]></category>
		<category><![CDATA[DDD]]></category>
		<category><![CDATA[OO]]></category>
		<category><![CDATA[Refactory]]></category>
		<category><![CDATA[TDD]]></category>
		<category><![CDATA[重构]]></category>
		<category><![CDATA[领域模型]]></category>

		<guid isPermaLink="false">http://tin.zztin.com/?p=823</guid>
		<description><![CDATA[所做的系统是一个连接到外部信息发送和搜索引擎调用服务的Web前端系统。系统与外部的接口使用的是一层Service外观进行包装，原先的设计目的是使用服务层剥离对外部系统的强依赖──解耦... ]]></description>
			<content:encoded><![CDATA[<p>所做的系统是一个连接到外部信息发送和搜索引擎调用服务的Web前端系统。系统与外部的接口使用的是一层Service外观进行包装，原先的设计目的是使用服务层剥离对外部系统的强依赖──解耦，同时还希望使用Service将系统的商业逻辑集中存放──提高复用的可能。但是实际上我们发现Service这样的抽取方法并没有提高代码的复用度，反而造成数据结构和其算法的大量重复。经过分析，发现由于使用了大量的Hash结构存放接口间的返回结果，造成数据与其Service内部的行为分离，传递后商业逻辑就出现了重复（这样的结果是引入大量Quick but dirty的解决方案所欠下的技术债造成的）。所以我和我的Pair绝对对其进行DDD（领域模型驱动设计）的重构。</p>
<p>领域模型驱动设计和面向对象设计在代码的抽象上很相似，它们都推荐让数据结构（状态）与商业逻辑（行为）统一管理。这样数据的状态与行为就不会分离，这样可以很大的减少由于商业逻辑分散造成的代码重复。这可以让我们实现我们非常重视的DRY（Don&#8217;t repeat yourself）。<br />
一开始我们尝试的是找到重复的商业逻辑和其对应的数据结构，然后尝试让它们映射到我们的领域模型。这样的效果还不错，但是经过了一天的工作，我们发现我们对领域模型的理解有问题，我们居然抽取出了重复的领域模型类。这个时候暴露的问题是我们对系统的领域模型没有统一和深入的认识。</p>
<p>所以下一步我们计划进行领域模型语言的讨论会，目的就是使用自己的“领域语言”描述系统的所有行为，从这样的领域故事中找到我们的领域模型（领域概念模型，不是具体编程的时候的类）。</p>
<p>领域模型讨论会最好由最熟悉领域模型的人起草，可以由这个人把它写在白板上。领域的故事最好能够涵盖系统的主要行为，描述要使用简练的语言。一般来说IT系统的内部行为可能很复杂，但是到了领域高度还是可以用比较简单的语言描述的，如果遇到一块白板不够的话最好首先考虑提高观察的高度，让领域的描述简练一些，其次再考虑扩展到第二块白板。在这个过程中我们要注意消除歧义，比如同样一个“术语”在两个功能区域中出现，那我们就要妥善的给他们各自取一个容易区分的“领域术语”作为名字。还有就是我们应该在写领域故事的时候考虑领域模型（或者理解为系统模块的抽象）之间的交互关系，最好在写领域故事的时候对行为的归属（它会指导行为到底会被建模在哪个领域模型中，可以体现为类的调用关系，哪个类持有交互逻辑）达成共识，这个时候达成的共识比在做具体的OO设计时候分辨商业逻辑归属要更体现商业价值。完成领域故事后我们要找到其中的所有领域模型（也就是前面说的领域对象和领域中的术语）。然后团队最好一起通读这个用户故事，一起讨论是否通顺（行为是否完备，抽象是否合理），是否有遗漏（遗失的领域模型或行为）。对于有外部系统的情况下，即使外部系统是面向消息的（或者说是没有使用领域模型驱动的SOA接口），那么团队最好对消息的内容有一个讨论，对其中设计到本系统和外不系统的领域模型进行认领，然后使用一个适配器来保证数据到达系统后就使用领域模型表示，外不系统的数据（一般没有行为）最好也使用一个领域模型进行约定。</p>
<p>完成了上面这一步后，DDD最重要的一部分就完成了，它可以实现系统领域模型自顶向下的“名正言顺”，减少在自底向上的重构过程中产生的大量重复领域模型。下面的重构过程就是给领域模型写测试，使用TDD（或者也可以用BDD的方式提早对行为做验收测试，用它们来驱动对领域模型的实现，其实对领域模型的TDD和BDD是殊路同归）的方式逐一实现领域模型。而后争取给系统写一些验收测试或者高级别的集成测试，再逐一替换这些领域模型。这样就达到了DDD重构的效果。</p>]]></content:encoded>
			<wfw:commentRss>http://www.diamondtin.com/2009/ddd-refactory-first-step/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>可测试性驱动开发还不是“测试驱动开发”</title>
		<link>http://www.diamondtin.com/2009/testability-driven-development-is-not-classical-test-driven-development/</link>
		<comments>http://www.diamondtin.com/2009/testability-driven-development-is-not-classical-test-driven-development/#comments</comments>
		<pubDate>Tue, 20 Oct 2009 01:33:56 +0000</pubDate>
		<dc:creator>tin</dc:creator>
				<category><![CDATA[Tech.技术]]></category>

		<guid isPermaLink="false">http://tin.zztin.com/?p=819</guid>
		<description><![CDATA[看完老赵精彩的两篇“可测试性驱动开发（上）”，“可测试性驱动开发（下）”。 写了篇回复 老赵，我觉得你说的“可测试性驱动开发”和“测试驱动开发”的结果是非常接近的，可是实际... ]]></description>
			<content:encoded><![CDATA[<p>看完老赵精彩的两篇<a href="http://www.cnblogs.com/JeffreyZhao/archive/2009/10/15/testability-driven-development-1.html">“可测试性驱动开发（上）”</a>，<a href="http://www.cnblogs.com/JeffreyZhao/archive/2009/10/19/testability-driven-development-2.html">“可测试性驱动开发（下）”</a>。</p>
<p>写了篇回复</p>
<blockquote>
<p>老赵，我觉得你说的“可测试性驱动开发”和“测试驱动开发”的结果是非常接近的，可是实际观察下来我觉得不是一样的。我觉得测试驱动开发的一个好处就是从外界向内部逐渐迫近，逐渐的暴露的你意图。意图其实是更接近你的商业流程和商业价值的。所以更接近与“意图驱动开发”。因为TDD鼓励从系统的外部行为向内部行为逐步细化，逐步测试－通过，循环。这样产生的结果就是方法小，方法名考究，高层的代码非常容易读懂（经常达到看起来就像文档）。</p>
<p>可是在“可测试性驱动开发”中，我觉得随时考虑的还是“可测试性”，但是“可测试性”本身与商业价值无关。所以驱动开发的东西就转变为程序员自己的一些“修养”问题了，你可能会倾向于使用模式来解决一些微观问题，让代码具有“可测试性”。这种做法可以产生组织良好的代码，它对于程序员来说易读（容易理解算法细节），但是这样的代码在被维护更久以后容易产生与商业价值的偏离。还有就是“测试性驱动”的经济问题，如果一个测试是纯技术意图驱动的，那么就是追本逐末了。</p>
<p>测试驱动开发中的ATDD（验收测试驱动开发）鼓励你将系统的流程Spec在实现前写出来作为驱动，而BDD则从微观行为上将你的领域模型的行为Spec写出来驱动，这两种方式我想才是经典TDD的“新外衣”，因为他们都继承了“意图驱动”并进化为“商业意图（价值）驱动”。</p>
<p>此文甚好，只是我觉得上面问题是个关键，”目标“最好还是在产生”策略“之前找到比较好，所以才写这个评论，冒犯了 ^___^</p>
</blockquote>]]></content:encoded>
			<wfw:commentRss>http://www.diamondtin.com/2009/testability-driven-development-is-not-classical-test-driven-development/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>程序员的点滴回忆</title>
		<link>http://www.diamondtin.com/2009/tips-of-a-programmer-1/</link>
		<comments>http://www.diamondtin.com/2009/tips-of-a-programmer-1/#comments</comments>
		<pubDate>Wed, 30 Sep 2009 16:10:17 +0000</pubDate>
		<dc:creator>tin</dc:creator>
				<category><![CDATA[Tech.技术]]></category>

		<guid isPermaLink="false">http://tin.zztin.com/?p=806</guid>
		<description><![CDATA[在ThoughtWorks就要两年了，相比进来之前的自己，现在做事可以抱有更低调的态度了。因为当你和众多聪明的人做事情的时候，你不得不谦虚，逐渐的你就会形成“开放性格”，这是我从ThoughtWork... ]]></description>
			<content:encoded><![CDATA[<p>在ThoughtWorks就要两年了，相比进来之前的自己，现在做事可以抱有更低调的态度了。因为当你和众多聪明的人做事情的时候，你不得不谦虚，逐渐的你就会形成“开放性格”，这是我从ThoughtWorks收获的最有价值的东西。</p>
<p>今天反思一下自己在开发中遇到的一些问题和TW的答案（只是一个Check list，没有逻辑顺序），有如下地方需要考虑：</p>
<ol>
<li>做一个需求（对于我们指User Story或Tech Task）的时候要做好评估。评估一般都不准，因为预测本身就不容易准确。有几个方法帮助你让它变得准确，最重要的就是在你工作的团队里面计算Velocity，通过不断的评估Story point（实施工作量的一个概要评估，可以使用1、2、4、8、16这样的大概数字，和人天没有关系）记录实际完成时间，两者相除则为Velocity。有了Velocity就可以作为之后该团队评估需求实现所需时间的参考。Story point使用民主投票的方式，民主要做好就要保护好“异见”，任何高估和低估的情况都要平等的讨论清楚，并达成一致。<br />
上面说的方法在某个需求有未知技术点的时候会产生严重的评估偏差，甚至完全无法评估。此时一般使用的方法是Spike。Spike的做法是从技术可行性着手，多参考网上的资料和现成代码，使用Quick and Dirty的方式让他们工作，并且在这个过程中评经验得出实现它大概付出的代价，帮助你正确评估一个需求。Spike要尽量覆盖自己所有拿不准的技术点，不要深度，但是要有足够的广度。Spike代码可以不写测试，但是推荐使用测试的方式去实验（因为它更容易组织）。Spike代码一样需要使用源代码控制，并且要多做提交。最后，最重要的一点是Spike代码永远不要进入production code base。李晓曾经说理想的Spike方式是做一个基本满足需求的Spike原型，然后抛弃，重新用TDD的方式实现相同的需求，保证进入code base的代码都是TDD出来（或者起码是有测试保证）的。</li>
<li>关于些代码是否要测试的问题，Kent beck说我只给会被Break的逻辑写测试。但是实际上不仅如此，在Kent beck总结出的TDD中，测试还是用来明确你的“意图”的代码。做事要有明确的“意图”，一方面它保证你不会迷失目标，另一方面它也是你和你的代码还有你的同事沟通（还包括你自己）的重要手段。但是这里有一个容易让人迷惑的事情，TDD出来的测试到底是测试分类（单元、集成、验收）中的哪一种呢？同事们的答案是它们没有直接关系。TDD是可以表达你对代码行为/结果“期望”的任何一种测试，当然你要尽量保证你的测试是更靠下面的测试（单元测试），因为底层的测试运行快依赖少，所以保证你的红-绿节奏更快。冤有头债有主，每个测试表明一个“意图”，几个“意图”对应一个需求，一个需求对应一些商业价值。如此的映射帮助你从代码的“意图”到“价值”打通经脉。</li>
<li>一般说User story以“As someone, I want to do something, Then I can achieve some business goal”的形式书写。一般说与之对应的验收条件以“Given some context，When something happened, Then you got the result”的方式去组织，这种书写方式可以保证你的验收条件被映射到一些Specs上面，一些逻辑相关的Specs就组成了对一个Feature的验证。如果你用这种方式组织你的测试，那么你就自然的实践了BDD。BDD是一个很大的概念，组只好测试只是个开始。Ruby里面的Cucumber是一个很好的验收测试工具，它能帮助你更好的从你使用需求及验收特性Driven你的测试，书写有价值的代码。而Rspec这样的BDD测试框架则可以帮助对你的其它测试（如单元测试）进行管理。这些都是形式，但是形式影响你思考的方式，最终可以帮助你提升的代码的“价值”量，减少“无价值”的代码。</li>
<li>如果你是一个测试驱动狂人，你是否要考虑试验ATDD（验收测试驱动）呢？我们认为ATDD是TDD的一个极致形式（因为它最大程度保证你的商业意图和代码的有效映射）。但是这里还是有很高的门槛。一个是ATDD的难度的确比其它层次的TDD要高，很多时候你都苦恼于不知道如何做Assertion，这种问题会影响效率。因为测试代码本身是没有商业价值的。另一方面即使你是脑力超人，可以很好的写出验收测试级别的测试代码作为驱动，这些代码运行的速度一般也比较令人失望。因为根据测试分组（Category）的理论，越在上层的测试运行速度越慢。所以，如果你用验收测试作为高层驱动可能会拖慢红-绿节奏。这时你需要清除的知道要向下面层次的TDD进行委托，保证节奏效率的同时还能清晰的让自己的测试回溯到“商业价值”上面。</li>
<li>保持一致的标准。有的时候你会说我们的Code base不允许Quick and Dirty代码的污染，有的时候你又说我们的首要任务是让它Work。Teck lead此时要保证好统一的标准，找到自己团队能够接受的合理平衡。</li>
<li>站立会议一定要短，昨天作了啥，有什么问题，今天准备做啥这个形式如果哪个方面与团队没什么关系就可以省略。站立会议不是报功会，所以不要说你Fix的bug的编号是什么，那个完全没有价值。</li>
<li>回顾会议非常重要，如果大家都觉得需要回顾会议的时候就开。时间可以是几个小时一次也可以是几个星期一次。常用的Theme是“Well/Less well/Puzzle”，回顾会议需要Time box，一般半小时以内比较好。长时间跨度的回顾可是使用Timeline的Theme，就是大家不根据资料回忆一个时间段内发生的印象深刻的事情（团队和项目相关的）和记忆中他们发生的时间，然后大家讨论这个事情产生的正向/负向的效果，因为记忆会“骗人”，所以收集到的记忆的偏差实际上都可以和当时团队的情绪变化产生映射（类似精神分析法，可以帮助团队找到很多有意思的东西）。回顾产生的偏差是个很有趣的话题，这是为什么我们办公室有大量的精神病和精神分析相关书籍的原因。其它的Theme还包括Future retrospective，就是回顾“没有发生的未来”的回顾会议，使用“Well/Less  well/Puzzle”作为容器，收集你想要得到的和希望避免的事情。出了这些基本形式，我们的Bonna还发明过大字报方式（就是搜集Headline hot news，bad news，流言八卦），用来收集各种客观消息并且集体对齐进行评估。Star fish也是一个Theme，不过因为大家总是忘记它的缩写是什么意思，用的比较少。回顾会议的主持人非常重要！还有回顾会议归档以后所有Action item都需要有负责人，并且要定期验证结果。</li>
<li>结对的时候两个人产生分歧是正常的，争论也是好的。不过不要争论太久（如超过15分钟）。久的争论大部分的原因就是互相没有聆听，产生了共同障碍。此时解决方法就是暂停争论，按照听起来比较短的路径前行一段实验一下，然后再讨论。此时一般会发现殊路同归，或者发现死胡同以后可以早点掉头。</li>
<li>只结对解决重点问题和难点问题是可以的，但是大部分的问题是你根本不知道哪里是“难点”和“重点”。所以资源和体力允许的时候尽量结对解决问题。</li>
<li>评价一段代码的好坏：首先看是否容易读懂，意图是否明确。这个要求需要你无惊讶的设计（使用模式、精心的设计）还有make sense的方法/变量命名。其次代码/方法要短，代码短是硬道理。然后是是否有代码重复。都达到了以后再看效率等问题（效率关键场合除外，但是这种场合很少）。</li>
<li>做事要尽量自动化，DRY。</li>
</ol>
<p>困了，下次继续。</p>]]></content:encoded>
			<wfw:commentRss>http://www.diamondtin.com/2009/tips-of-a-programmer-1/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>再谈网页设计中的em与px</title>
		<link>http://www.diamondtin.com/2009/using-em-and-px-together-in-web-page-design/</link>
		<comments>http://www.diamondtin.com/2009/using-em-and-px-together-in-web-page-design/#comments</comments>
		<pubDate>Thu, 24 Sep 2009 02:19:58 +0000</pubDate>
		<dc:creator>tin</dc:creator>
				<category><![CDATA[Tech.技术]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[em]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[layout]]></category>
		<category><![CDATA[length unit]]></category>
		<category><![CDATA[px]]></category>

		<guid isPermaLink="false">http://tin.zztin.com/?p=803</guid>
		<description><![CDATA[回应hax大牛在“em or px“的讨论： 上次看到你在我分享的friendfeed上面的评论我就想好好讨论一下这个问题了。&#8217;em&#8217;是从字体设计上面继承的一个概念，是指字模的高度，一般书上会说em... ]]></description>
			<content:encoded><![CDATA[<p>回应hax大牛在“em or px“的讨论：</p>
<p>上次看到你在我分享的friendfeed上面的评论我就想好好讨论一下这个问题了。&#8217;em&#8217;是从字体设计上面继承的一个概念，是指字模的高度，一般书上会说em能够保证不同字体的大写X的高度保持一致。那么大写X的高度就是这个字体的em。</p>
<p>你说的px是相对单位不仅在你说的显示器尺寸上是相对的，而且由于大部分的矢量元素的渲染来说比较先进的浏览器都支持“半像素平滑”，连像素内的颜色的投影也可以是相对的（渲染引擎会进行像素平滑的计算）。</p>
<p>在网页渲染的布局上来说它要转化em到px这个单位，就是说在一定的zoom下两者是等价的。</p>
<p>但是为什么我还是很支持使用em作为首选的字体和布局单位呢？当然这不是用来保证一行到底可以显示多少文字，因为px也可以保证。主要目的是区分布局中“缩放友好”的矢量元素（如字体，布局相关的所有html元素）和“缩放不友好”的标量元素（如很多“替换元素”是不友好的，典型的如图片，还有在使用某些Windows主题以后的input元素）。在使用webkit的浏览器，缩放会更加友好，文字和布局会随缩放变化，但是图片等却保持原有的最佳尺寸。Firefox3以后所使用的全部缩放我觉得在有些时候是有用的，可是总有它让你不爽的地方⋯⋯</p>
<p>比如如果你在某些设计场合希望容器变大文字尺寸不变，从而在缩放显示更多内容。另外一些地方你希望容器和文字尺寸一起变化。px和em的配合让两种需求可以比较容易的在同一个页面出现。</p>
<p>从设计为内容服务的角度考虑，使用em作为基本单位可以让你更集中于“内容驱动”，避免过分的”设计驱动“。我的工作范畴内前者更常见，也更符合客户的需求。</p>]]></content:encoded>
			<wfw:commentRss>http://www.diamondtin.com/2009/using-em-and-px-together-in-web-page-design/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
