<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
 <channel>
  <title>梦想风暴</title>
  <link>http://dreamhead.blogbus.com</link>
  <description><![CDATA[一个小程序员的信口开河]]></description>
  <generator> by blogbus.com </generator>
  <lastBuildDate>Mon, 21 May 2012 09:55:04 +0800</lastBuildDate>
  <image>
									<url>http://public.blogbus.com/profile/8/9/0/6098/avatar_6098_96.jpg</url>
									<title>梦想风暴</title>
									<link>http://dreamhead.blogbus.com</link>
								</image>  <item>
   <title>代码之丑（十一）</title>
   <description><![CDATA[<p>全局变量永远是不受欢迎的，因为它会带来太多的问题，所以，诸如Java这样的程序设计语言干脆摒弃了全局变量。一旦我们有机会面对全局变量，想都不要想，干掉它。</p>
<p>if (IDLE == g_status) {<br />&nbsp; ...<br />}</p>
<p>那个g打头的家伙就是全局变量，它就是我们的靶子。第一直觉，我们不要直接访问全局变量，那就用函数把它封装起来：</p>
<p>int getCurrentStatus() {<br />&nbsp; return gStatus;<br />}</p>
<p>于是，代码变身了：</p>
<p>if (getCurrentStatus() == IDLE) {<br />&nbsp; ...<br />}</p>
<p>把变量封装成函数，从某种角度说，这是一种进步。但我想说，这还不够。这只是一种简单的封装，本质上来说，这与直接暴露数据差别不大，我们需要更好的封装，通常的做法是封装出行为。行为从哪来，从实际需求来。</p>
<p>就以上面这段代码为例，我们封装了status，其实，它的目的是为了与IDLE状态相比较，这就是一种行为，我们可以这样封装：</p>
<p>bool isCurrentStatus(int status) {<br />&nbsp; return status == g_status;<br />}</p>
<p>if (isCurrentStatus(IDLE)) {<br />&nbsp; ...<br />}</p>
<p>还有一种修改方式，既然IDLE是一个固定的常量，索性把它也隐藏起来：</p>
<p>bool isIdle() {<br />&nbsp; return IDLE == g_status;<br />}</p>
<p>if (isIdle()) {<br />&nbsp; ...<span style="white-space:pre">	</span><br />}</p>
<p>实际上，这种封装出行为的方式不仅仅适用于全局变量，把数据拿出来再用的情形也是经常可以见到的：</p>
<p>if (machine.getStatus() == IDLE) {<br />&nbsp; ...<br />}</p>
<p>封装的方式同上面一样，这里选择一种实现：</p>
<p>class Machine {<br /><span style="white-space: pre;">&nbsp; </span>...<br /><span style="white-space: pre;">&nbsp; </span>bool isIdle() {<br /><span style="white-space: pre;">&nbsp;   </span>return status == IDLE;<br /><span style="white-space: pre;">&nbsp; </span>}<br />}</p>
<p>if (machine.isIdle()) {<br /><span style="white-space: pre;">&nbsp; </span>...<br />}</p>
<p>封装，就得封装出个行为来。</p><!--sp-->]]></description>
   <link>http://dreamhead.blogbus.com/logs/214225975.html</link>
   <author>dreamhead</author>
   <pubDate>Sun, 20 May 2012 20:46:00 +0800</pubDate>
  </item>
  <item>
   <title>ThoughtWorks校园行，第二步</title>
   <description><![CDATA[<p>自从迈出了<a href="http://dreamhead.blogbus.com/logs/198429607.html" target="_blank">ThoughtWorks校园行的第一步</a>，西电的校园活动就一次次进行下来，我们讲了如何写代码，讲了完整的开发过程，后续的一系列校园技术讲座也已经排上了日程。</p>
<p>其实，单以效果而言，技术讲座所带来的影响是有限的，对于参加讲座的学生来说，除了知道很多新名词、新做法，多半也就是看个热闹。直接动手实践，才是一个更好的做法。</p>
<p>感谢我们优秀的市场MM，她为我们打开了一片新天地。感谢西安交通大学软件学院的领导具备的卓越眼光，为他们的学生提供了一个接触外面世界的机会。</p>
<p>于是，我们有了一个新的机会，在西安交通大学开设一门软件开发的课程。</p>
<p>这门课，我们称之为&ldquo;现代软件开发&rdquo;，其目的就是为了告诉同学们，不同于传统方式的开发方法。其实，我们本可以叫敏捷软件开发方法，但我着实不喜欢这个名字，因为这已不是我追求的东西，我只想把一些好的东西告诉同学们，所以，选了一个不容易过时的名字。</p>
<p>我们是这样设计的这门课，采用上下半场的方式运作。上半场，我们会介绍一些基本的开发方法，比如整洁代码，比如重构，比如自动化等等。而下半场，则完全是实践。我们选取了一个项目，按照我们的方式运作了一个项目，我们的同事会与同学们结对，让他们直接体会最原汁原味的ThoughtWorks开发方式。</p>
<p>就在这个周末，这个系列课程终于迈出了第一步。</p>
<p>第一次课基本上算是一个课程介绍，让为有兴趣选修这门课的同学了解这门课，以及我们的上课方式。我们讲了公司里如何做软件，还演示了结对开发和TDD。</p>
<p>第二步就这样迈了出来，在接下来的一段时间里，虽然要牺牲一些业余时间，但这也是一个很好的尝试，让我们的课程更加系统化，也给了我们的同事一个很好的锻炼机会。</p>
<p>我们的同事在课程的结尾送给同学们一句话，与其周末逛街打DOTA，还不如来写写代码。嗯，就是这样。</p><!--sp-->]]></description>
   <link>http://dreamhead.blogbus.com/logs/212749402.html</link>
   <author>dreamhead</author>
   <pubDate>Sun, 13 May 2012 21:10:00 +0800</pubDate>
  </item>
  <item>
   <title>五年思想工作者</title>
   <description><![CDATA[<p>五年了，真快。</p>
<p>工作十年，我只工作过两家公司：为我打好基础的东软和为我打开视野的ThoughtWorks，每家五年。这个换工作的速度，在IT行业里，应该算是蜗速了。</p>
<p>当年进到ThoughtWorks，我最想解惑的是如何做好软件，因为之前的开发经历里，我有太多想不明白为什么的地方，比如，为什么要写文档。选择加入ThoughtWorks，我知道这里有敏捷，貌似是解惑的途径。</p>
<p>随着自己在ThoughtWorks做过项目的增多，我了解了敏捷，这些曾经的困惑逐渐得以挥去。当有机会尝试咨询，我开始得到从更多角度看待软件开发，我开始相信改变。渐渐地，我知道了我追求的其实不是敏捷，是持续改进。</p>
<p>去年带了一个项目，在那个项目里，我做了一个尝试。我把项目的目标订在了人才培养，而非传统意义的交付。于是，在这个过程中，我花了大量的精力去教新员工写代码，帮他们设定个人成长目标，教他们做事，带着他们吃好玩好&hellip;&hellip;就是这样一个几乎都是由新ThoughtWorker&mdash;&mdash;甚至大多是毕业生&mdash;&mdash;组成的项目组，后来，这个项目成了Michael Chen口中最接近他心目中<a href="http://michael.nona.name/archives/370/" target="_blank">全面成功</a>的项目。</p>
<p>早在做咨询的最初，我就认识到，敏捷实施，管理实践很快上手，但新鲜劲一过，就会发现，收效甚微，而技术实践实施起来，却难上加难。我一度很悲观地认为，这事没法搞，我再厉害，也不可能让他们把我十年的东西在几个月内学会。去年的这个项目实验让我这个问题有了新的思考。</p>
<p>真正要敏捷起来，我们要做的并不是敏捷实践，而在于提升团队中每个人的能力，而其中的关键在于，营造团队学习氛围。这正是我们在ThoughtWorks西安办公室努力营造的，事实证明，在这样的环境下，整体的成长是很快的，而学习氛围更好的团队其实也是各方面做得更好的团队。</p>
<p><a href="http://blog.vincentx.info/" target="_blank">徐昊</a>对这个问题也有属于他的思考，结合了我们在ThoughtWorks西安办公室所做的各种努力，他提出了LOT（Learning Organiation Transformation，学习型组织转型）。</p>
<p>从了解如何好软件，到告诉别人如何做好软件，到思考真正提升团队能力，还好，五年的思想工作者，光阴不算虚度。</p><!--sp-->]]></description>
   <link>http://dreamhead.blogbus.com/logs/211517418.html</link>
   <author>dreamhead</author>
   <pubDate>Tue, 08 May 2012 23:28:00 +0800</pubDate>
  </item>
  <item>
   <title>构造函数沉思录</title>
   <description><![CDATA[<p><strong>缘起</strong></p>
<p>构造函数，是由C++引入主流程序世界的，其用意是在《C++语言的设计与演化》如是表达：</p>
<p>&nbsp; &nbsp;它建立起其它成员函数进行操作的环境基础。</p>
<p>在很早的一篇blog《<a href="http://dreamhead.blogbus.com/logs/456837.html" target="_blank">对象的声明</a>》中，我曾探讨过构造函数的来龙去脉。对于面向对语言而言，构造函数似乎是标配。</p>
<p>一个语言特性，一旦被扔到真实世界，随之而来的是，其使用往往会超出其设计者的初衷，构造函数亦是如此。</p>
<p>事实上，通过前面C++之父的描述，我们依然很难定位构造函数的准确用法。所以，我们常常看到许多人把诸多操作强塞入构造函数，造成构造函数极为复杂，进而关于导致了一些复杂的语法讨论，比如如何处理构造函数抛出的异常。</p>
<p>这里要讨论的是构造函数的另一个常见问题。</p>
<p><strong>重载构造函数</strong></p>
<p>同样是在《C++语言的设计与演化》里，有这样一段描述：</p>
<p>&nbsp; &nbsp; 观察发现，允许定义多个构造函数很有价值，因此这也就成了C++重载机制的一个重要应用方面。</p>
<p>是的，我要说的就是构造函数重载。构造函数可以重载，Java和C#也拿了过来，这似乎成了一种约定俗成。</p>
<p>在实际应用中，有不少人会这么做：给一个类创建多个构造函数，有的初始化了全部的字段/成员变量，有的只初始化诸多字段/成员变量中的几个。下面便是一个例子：</p>
<p>&nbsp; public Image(URL url, Tag tag) {<br />&nbsp; &nbsp; this.url = url;<br />&nbsp; &nbsp; this.tag = tag;<br />&nbsp; }</p>
<p>&nbsp; public Image(URL url) {<br />&nbsp; &nbsp; this.url = url;<br />&nbsp; }</p>
<p>这么做的原因通常是，初写这些代码时，这些构造函数要用在不同的场合下。比如，在产品代码中，我们需要的可能是一个完整的对象，而在测试代码中，针对要测试的内容，我们只要设置几个字段即可。</p>
<p>但是，因为它们都是构造函数，名字完全一致，其最初的意图无法体现，后来的人看到这样的函数，图省事，便拿过来用。随后一些初始化不完整的对象就出现在系统中。随着系统的不断演进，残缺的对象在很多情况下就会出问题，于是，为了修补，我们再向代码里添加一些setter。与setter相伴的往往是，可变（mutable）对象的出现。而许多系统的状态不稳定就是由各种可变对象造成（这也是一个值得讨论的话题）。貌似很简单的构造函数蕴含着诸多的问题。</p>
<p>就这个问题而言，可以怎样解决呢？</p>
<p>一种常见的解决方案是，类只提供一个完整的构造函数，至于其它部分，则采用工厂方法完成。比如上面的例子，对Image类，我们只有一个构造函数：</p>
<p>&nbsp; public Image(URL url, Tag tag) {<br />&nbsp; &nbsp; this.url = url;<br />&nbsp; &nbsp; this.tag = tag;<br />&nbsp; }</p>
<p>如果在测试里用到，就为它创建一个工厂方法：</p>
<p>&nbsp; class ImageForTestFactory {<br />&nbsp; &nbsp; public static Image createImageWithURL(URL url) {<br />&nbsp; &nbsp; &nbsp; return new Image(url, null);<br />&nbsp; &nbsp; }<br />&nbsp; }</p>
<p>Image的第二个参数Tag，这里就简单的设置为null，事实上，我们可以根据需要进行设置。比如，我们需要所有的字段都不能为空，这里就可以提供一个缺省的Tag。这段代码的使用者根本无需顾及Tag究竟是怎样。</p>
<p>工厂方法很大的一个价值，便在于它提供了名字，表明意图。名字到底有多大价值，如果你对整洁代码（Clean Code）有所追求，便就会发现，关于整洁代码的讨论，第一个要讨论的东西便是命名。</p>
<p>事实上，这些做法并不如何特殊，<a href="http://book.douban.com/subject/3360807/" target="_blank">《Effective Java》第二版</a>，开篇讨论的就是这样的问题。条款1就是&ldquo;考虑以静态工厂方法代替构造函数&rdquo;。这个条款里面建议的方案更加激进，建议将构造函数设置为private。这样一来，人们就完全没有机会使用该类的构造函数，只能通过其提供的工厂方法构造对象：</p>
<p>&nbsp; class Image {<br />&nbsp; &nbsp; private Image(URL url, Tag tag) {<br />&nbsp; &nbsp; &nbsp; this.url = url;<br />&nbsp; &nbsp; &nbsp; this.tag = tag;<br />&nbsp; &nbsp; }</p>
<p>&nbsp; &nbsp; public static Image createNewImage(URL url, Tag tag) {<br />&nbsp; &nbsp; &nbsp; return new Image(url, null);<br />&nbsp; &nbsp; }</p>
<p>&nbsp; &nbsp; ...<br />&nbsp; }</p>
<p>另外一种值得考虑的做法是，采用builder模式。《Effective Java》第二版的条款2给出了更详细的解释。所以，<strong>如果类里有多于一个的构造函数，那么请考虑其它方式代替。</strong></p>
<p><strong>无构造函数的Go</strong></p>
<p>顺着这个思路，再进一步，我们完全可以写出&ldquo;除本类之外，没有new本类对象的代码&rdquo;。换句话说，如果不是语言层面有所限制，我们完全可以抛弃构造函数，而事实上，Go语言就这么做了。</p>
<p>在Go语言里，如果我们要构造一个对象可以这么做：</p>
<p>&nbsp; type Person struct {<br />&nbsp; &nbsp; name string<br />&nbsp; }</p>
<p>&nbsp; func NewPerson(name string)(*Person) {<br />&nbsp; &nbsp; p := new(Person)<br />&nbsp; &nbsp; p.name = name<br />&nbsp; &nbsp; return p<br />&nbsp; }</p>
<p>在语法上，Go语言本身并没有类，但从C/C++的年代我们就知道，struct和class本质是一样的。所以，实际上，NewPerson就是一个构造函数，它负责初始化了Person的相关字段。构造一个对象的方法就可以这样：</p>
<p>&nbsp; p := NewPerson("dreamhead")</p>
<p>从本质上说，NewPerson就是一个工厂方法。当然，Go语言之所以可以这么做，因为其struct的所有字段都是public，可以自由访问，在面向对象程序设计语言中，恐怕没那么简单。或许，抛开构造函数的做法，让我们一下子回归到了最初的年代，但同之前模糊的印象不同，如今我们对构造的概念有了全新的理解。我们依然要构造对象，只是不再依赖于构造函数而已。</p>
<p>是时候反思一下构造函数了。C++设计于80年代，那时候，设计模式还不是主流，那时候，编写代码更多强调的是功能，而非整洁。</p><!--sp-->]]></description>
   <link>http://dreamhead.blogbus.com/logs/207936339.html</link>
   <author>dreamhead</author>
   <pubDate>Mon, 23 Apr 2012 13:23:00 +0800</pubDate>
  </item>
  <item>
   <title>从Go看，语言设计（二）</title>
   <description><![CDATA[<p>书接上文，继续从Go看语言设计。</p>
<p><strong>并发编程</strong></p>
<p>从多核CPU进入人们的生活，并发编程就成为编程中的新热点。在许多语言里，并发是由库提供的，而对于Go语言，并发则是语言的一部分。曾经，一说到并发编程，就会让人想到多线程/多进程、共享内存等等。Erlang改变了许多人关于并发编程的认识，基于消息的通信模式如今已逐渐成为新的标配，Go语言选择的也是这种模式。</p>
<p>首先是启动并发的方式：一个简单的函数，go一下就可以了：</p>
<p><span style="white-space: pre;">	</span>go Handle();</p>
<p>接下来是消息通信：</p>
<p><span style="white-space: pre;">	</span>ch := make(chan int)<br /><span style="white-space: pre;">	</span>go func() {<br /><span style="white-space: pre;">		</span>ch &lt;- 0<br /><span style="white-space: pre;">	</span>}()</p>
<p><span style="white-space: pre;">	</span>fmt.Println(&lt;-ch)</p>
<p>这里创建了一个通信通道（make(chan int)），有了这个通道，通信的双方就可以彼此发消息。</p>
<p><strong>不显式声明的接口与实现之间的关系</strong></p>
<p>或许是我少见多怪，Go语言是我接触到的第一个无需显式声明接口和实现二者关系的强类型语言。比如，定义这样一个接口：</p>
<p><span style="white-space: pre;">	</span>type Runnable interface {<br /><span style="white-space: pre;">		</span>Run()<br /><span style="white-space: pre;">	</span>}</p>
<p>然后，是一个使用了这个接口的函数</p>
<p><span style="white-space: pre;">	</span>func RunTo(r Runnable, place string) {<br /><span style="white-space: pre;">		</span>r.Run()<br /><span style="white-space: pre;">		</span>fmt.Println("Get to " + place)<br /><span style="white-space: pre;">	</span>}</p>
<p>之后，再来定义一个类型：</p>
<p><span style="white-space: pre;">	</span>type Person struct {<br /><span style="white-space: pre;">		</span>name string<br /><span style="white-space: pre;">	</span>}</p>
<p>这个类型也有一个Run函数：</p>
<p><span style="white-space: pre;">	</span>func (p *Person) Run() {<br /><span style="white-space: pre;">		</span>fmt.Println(p.name + " is running")<br /><span style="white-space: pre;">	</span>}</p>
<p>从代码层面上，Runnable和Person并没有直接的关系，唯一的关系就是二者都有Run函数。即便如此，我们依然可以把Person当做Runnable来使用：</p>
<p><span style="white-space: pre;">	</span>p := new(Person)<br /><span style="white-space: pre;">	</span>p.name = "dreamhead"<br /><span style="white-space: pre;">	</span>RunTo(p, "Xi'an")</p>
<p>只要实现者拥有接口定义的方法，就可以当做这个接口来用。如果熟悉Ruby这样的动态类型语言，你会发现这种说法几乎同<a href="http://en.wikipedia.org/wiki/Duck_typing" target="_blank">Duck Typing</a>如出一辙，只不过，在Ruby里没有&ldquo;接口&rdquo;而已。</p>
<p>从实现的角度，这个问题并不难理解，所有这一切都是编译器替我们完成的。如同类型推演一样，编译器让我们不必将重复概念反复来说，同时还保证了，不会有&ldquo;上错花轿&rdquo;的情况出现。</p>
<p><strong>小结</strong></p>
<p>Anders Hejlsberg总结了程序设计语言发展的<a href="http://v.youku.com/v_show/id_XMTk1ODM2NTA4.html" target="_blank">三大趋势</a>：声明式、动态性和并发。</p>
<p>声明式，包括函数式编程和DSL。函数式编程自不必说，DSL实际上事关表达性，Go简化代码编写的方式就是在这个方向迈出的步伐。动态性，并不仅仅是动态语言，动态语言与静态语言之间的互相汲取营养，类型推演与不显式声明接口和实现关系，便是向着这个方向迈进。至于并发，无需多提。</p>
<p>总的说来，Go语言的语言设计本身是符合现代程序设计语言发展趋势的。</p><!--sp-->]]></description>
   <link>http://dreamhead.blogbus.com/logs/204841467.html</link>
   <author>dreamhead</author>
   <pubDate>Wed, 11 Apr 2012 22:38:00 +0800</pubDate>
  </item>
  <item>
   <title>从Go看，语言设计（一）</title>
   <description><![CDATA[<p><a href="http://golang.org/" target="_blank">Go语言</a>发了正式版，终于像一个正经的东西了，不再需要每次从版本控制里面拿代码编译了。拿来把玩一番，看到了一些有趣的东西，记录一下。</p>
<p>作为一门现代程序设计语言，Go语言从语言设计上反应出现代程序设计语言一些重要变化。</p>
<p><strong>函数成为第一类对象</strong></p>
<p>函数式编程已经无可阻挡地成为程序设计语言发展的重要趋势，只要是还在演进之中的程序设计语言，函数式编程都已经成为其重要的一部分，即便是Java这个笨重的大象，也会在Java 8中引入lambda。函数式编程的第一步，就是让函数成为第一类对象，也就是可以把函数作为参数和返回值传递。然后，才会有高阶函数，以及后面的一系列变化。</p>
<p>下面是一个简单的Map实现：</p>
<p><span style="white-space: pre;">	</span>func Map(elements []int, f func(int)(int)) (results []int) {<br /><span style="white-space: pre;">		</span>results = make([]int, len(elements))<br /><span style="white-space: pre;">		</span>for i, element := range elements {<br /><span style="white-space: pre;">			</span>results[i] = f(element)<br /><span style="white-space: pre;">		</span>}<br /><span style="white-space: pre;">		</span>return<br /><span style="white-space: pre;">	</span>}</p>
<p>调用起来也很简单：</p>
<p><span style="white-space: pre;">	</span>result := Map(elements, func(element int) int {<br /><span style="white-space: pre;">		</span>return element + 1<br /><span style="white-space: pre;">	</span>})</p>
<p>稍微多说几句，在<a href="http://www.thoughtworks.com/articles/technology-radar-march-2012" target="_blank">新一期的ThoughtWorks技术雷达</a>上，函数式Java跃然纸上。我对这个问题的理解是，并不仅仅是要有函数式的语言构造，更应该是将函数式编程的一些理念引入到日常的开发中，比如引用透明性，无状态函数等等，这是个有趣的话题。</p>
<p><strong>简化代码编写</strong></p>
<p>程序员每天要写很多代码，设计一门程序设计语言，除了要考虑各种各样的语言特性之外，很重要的一点就是，就是让写代码更容易。类型推演和内置数据结构就是在这个方向上的努力，Go语言就提供了这两方面的支持。看看下面这段代码，典型的Java啰嗦代码：</p>
<p><span style="white-space: pre;">	</span>List lists = new ArrayList();<br /><span style="white-space: pre;">	</span>lists.add(0);<br /><span style="white-space: pre;">	</span>lists.add(1);<br /><span style="white-space: pre;">	</span>lists.add(2);</p>
<ul>
<li>类型推演</li>
</ul>
<p>动态类型语言很令人羡慕的一点就是，他们的变量不用反反复复地写类型。它们也有让人鄙视的地方，没有类型的变量无法做静态检查，许多错误只能在运行阶段暴露。类型推演给予我们一个鱼与熊掌兼得的机会：既能从繁琐的类型声明中解脱出来，又能拜静态类型所赐，在编译期就可以做很多检查，减小犯错的几率。</p>
<p>例子：</p>
<p>&nbsp; &nbsp; car := new(Car)</p>
<ul>
<li>基本数据结构已不可或缺</li>
</ul>
<p>从语言设计的角度来讲，基本数据结构并不是语言的一部分。但从程序员的角度来说，基本数据结构的缺失会让代码显得无比啰嗦，这是对追求整洁代码之人的折磨。所以，有了人写了<a href="http://code.google.com/p/guava-libraries/" target="_blank">Guava</a>这样的库，解救水深火热的Java人，下面是前面那段代码的Guava版本：</p>
<p><span style="white-space: pre;">	</span>List lists = newArrayList(0, 1, 2);</p>
<p>Go语言内置了一些数据类型的支持，让代码编写稍微简化了一些，不过，相比于很多语言，它还不够简洁。</p>
<p>有了类型推演和基本数据结构，前面那段啰嗦的代码在Go中就是这个样子了：</p>
<p>&nbsp; &nbsp; elements := []int{1, 2, 3}</p><!--sp-->]]></description>
   <link>http://dreamhead.blogbus.com/logs/204670245.html</link>
   <author>dreamhead</author>
   <pubDate>Tue, 10 Apr 2012 12:23:00 +0800</pubDate>
  </item>
  <item>
   <title>五百杂谈</title>
   <description><![CDATA[<p>查了一下自己的blog，我已经写了499篇，换句话说，这是第500篇，吓了自己一跳。<a href="http://dreamhead.blogbus.com/logs/196187672.html#cmt" target="_blank">一个朋友问</a>，真的好奇你怎么坚持写了这么久？我回答，其实，只要坚持就好了，成了习惯，也就没什么难的了。</p>
<p>这篇没想好什么特定的主题，就把脑子里的东西倒一下，所谓&ldquo;杂谈&rdquo;，算是一些分享吧！</p>
<p>先说编辑器吧！以前说起Mac下的编辑器，随着Rails兴起的<a href="http://macromates.com/" target="_blank">TextMate</a>堪称神器，但其不思进取的程度是令人发指的。用它写中文，是多少年的痛，即便我用上所谓的字体，也刚刚达到能显示但很糟糕的效果。在可用性为王的苹果世界里，这是不可接受的。在地老天荒之前，TextMate 2终于抛出了<a href="http://blog.macromates.com/2011/textmate-2-0-alpha/" target="_blank">Alpha版本</a>。可惜这时，我已经移情别恋了。</p>
<p>它叫<a href="http://www.sublimetext.com" target="_blank">Sublime Text</a>。快速发展的它，已经到了<a href="http://sublimetext.com/2" target="_blank">2</a>，而且是Beta。它是跨平台的，也就是说，在Windows和Linux上也能用，只是不见得有Mac平台下那么好看。这篇blog就是在Sublime Text 2里写的，因为它的中文显示很好，仅凭这一点它就具备了成为我日常编辑器的基础。喜欢Sublime Text，还有一个很重要的原因，就是它支持VI模式。换句话说，当我按下Esc，我就可以使用VI的操作命令了。有人说，那直接用VI好了，可能是因为我懒的缘故，迄今为止，我只熟悉常用的VI操作命令，对于VI配置一窍不通，没有配置过的VI，还算不上神器。</p>
<p>说到VI，有同事给我推荐了针对mac用户的<a href="https://github.com/carlhuda/janus" target="_blank">janus</a>，这是一个已经配置好的VI版本。如果早点知道，也许就下功夫练练，掌握好VI了。</p>
<p>再来聊聊雷达，ThoughtWorks刚刚发布了新一期的<a href="http://www.thoughtworks.com/articles/technology-radar-march-2012" target="_blank">技术雷达</a>。其中有一项是，构建自己的雷达。我在微博上<a href="http://weibo.com/2192241300/yadkJk7fv" target="_blank">评论</a>道：每个团队都应该有一个自己的雷达，可以根据需要选择自己的维度，比如，技术、业务、部署、工具等等。这样，每个团队成员都可以对比雷达图，弥补知识欠缺，新人也可以迅速对项目整体情况有个认识。</p>
<p>其实，这里面包含了两层意思。一个团队要建立雷达，还要将其中内容根据优先级进行排序。这样，新加入者才能更很好的学习，之所以对这个东西有感慨，因为这些东西正是我们正在自己和客户项目上实践的东西。</p>
<p>最近在做的一件事，在Windows上交叉编译程序，放到Linux上跑，不同的是，这次用到了虚拟机，用到了<a href="http://www.vagrantup.com/" target="_blank">Vagrant</a>。还没等我写Hello Vagrant，我的同事<a href="http://mingjin.thoughtworkers.org/" target="_blank">金明</a>就写好了（<a href="http://mingjin.thoughtworkers.org/?p=155" target="_blank">一</a>、<a href="http://mingjin.thoughtworkers.org/?p=170" target="_blank">二</a>），如果你有兴趣了解Vagrant，可以参考。</p>
<p>随着对Vagrant了解的增加，我越发觉得这东西不错，虽然它现在只是针对<a href="https://www.virtualbox.org/" target="_blank">Virtual Box</a>的，但已经<a href="https://github.com/lynaghk/vagrant-ec2" target="_blank">有人尝试把它与EC2统一起来</a>。说白了，无论是虚拟机还是云，都是为了虚拟化，Vagrant可以成为统一的入口。</p>
<p>新读了《<a href="http://book.douban.com/subject/6885274/" target="_blank">乔布斯的魔力演讲</a>》，它告诉我一次只能说三件事，说到了，就结束这第500篇吧！</p><!--sp-->]]></description>
   <link>http://dreamhead.blogbus.com/logs/200048627.html</link>
   <author>dreamhead</author>
   <pubDate>Wed, 21 Mar 2012 21:57:00 +0800</pubDate>
  </item>
  <item>
   <title>ThoughtWorks校园行，第一步</title>
   <description><![CDATA[<p>就在昨天晚上，西安电子科技大学，ThoughtWorks校园行，迈出了第一步。</p>
<p>2009年校园招聘，终于完成了招聘的各个环节，放松下来的几个人，闲散在校园中散步。我突发奇想，为什么不能给招来的学生在入职前做一些培训，因为我们开发中的很多东西，对学生来说，只是不知道而已，与其在加入公司后紧张的学习，不如在加入之前就了解这些东西，减缓一下入门门槛。</p>
<p>在ThoughtWorks工作的一个好处就是，你有什么想法，就会得到别人的鼓励。于是，就有每年一次的毕业生入职前培训。因为我的主意和在其中的付出，这个培训有了一个属于我的名字&mdash;&mdash;郑大晔校。</p>
<p>转眼，第三批接受培训的人也已经开始入职了，在这个过程中，我们也积累了一些与学生们打交道的经验。ThoughtWorks作为一家有社会责任感的公司，既然可以帮助与自己签约的学生，为什么不能帮助那些在学校里的学生。于是，ThoughtWorks校园行提上了日程，我们的想法很简单，告诉学生们，怎样做好软件。</p>
<p>经过多方接触和积极筹备，校园行终于在西电迈出了第一步。</p>
<p>《公司是如何做软件的》，这是我们校园行的第一讲。这是我们精心选择的话题，对于大多数在校生而言，公司里如何做软件一直是一个神秘的事情，无论是拓展视野，还是未来的就业，这都是他们希望了解的。而站在我们的角度，学生们更多的是在&ldquo;写程序&rdquo;，而不是&ldquo;做软件&rdquo;。在公司里，做软件，要考虑的方面，远要比写一个程序多得多。在这个话题里，我们还与同学们分享了如何从一个学生成为一个好的程序员。</p>
<p>这次活动的主讲人就是郑大晔校的第一批毕业生，<a href="http://www.cnblogs.com/cuiliqiang/" target="_blank">崔力强</a>。在别的公司，同年毕业的还在跟着老员工后面学习时，他们这批人已经成了我们各个项目组的主力，而小崔是其中佼佼者。当然，选择他作为主讲人，还因为西电是他的母校。</p>
<p>这个在我们看来宣传做得很一般的活动，居然来了很多人，大大出乎了我们的意料。在演讲过程中，我看到了很多渴望知识的双眼，许多人非常认真的做着笔记，这让我相信，我们提供的内容对他们来说是有价值的。在后续的问答环节里，我之前的担心是没有足够的问题，但事实证明，这完全是多余的，同学们抛出了很多的问题。</p>
<p>现在坐下来，在脑子里重温昨天的场景，我相信，把&ldquo;如何做软件&rdquo;送到学校里是一个正确的选择。这次活动对我们而言，更多的意义在于试水，它让我们有勇气把后续的活动提上日程。我们还有很多好东西，比如乐高游戏，Coding Kata，OO训练营等等，希望在未来的日子里，这些内容都会出现在我们的校园行里。</p>
<p>ThoughtWorks校园行，西电只是第一站。在西安，我们已经开始联系其它的高校。成都的校园行，也在积极筹备之中。如果你在校园，如果你是老师，或是学生，希望我们走进你们的学校，欢迎与我们联系。</p>
<p>我们愿意为改变一些东西，尽一些绵薄之力。</p><!--sp-->]]></description>
   <link>http://dreamhead.blogbus.com/logs/198429607.html</link>
   <author>dreamhead</author>
   <pubDate>Tue, 13 Mar 2012 23:08:00 +0800</pubDate>
  </item>
  <item>
   <title>读《黑客：计算机革命的英雄》</title>
   <description><![CDATA[<p><a style="margin:5px;float:left;" href="http://book.douban.com/subject/6860890/" target="_blank"><img style="border:none;" src="http://img1.douban.com/mpic/s6951030.jpg" alt="" /></a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>多年前，<a href="http://dreamhead.blogbus.com/logs/149825.html" target="_blank">我读过《DOOM启世录》</a>，那是一个英雄传奇，看得我热血沸腾。那本书曾提及，有一本书让John Carmack产生了极大的共鸣，给予了它在这个领域前行的动力。Carmack的启示录是《黑客：计算机革命的英雄》(Hackers: Heroes of the Computer Revolution)。</p>
<p>我一直很好奇这是一本怎样的书，不过，作为Carmack的启示录，一本1984年撰写的书，在这个技术日新月异的领域，指望重新读到这本&ldquo;古代&rdquo;著作似乎不是一件很容易的事。</p>
<p>当我在网上书店里看到这本书时，我简直不敢相信自己的眼睛。还有什么好说的，下订单。</p>
<p>终于读完了这本书，我也终于可以理解为什么John Carmack的激动了，那是一部波澜壮阔的黑客史，那是一群发自内心喜欢计算机的人，对技术最简单、最纯粹的热爱，那是一种超凡的魅力。如果真心热爱计算机，你会发现，其实你并不孤单。</p>
<p>我们可以看到五六十年代，一群黑客乐此不疲地探索着初生计算机的威力，也可以看到七十年代，一群硬件黑客努力把神秘的大家伙开始走进寻常百姓家，还有八十年代初，游戏黑客们推动了计算机的普及。</p>
<p>这本书里出现了&ldquo;家酿计算机俱乐部&rdquo;的名字，如果你读过《<a href="http://book.douban.com/subject/6798611/" target="_blank">乔布斯传</a>》，或是了解过苹果公司的历史，这个名字不应该让你感到陌生。是的，苹果公司正是从这里起步的。史蒂夫&middot;沃兹尼亚克（简称沃兹），就是通过这个俱乐部分享的一些信息打造出了Apple I，后来，才是史蒂夫&middot;乔布斯和他通过这台电脑起步，开创苹果神话。在这本书里，有一个专门属于沃兹的章节，由此可见，沃兹在黑客历史中所起的重要作用。</p>
<p>这里还有出现了许多如今看来响当当的名字，比如比尔&middot;盖茨，他的那封公开信，并不像后人描述的那样，在软件历史上是浓墨重彩的一笔，更多的还是年少盖茨的处事不够圆润。比如理查德&middot;斯托曼，他称自己为最后一个黑客，他的个人能力在书中得到了极高的评价，一个人可以顶上十几个一流黑客。所谓最后一个黑客，更多的是对纯真年代的一种追思。</p>
<p>作为《Wired》杂志的资深作者，Steven Levy的写作功力是相当深厚的，在他的黑客世界里，每个人都是那么有血有肉。其实，对于一个中译本来说，巨大的挑战在于翻译，感谢这本书的几位译者，在我看来，这本书算是翻译得相当流畅，少有因为语言的原因造成阅读的障碍。</p>
<p>工作很多年，我经常面对的是一张张无辜的面孔，他们努力在软件焦油坑中挣扎。他们中的很多人选择计算机作为自己的职业，并非因为他们多么热爱计算机，而是因为他们要找一份养家糊口的工作。周边的环境告诉他们，只要低着头写代码就好了。他们根本不知道，原来计算机也可以很有趣。常常与这样的人打交道，</p>
<p>久而久之，我都几乎忘记了自己最初选择写程序为职业的初衷：乐趣。感谢《黑客：计算机革命的英雄》，它帮助我重新找回了写程序之初的追求：探求事物本质的乐趣。</p><!--sp-->]]></description>
   <link>http://dreamhead.blogbus.com/logs/196187672.html</link>
   <author>dreamhead</author>
   <pubDate>Sun, 04 Mar 2012 23:43:00 +0800</pubDate>
  </item>
  <item>
   <title>在Lion上安装ruby</title>
   <description><![CDATA[<p><strong>简略版</strong></p>
<ul>
<li>通过App Store安装Xcode。安装完毕后，运行Xcode，进行真正的&ldquo;安装&rdquo;。</li>
<li>打开Xcode，Preferences-&gt;Downloads-&gt;Components，安装Command Line Tools。</li>
<li>安装RVM后，运行rvm install 1.9.3 --with-gcc=clang</li>
</ul>
<p><strong>完整探索版</strong></p>
<p>因为想看看iBooks Author长什么样，从雪豹升级到了狮子。按许多同事的说法，这是一个无痛升级的过程，我信以为真，至少在升级初期，使用应用的时候，确实没有遇到什么问题。。</p>
<p>直到我安装一个gem包，我才发现，对于开发者来说，没那么简单。要装的这个gem需要libxml2的支撑，补装libxml2库，在构建过程中发现，gcc没了。</p>
<p>我知道Xcode里面有gcc，而且升级前，我是装过Xcode 3的。按照网上的提示，我在/Developer/usr/bin目录下找到了gcc的命令。或许是因为升级的缘故，原本在/usr/bin下的链接被取消了。兴高采烈的把它加到PATH里，这下gcc是能找到了，但继续安装，居然还是出错：</p>
<p>&nbsp; error: C compiler cannot create executables</p>
<p>又经过几番纠结的搜索，我才意识到一个问题。Lion上支持的Xcode要在4以上，而我从前的版本是3。于是通过App Store安装Xcode的最新版本，这是一个漫长的过程，一个字，大。顺便说一下，为了干净，我删除了Xcode 3，使用下面的命令：</p>
<p>&nbsp; sudo /Developer/Library/uninstall-devtools --mode=all</p>
<p>安装好后，我发现我可以在Xcode里面编译代码，却找不到命令行。于是，又一次投入搜索的怀抱，我才知道，原来在Xcode 4.3里，命令行是要额外安装的。打开Xcode，通过Preferences-&gt;Downloads-&gt;Components，安装Command Line Tools。</p>
<p>有了gcc，直接运行rvm install 1.8.7。又遇到问题：</p>
<p>&nbsp; The provided compiler '/usr/bin/gcc' is LLVM based, it is not yet fully supported by ruby and gems</p>
<p>在Lion里，苹果把缺省的编译器替换成了LLVM的实现。通过下面的命令，我们便不难发现这一点：</p>
<p>&nbsp; ls -l `which gcc`</p>
<p>如果你还不知道LLVM，那<a href="http://www.programmer.com.cn/9436/" target="_blank">这篇文章</a>不容错过，顺便说一下，<a href="http://www.douban.com/group/topic/23658084/" target="_blank">这个系列</a>的文章都很好看。</p>
<p>经过继续努力，我才知道在Lion上用RVM安装ruby需要告诉它，我要用LLVM的编译器：</p>
<p>&nbsp; rvm install 1.8.7 --with-gcc=clang</p>
<p>好，这段命令是起作用的，但是在安装过程中，我们会看到下面的提示：</p>
<p>&nbsp; Ruby 'ruby-1.8.7-p358' was build using clang - but it's not (fully) supported, expect errors.</p>
<p>这句话告诉我们，这个ruby能用，但不保证没错。多么不负责任的提示啊！在RVM里，我找到了这个问题的答案，在$HOME/.rvm/scripts/functions/manage/ruby里，出现这段提示前有一个判断：</p>
<p>&nbsp; __clang_ready &amp;&amp; __rvm_compiler_is_llvm</p>
<p>同样在这个文件里，可以找到__clang_ready的实现，简而言之，只有1.9.3-p125以上的版本才是完全支持clang的。于是，我这么做，才得到一个万事大吉的ruby：</p>
<p>&nbsp; rvm install 1.9.3 --with-gcc=clang</p>
<p>通过如此纠结的一次安装经历，我越发觉得，<a href="https://github.com/dreamhead/1step" target="_blank">1step</a>是对的，把时间花在这些东西上，实在是浪费生命。</p><!--sp-->]]></description>
   <link>http://dreamhead.blogbus.com/logs/194495277.html</link>
   <author>dreamhead</author>
   <pubDate>Sat, 25 Feb 2012 11:01:00 +0800</pubDate>
  </item>
 </channel>
</rss>

