星巴克从事的是兜售梦想的工作,而不是卖咖啡。它将梦想兜售给那些渴望在工作和家庭之外找到“第三空间”的人,它将梦想兜售给那些渴望享有尊严和拥有体面工作的人。卖咖啡不是星巴克的事业,这就是它成功的原因。游戏不是Cranium的事业,它的事业是兜售自尊。计算机不是苹果的事业,它的事业是放飞你的创造力。将产品与梦想区分开来是创造出改变世界的革命性产品和服务的根本。
posted @ 2011-06-29 16:09 申健 阅读(25) 评论(0) 编辑

@echo off

setAddStr=\Device\NdisWanIp\0

for /f "tokens=3 " %%i in ('reg query HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Linkage ^| find "Bind"') do set BindStr=%%i

set finalStr=%AddStr%%BindStr%


reg delete HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Linkage /v Bind /f

reg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Linkage /v Bind /t REG_MULTI_SZ /d %finalStr:~0,-2%

posted @ 2011-05-30 15:48 申健 阅读(191) 评论(0) 编辑

The Agile development community has struggled for years with an array of solutions for automated testing solutions for web development.  NUnitASP is a good way to unit test server side ASP.Net code, especially now that it doesn’t require XHTML compliant pages, but it can’t handle client side scripting and AJAX is exploding in popularity.  Several tools have used COM (must die) to drive Internet Explorer (IE) with varying degrees of success.  My personal experience is that the IE COM API is too byzantine and flat out flaky.  Besides the flakiness, Firefox and other browsers are gaining in popularity so the IE only testing might not cut it anymore.

Enter the Selenium project.  The developers of Selenium had the brilliant, but in retrospect painfully obvious, idea to use Javascript inside a browser to drive the web testing.  Presto, automated testing for web applications that can test client side Javascript and multiple browser engines.  In its original incarnation Selenium ran FIT style test tables inside a web browser.  Recently, Selenium Remote Control has been released to that allow the core Javascript engine to be driven through API’s for .Net, Java, Ruby, or Python.  The FIT style table runner is perfectly functional, but for us it’s very convenient to use the Selenium RC .Net wrapper.  So far I’m pleasantly surprised by how easy it is to use the .Net wrapper.  

Sample Test

The API libraries communicate with the Selenium Server, a Java executable that can start and stop any supported browser and send testing commands to the browser.  The .Net callable wrapper works by sending HTTP messages to the Selenium Server that controls a browser.  The first step is to start up the Selenium Server from a command prompt.

java -jar server\selenium-server.jar -interactive

The next step was to create a simple HTML page with a textbox that changes values when a button is clicked:

<html>
<head>
<script language=javascript src=prototype-1.4.0.js></script>
<title>Selenium Target Page</title>
<script id=clientEventHandlersJS language=javascript>
<!--
 
function button1_onclick() {
    $('text1').value = "Goodbye"; // Using the Prototype library
}
 
//-->
</script>
</head>
<body>
 
<form name="form1">
    <input id="button1" type=button onclick="return button1_onclick()" value="click me"/>
    <input id="text1" type=text value="Hello"/>
    <select testid="select1" >
        <option value="1">North</option>
        <option value="2" selected=true>West</option>
        <option value="3">South</option>
        <option value="4">East</option>
    </select>
</form>
 
</body>
</html>

Next I wrote a little NUnit test fixture class to run tests against the web page. The key object is the DefaultSelenium class that is created in the SetUp() method:

/// <param name="serverHost">the host name on which the /// Selenium Server resides</param>
/// <param name="serverPort">the port on which the /// Selenium Server is listening</param>
/// <param name="browserString">the command string used /// to launch the browser, e.g. "*firefox", "*iexplore" /// or "c:\\program files\\internet explorer\\iexplore.exe"</param>
/// <param name="browserURL">the starting URL including /// just a domain name.  We'll start the browser pointing at /// the Selenium resources on this URL,
/// e.g. "http://www.google.com" would send the browser to /// "http://www.google.com/selenium-server/SeleneseRunner.html"</param>
public DefaultSelenium(String serverHost, int serverPort,        String browserString, String browserURL)
{
  this.commandProcessor = new HttpCommandProcessor(serverHost,       serverPort, browserString, browserURL);
}
using System;
using NUnit.Framework;
using Selenium;
 
namespace SeleniumTarget
{
    [TestFixture]
    public class WebPageTester
    {
        DefaultSelenium selenium;
 
        [SetUp]
        public void SetUp()
        {
            // 4444 is the default port for the Selenium Server
            selenium = new DefaultSelenium("localhost", 4444, "*iexplore", "http://localhost");
            selenium.Start();
        }
 
        [TearDown]
        public void TearDown()
        {
            // Make sure the Selenium environment is cleaned up after each test
            selenium.Stop();
        }
 
 
        [Test]
        public void CheckTheTitle()
        {
            selenium.Open("http://localhost/SeleniumTarget/TestPage1.htm");
 
            Assert.AreEqual("Selenium Target Page",
                            selenium.GetTitle(),
                            "Check the title of the browser");
        }
 
 
        [Test]
        public void ClickButton1ChangesText1FromHelloToGoodbye()
        {
            selenium.Open("http://localhost/SeleniumTarget/TestPage1.htm");
            Assert.AreEqual("Hello",
                            selenium.GetValue("text1"),
                            "Initial Value");
 
            selenium.Click("button1");
 
            Assert.AreEqual("Goodbye",
                            selenium.GetValue("text1"),
                            "Value after clicking button1");
        }
 
        /// <summary>
        /// Check that the options of a <select></select> element are
        /// as expected.  Finds the <select> element by using an xpath expression
        /// </summary>
        [Test]
        public void Select1Values()
        {
            selenium.Open("http://localhost/SeleniumTarget/TestPage1.htm");
            string locator = "xpath=//select[@testid='select1']";
 
            string[] options = selenium.GetSelectOptions(locator);
 
            Assert.AreEqual(new string[] {"North", "West", "South", "East"},
                            options,
                            "Values in the select1 dropdown");
        }
    }
}

It’s a trivial example, but it’s a start. 

What I don’t know –

  • What’s the best way to handle the Selenium Server process?  How do you guarantee it’s up when you start your tests?  I’m thinking some kind of Windows service wrapper
  • How do you integrate Selenium with CruiseControl.Net to get it into your Continuous Integration strategy?  I can’t find much on the web about this yet.  You can run Selenium from NUnit for developer testing, but that isn’t a very desirable answer from a tester’s perspective.  For a couple of reasons, our thinking is to wrap the Selenium manipulation inside a FitNesse DoFixture.  We already know how to integrate FitNesse tests within a CC.Net build and it’s convenient to run all the tests together.  We’re also hoping that the DoFixture tests will be easier to understand and that we can hide some of the web page details behind the fixture.

Other Tools

We’re looking primarily at Selenium, but we’re also considering WATIR (Ruby based tool) and Sahi (I don’t know much about it, but it looks strong).  One of our colleagues is experimenting with a Ruby based DSL for testing another web product using WATIR as the core that looks promising.  I’ve also been playing with the Ruby driver for Selenium with an eye towards creating a testing DSL for our application.   

posted @ 2011-05-29 10:57 申健 阅读(60) 评论(0) 编辑

http://www.robertkan.net/blog/2009/05/15/failed-to-load-module-for-fs-type-bdb-in-tortoisesvn-16x

 

Today I’ve met small problem with my beloved TortoiseSVN client. I was in need to access some old repository stored locally on my computer – for newer projects I’m usingdedicated Debian based SVN server. Anyway, trying to access to my local repository via TortoiseSVN has resulted with following message:

Failed to load module for FS type 'bdb'

After quick Googling it appeared that from branch 1.6.x, TortoiseSVN doesn’t support local file:/// repositories based on BDB and they need to be converted to new FSFS format using ‘svnadmin’ command line tool as it is explained inSVNBook. As ‘svnadmin’ tool is not present in TortoiseSVN, some additional work is needed.

Finally I did in following way:

  1. download and  Tigris build of SVN (it was svn-win32-1.6.1.zip in my case). I’ve tried both 1.5.x and 1.6.x version of CollabNet’s SVN but apparently they do not support local BDB as well,
  2. unpack it to any directory, and using command line enter to the bin subdirectory where the svnadmin.exe tool is stored
  3. as written in the book, make dump of your repository with following command:
  4. svnadmin dump c:\FullPathToOldRepository > dumpfile.bin
  5. create new repository in choosen directory, you can use TorotoiseSVN for it as well, now it won’t ask you for data storage format as BDB is disabled, so it will use FSFS.
  6. import dump data into new repository:
  7. svnadmin load c:\FullPathToNewRepository < dumpfile.bin

That is, it worked for me like a charm.

posted @ 2011-04-28 13:19 申健 阅读(95) 评论(0) 编辑

DevOps,不是一个传说!

作者 乔梁 发布于 2011年4月19日 上午12时0分

   

DevOps最近成了热词,望文生义,你也能猜个八九不离十,它就是在说"研发团队"与"运维团队"之间的那点事儿。那么,到底什么是"DevOps"呢?

WikiPedia上说:"DevOps是软件开发、运维和质量保证三个部门之间的沟通、协作和集成所采用的流程、方法和体系的一个集合。它是人们 为了及时生产软件产品或服务,以满足某个业务目标,对开发与运维之间相互依存关系的一种新的理解。"这恰好体现了精益管理中的客户价值原则,即:以客户的 观点来确定企业从设计到生产交付的全部过程,实现客户需求的最大满足。我们也可以把DevOps看作是一种能力,在缺乏这种能力的组织中,开发与运维之间 存在着信息"鸿沟"。

如何获得这种能力呢?关键有两点:一是全局观:要从软件交付的全局出发,加强各角色之前的合作;二是自动化:人机交互就意味着手工操作,应选择那些 支持脚本化、无需人机交互界面的强大管理工具,比如各种受版本控制的script,以及类似于Nagios这样的基础设施监控工具,类似于Puppet、 Chef这样的基础设施配置管理工具。

有 人评论说:"针对目前国内情况,DevOps还是很遥远。也许只有行业顶尖的公司,或者新成立的公司会有这样的尝试。大多数的企业还未开始进行敏捷的推 进,传统的重重阻碍会使敏捷的推进进程遥遥无期。" DevOps真的离我们有那么远吗?DevOps应该从哪里开始呢?

一、让数据说话

让我们看一看百度某产品线在半年内的变化吧。首先要说明两个百度术语。"提测"是指某个项目开发完成后,在正式上线前,将其提交给测试组进行测试的 活动。对于客户来说,"提测"这个动作本身并不增加什么价值,但也需要花费一定的时间。"上线"是指某个项目验证合格后,将其部署到服务器的过程,其中包 括"上线申请"和"实际部署"两个活动。也许在各公司中对这两个活动叫法不同,但在软件生命周期中,"提测"、"上线"这两件事无论花长时间,大家可能都 不会感到奇怪。下面两张图是该产品线进行改进之后的对比数据。

从图中不难看出,提测和上线部署的效率已大大提高。象百度这样的互联网企业,产品线多得数不清,几乎每个产品线每周都有新功能部署。仅从这两个数据来看,其收益可想而知。那么,半年前的状况是什么样的呢?

二、流程建模

既然DevOps关注于价值交付的全过程,那就让我们看看该产品线常见的交付过程吧。

对于单个项目来说,它大体上是一个典型的瀑布开发过程。首先是需求收集与整理,撰写MRD(Marketing Requirement Document)或总体设计后,进行评审。如果涉及到多模块,每个模块的开发人员会对各自负责的模块进行详细设计,给出大致的开发计划,并商定联调时间 点。之后,开发人员会从主干上拉出项目分支,并在该分支上进行开发。当到最后联调点时,几个开发人员才会在将代码合在一起,进行联调。当调通之后,开发人 员再申请提测。测试人员接到提测申请单后,进行测试,记录Bug,通知开发人员修复,直致质量达到标准。之后,开发人员会填写上线申请单,经运维人员确认 后,运维人员操作进行上线部署工作。如图所示。

开发的复杂性还在于:该产品线有很多并行项目,为了避免互相干扰可能带来的冲突,每个项目启动后都会重新在主干上拉出分支,在上线前才进行合并。如下图所示。

另外,并行项目太多,导致每个开发人员会同时参与多个处于不同阶段的项目。那些周期较长的项目虽然会被分解成多个迭代,但每个迭代内都是同样的开发流程,只是最后仅有一次上线而已。

总而言之,突出的问题表现在:

  1. 同一角色多个人员的合作开发;
  2. 各角色部门之间的协作以各自的产品物为目标,如MRD、产品代码、测试用例、上线操作单;
  3. 基于人机交互方式的内部流程管理平台。

三、发现浪费

从精益思想出发,为了尽早交付价值,必须首先找出整个流程中的浪费,并将其消除,从而提高流程效率,让"一个想法从提出到实现"可在最短时间里完成。那么,浪费到底表现在哪里呢?

  • 一些不必要的多分支开发,合并后发生问题的风险高。多个项目中可能都要修改同一个模块的代码,每次在最后合并代码时都会出现一些问题,非常痛苦,尤其是修改比较大的时候,合并及修复时间较长。
  • 推迟问题被发现的时间。每个开发人员会将需求分解成多个技术任务后开发。所以,所有任务完成之前,应用程序一直处于不可用状态。当最后在一起联调时,常常会发现一些意想不到的问题。
  • 基于流程平台的沟通。在提测环节中,沟通完全基于内部项目管理平台和即时消息工具或Email。比如开发人员在提测前,需 要在项目管理平台上申请该项目的4位版本。拿到4位版本后,才能提交平台统一编译。如果编译失败,那么问题解决后还要再次申请4维版本。如果成功,则在项 目管理平台上填写表单,回答一系列的问题(比如,是否做过单测?测了哪些功能点?部署步骤是什么?),发起提测工作流,管理平台会自动发送电子邮件给相关 测试人员,通知他们进行测试。测试人员收到该提测工作流后,必须在平台上进行相关确认操作,通知开发人员已收到该版本。如果测试人员对部署和测试内容有疑 问的话,还会通过即时通讯工具或邮件与开发人员进行确认。
  • 常规的例行工作很难自动化。上线部署也需要通过内部平台来完成。开发人员拿到已测试通过的4位版本后,先要登录到内部平 台,再提交上线申请单,填写上线步骤。当运维人员收到上线步骤后,再将其"翻译"成平台可以识别的"半自动上线步骤",再让平台来执行。如果运维人员不理 解上线步骤,就要和开发人员通过电子邮件或即时通讯工作等进行反复确认。部署配置信息分散在各处。如下图所示:

另外,该产品的一个重要特征是需要不断地尝试调整程序算法策略,以得到最佳的流量效果,而这种调整的频率较高(至少每周一次)。当需要调整策略时, 开发人员修改代码后重新进行编译打包,由于产品代码发生变化,所以测试人员仍需要进行大量的回归测试,而运维人员在部署时也需要将对二进制文件包进行整体 部署,整个周期比较长。

从上面这些内容中,我们不难发现,流程中更倾向于将问题推迟到后面解决(比如最后集成联调),将工具(平台、邮件、即时通讯)作为协作的基础,而角 色间的沟通几乎完全依赖于前一个环节的产物(比如MRD、产品代码、上线步骤)。那么我们使用哪些对策进行优化,达到消除浪费的目的呢?

四、应对措施

1. 无人工干预方式的脚本自动化

  • 自动化提测——由于已做到了每日集成,所以每天都有可测试的版本,开发人员不再需要为提测进行专门的准备工作,只要从成功构建的列表中选择一个给测试人员就可以了。使用Hudson平台后,通过插件即可调用自动化脚本,完成提测版本的标识。
  • 统一配置信息源——将所有的配置项全部放在Subversion库中进行版本控制;并根据应用环境的不同,分别保存在Dev,Test和Online三个目录中。

  • 常规流程脚本化——经过各角色的共同讨论和可行性分析,最后配置上线部署的实施方案是:由开发人员将产品二进制包与配置项 进行剥离,这样仅做策略调整时,测试人员只要对已修改的配置项进行相关测试即可。运维人员用一系列的脚本代替了内部运维平台的手工上线操作,再通过 Hudson平台的插件,以 "Click Button"的方式达到了一键式部署。

2. 尽早发现问题,解决问题

  • "需求细分,及时开发,及时验证"——将需求拆分成端到端可测试的需求(即"用户故事"),这些需求一般可在3天内完成。在实现每个需求之前,开发人员与测试人员进行充分沟通,对需求与验收条件达成共识。每开发完成一个用户故事,就进行测试,并用自动化测试进行覆盖。
  • "主干开发,分支提测"——将原来的多个分支进行合并,统一在主干上开发,每周结束时拉出一个分支,进行提测,一旦发现问题,就在主干上修复。
  • "持续集成"——为了确保每次提交质量,对主干开发建立持续集成环境,开发人员和自动化测试人员都严格遵守持续集成纪律"Check-in Dance"。

新的开发流程如下图所示。

分支开发策略变更为Single Branch模式。

五、小结

通过以上改进措施,让团队的合作方式发生了重大变化,从"碉堡防御"走向了"战线统一"。

原来,各角色仅关注于自己本身的工作,虽然大家都同处于一个项目中,但各自划分了"领地",产品经理就应该将MRD写得清清楚楚,如果开发人员认为 不清楚,那就回去再改。开发人员只管按照MRD上的内容进行开发,很少考虑可测性和易测性问题。测试人员只管按照MRD中内容来测试,有问题通过内部工作 流平台提交问题单。运维人员只管根据开发人员提交的上线操作单进行操作。似乎各角色之间的沟通介质只有各自的"交付物"。

现在,各角色都能够共同合作,以项目的最终交付为目标,积极讨论需求,优化实现。因为角色之间的这种紧密合作让所有人对不同角色都有了深入的了解。 开发人员耐心为产品经理解释技术实现,说明计划安排,测试人员与开发人员共同讨论验收条件,避免遗漏需求。开发人员让运维人员了解架构设计, 细心听取运维人员的建议,进行技术改造,使部署工作更快捷有效。

通过这些活动,大家都认识到原有内部管理平台仅是个公文流转的支撑平台,要想提高工作效率,就要将这种"办公自动化工具"进一步提升为"全面自动化工具",使所有人更关注于端到端的价值,而非各角色之间的分界点。

六、结束语

百度刚刚开始敏捷之旅,还没人谈及"DevOps"运动,虽然还没有什么强大的工具支撑,但基于"提高效率"的朴素思想进行的过程改进也带来 了"DevOps"效果。可见,DevOps听上去很神秘,但其实并不难。只要本着精益思想,聚焦于快速交付价值,不断发现并消除浪费,你也一定会有很大 收获。


感谢熊节对本文的审校。

给InfoQ中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家加入到InfoQ中文站用户讨论组中与我们的编辑和其他读者朋友交流。

posted @ 2011-04-22 11:22 申健 阅读(17) 评论(0) 编辑
摘要: http://skysigal.xact-solutions.com/Blog/tabid/427/entryid/1586/CruiseControl-NET-Setting-it-up-with-FXCop.aspx阅读全文
posted @ 2011-04-20 13:18 申健 阅读(44) 评论(0) 编辑
摘要: 原文地址:http://guoshiguan.iteye.com/本文讲述了ESB架构在企业内的实际运用,包括在部门内、部门间以及企业级ESB架构的设计和案例;分享了ESB设计过程需要考虑的关键问题;描述了不同ESB域的实施重心。相关厂商内容百度技术沙龙第十三期报名:JavaScript库的设计与应用Sybase在线研讨会:复杂事件处理与实时分析应用(4月14日 周四)Adobe Flash Builder 4简体中文正式版高速下载Web App应用开发者大会火热报名中(4月27日 北京 免费)!概述ESB的存在主要是为了整合企业内部的应用,使企业内的应用能融为一体,而不是成为一个个信息孤岛。阅读全文
posted @ 2011-04-13 11:12 申健 阅读(507) 评论(0) 编辑
摘要: 原地址:http://macrochen.iteye.com/blog/353726Subversion(SVN) 是一个版本管理软件或者服务器,可以提供托管“源代码或文档” 并能够异域同步文件更新,记录版本区别,分晰先后文件差异之处的程序。Subversion有一个很标准的目录结构,是这样的。比如项目是proj,svn地址为svn://proj/,那么标准的svn布局是svn://proj/ | +-trunk +-branches +-tags这是一个标准的布局,trunk为主开发目录,branches为分支开发目录,tags为tag存档目录(不允许修改)。但是具体这几个目录应该如何使用,阅读全文
posted @ 2011-04-13 10:53 申健 阅读(38) 评论(0) 编辑
摘要: http://www.infoq.com/cn/articles/enterprisemessage-sqlserver-servicebroker1、引言Microsoft 在SQL Server 2005引入了服务代理 (Service Broker 简称SSB) 为技术支持代理设计模式和面向消息的中间件 (MOM) 的原则。Service Broker在SQL Server 2008上得到完善, SQL Server Service Broker 为消息和队列应用程序提供 SQL Server 数据库引擎本机支持。这使开发人员可以轻松地创建使用数据库引擎组件在完全不同的数据库之间进行通信阅读全文
posted @ 2011-03-31 12:07 申健 阅读(86) 评论(0) 编辑
摘要: 1、“如果程序员及其主管经理在读过本书之后,哪怕只是学会了将程序员当做活生生的人,而不是另外一台机器来看待,那么这些程序员就将会更高效地发挥作用,同时会对自己的工作更加称心如意。”2、汽车配件清单的例子----程序员狭隘的心理问题3、程序员组----一组人在一起工作,但是各自的工作不交叉。作者建议这类人应该互相协作,互查代码。4、What Do You Say to a Naked Lady?待续。。。阅读全文
posted @ 2011-03-11 09:39 申健 阅读(57) 评论(0) 编辑