【原文地址】And Get Rid Of Those Pesky Programmers
【原文发表日期】 Jun 12, 2009
【狐言乱语:说实在话,我觉得这篇文章写得很糟糕。从哲学角度而言,这里并没有太深层的见地。从文章的逻辑来看,甚至可以说是有些散乱的… 那些所提及的道理(比如最后一段)也不见得有太大的新意…】
时不时地总会有些电子邮件或者网站文章里会提到他们保证能证明Fred Brooks在他的人月神话(强烈推荐阅读!)中所提出的疯狂的“没有银弹”的理论是错误的。如果有“银弹”,那我们在下一个十年中所能取得的在生产效率、可靠性、和简洁性方面的进步将会以十倍计。
这一次,我们所听到的保证也和从前大同小异,不过这次的保证人觉得有必要郑重指出他们革命性的新程序/框架/神奇的发明可以是业务分析师直接以十倍速来开发应用程序而且完全不需要借助专业程序员的工作!
“哦,好耶!让我们摆脱这些讨厌的身上有股怪味的程序员吧!我们不需要他们了!”
不过,请看在上帝的份上帮帮忙等那么一下下!你确定么?!
我现在正尽力使自己忘了他们所说的以免无法控制自己最直接的条件反射,那就是直接把对方当成脑残而无视掉。如果我是一个反应过激的人,很显然我最先想到的一个恼人的问题就是:
“为啥这些商务人士如此热衷于摆脱我们这些程序员”
我们很容易把这简单归罪于这些穿西装的家伙不懂软件开发这事儿,从而迫使自己和Tom Smykowski一样开始为我们具体在这儿干些什么进行辩护:
“好吧好吧,你瞧,我已经告诉你了:我和那些该死的客户打交道,这样那些工程师就不必为此伤脑筋了。我有和人打交道的能力;我善于和人打交道。你们怎么就不懂呢?你们这些人到底有什么毛病?”
也许吧,就如Steve “Doc” List在最近一期MSDN杂志的End Bracket article专栏上引用的Cool Hand Luke里的一句关于“有效交流”的台词所说的那样:
“我们所面对的是一种失败的交流”
Leon Bambrick(也就是SecretGeek)最近在他的这篇帖子里谈到了这个现象:The Better You Program, The Worse You Communicate,在文章中,他解释了为什么很多使我们成为高效的软件研发人员的素质却没能在人际交流的方面给予我们同样的帮助。
归根结底,我们有些时候确实会使人觉得很难相处。我们经常全神贯注于技术方面的难题或者解决方案的局限,以致我们会不知不觉地用一大套专用术语把那些利益相关人士(stakeholders)搞得云山雾罩的,或者我们干脆把他们的需求形容为无理取闹从而直接把他们惹恼了。有些时候,我们失职于无法深入理解他们业务于是我们就干脆开始取笑他们而不是真正地区了解他们所需要的。难怪到最后他们会希望能自己来干编程的活了呢!
好吧,好吧。情况并不总是这样的。不是每个程序员都是这般作为,所以如此批评每个开发人员并不公平。我其实也只是想强调并理解支撑这个想法的观点:也就是将程序员排除在外会是件好事。
相当一部分的批评应该归咎于那些兜售蛇油的推销员们(译注:snake oil salespeople,通常指兜售一些无实际效果的所谓神奇药品的江湖骗子;此处指推销上面所提到的快速自动软件开发平台的销售人员),因为在目前的情况下,他们是在推销一个谎言。他们试图使用户相信的是每个普通的业务人员都可以用自己的语言向那个神奇的软件描述他们所面对的业务逻辑,然后那个神奇的软件就会自动生成所需的应用程序了。
前些天,我发了一个内部的电子邮件用很通俗的语言描述了一个我觉得会很有意思的功能。几小时后,我的同事已经有了一个实现的雏形可以演示了。
朋友们,这,才是最牛逼的指令式编程(declarative programming)呢。我只要把自己的意图描述出来,然后稍等一会儿,接着,哗啦一下!代码就出现了!也许这就是那些神奇的软件所想要达成的事,不过这里有个问题。我举的这个例子中,我是把需求提交给了一个人类同胞。如果我的那个电子邮件是发到某个软件那里去了,那它恐怕是不知道应该为我做点什么的。
在将来的某个时候,也许会有软件可能具备上述的一些功能,不过这只有在软件达到相当成熟的人工智能和真正懂得如何处理模糊概念后才有希望。换句话说,只有当软件自己成为程序员时,你才可能摆脱人类程序员。不过我还是要遗憾地指出,你其实还是在和一个程序员打交道,只不过那是一个不会傲慢地对你的需求嗤之以鼻的无机体(至少不会当着你的卖弄如此,当然,它可能私下里正在盘算如何统治全世界呢)。
在那一天到来之前,当一个业务人员使用上面所提及的那个神奇的框架来自己编制出一个如乐高积木般精确的程序时,这个小业务员实际上有成为了现实意义上的程序员了。这样的工作其实和一个真正的开发人员所需掌握的技术已经相去不远。所以在如此情况下,你并没有真正摆脱程序员这个概念,你只是将一个业务人员转职成了一个开发人员,一个正巧也懂得业务规范的开发人员。
归根结底,不论你的系统有多指令化(“declarative”)有多傻瓜式,以至于一个非开发人员也可以通过在屏幕上把一些小控件拖来拖去就拼成一个应用程序,在这套模式中,能够被允许的概略性和模糊性是很少很少的。而概略和模糊的概念,恰恰是电脑所不擅长而人类所擅长处理的,这正如Spock在一集Star Trek中所提到的:
“计算机,请计算PI的最后一位数字” – Spock
除了这些,你还应该再想到在完成一个应用程序的过程中有很大一部分的实际工作并非是撰写代码,而且所有围绕着这个任务所展开的调查研究,正如Udi Dahan在他的“重用的谎言和误区”一文中所提到的。
说了这么多并不说明我认为我们应该停止投资开发更加完善的工具。毕竟,软件开发的历史就是一部不断改进高层工具从而提高开发者生产效率的历史。我所观察到的危险在于那些试图摒弃无论使用何种工具来开发程序都需要用到的原则和特性的所谓方法论。
即使有一天你能够用人类的语言来告诉电脑你所想要的,而且电脑也可以就此工作,我们还是需要重视软件开发的原则,确保质量检查,测试,等等这些不变的标准。
对于我们程序员来说,我觉得我们应该从中学到两点。首先,我们必须向利益相关人士(stakeholders)介绍软件编写的真正流程是如何的。即使他们无心倾听,一点点的了解和理解都会有长远的帮助。我们要有耐心,不要摆出居高临下的姿态,并且要对结果有最好的期待。其次,我们也该要求自己对所面对的业务有更深层的理解和见地,从而我们在别人眼中的就成长为一个有价值的商业伙伴,只是,我们也碰巧写点真正有空的程序罢了。
【原文地址】ASP.NET MVC Installer For Visual Studio 2010 Beta 1 And Roadmap
【原文发表日期】 Jun 09, 2009
不久之前我公布了我们就关于ASP.NET MVC与Visual Studio 2010平台的集成的一些计划。ASP.NET MVC并没有包括在日前发布的Beta 1里面,这个决定引起了一些朋友的猜测和关注(甚至还有人怀疑这里有什么阴谋!); ) 其实真正的原因就是如我所说明的:
你可能会注意到ASP.NET MVC并没有包含在Beta 1中。主要的原因是Beta 1在MVC 1.0发布之前已经内容锁定了(译注:lock down;微软内部指一个产品只修改bug不增加功能的阶段)。而VS10 Beta 2里会包含ASP.NET MVC。 …
我们正在努力设法完成一个编外的安装程序来在VS2010 Beta1环境下安装ASP.NET MVC的项目模版和工具,预计会在六月的某个时间通过CodePlex发布。所造成的不便,敬请见谅。我会在第一时间写博客通知大家的。
今天我高兴地向大家宣布,我上面所说的安装程序已经完成了,你可以在CodePlex上找到它并下载。请一定尝试一下这个新东东,因为很多VS10所支持的测试驱动开发(TDD, Test-Drive Development)方面的新功能和ASP.NET MVC有着紧密的联系,关于这点ScottGu会在下一则博客中进行介绍。
如果你在使用过程中遇到任何困难,你可以参考一下Jacques的这篇帮助指南,Jacques是这个安装程序的主要开发人员,所以也请不吝提供您宝贵的反馈意见。
你可能会注意到这个安装程序自称是ASP.NET MVC 1.1版本,但正如ReadMe中所提及的,这个其实只是ASP.NET MVC 1.0针对Visual Stuido 2010重新包装后的版本。1.1这个版本后只是个占位符。我们有意递增了版本号以避免与ASP.NET MVC 1.0有任何运行时的冲突。所有这些以及其他更详细的概况可以在发行注记(Release Notes)里找到。
等到VS10 Beta 2发布的时候,你就不需要再下载一个额外的独立安装程序了(虽然我们还会给VS2008的用户发布一个支持ASP.NET 3.5 SP1的独立安装程序)。Beta 2会包含一个预览版的ASP.NET MVC 2,这也正是我在接下来的产品未来蓝图(Roadmap)中所要介绍的内容:
产品规划蓝图
我最近发表了一篇关于ASP.NET MVC 2的产品规划蓝图的文章,主要是从宏观角度介绍我们准备在ASP.NET MVC 2里增加的新功能。这些新功能的介绍很明显地缺少足够的细节,这主要是因为我们当前还在紧张地策划阶段以搜集更详细的用户所遇到的困难和需求。
当下,我们会尽量避免太过关注于实现细节。在设计软件的时候,人们总是很容易有先入为主的想法来决定某个问题的解决方法应该是如何如何的,而事实上,我们常常连究竟需要解决的是什么问题都还没搞清楚呢。
与其试图将人们导向我们所认为的答案所在,我更希望将注意力集中在确保我们能够正确认识我们所面对的问题的领域以及人们想从这个框架中所得到的是什么。这样做是我们有充分的自由区尝试各种不同的方案,有些甚至是通常不会想到去尝试的,比如编写基于表达式的URL帮助函数的其他途径。也许这些额外的尝试是成功的,也许不是。但最理想的,我觉得就是对于每个我们所想实现的功能,我们都能提供多种的设计选择。
在我们进行这些计划的同时,我也会持续地提供规划蓝图中更多的细节与大家分享。
快捷代码片段(Snippets,亦称Code Snippets)
VS10有一个很酷的新功能就是现在HTML editor也支持快捷代码片段了。Visual Web Developer team的Jeff King给我发来了我们打算在下一版中发布的那些代码片段。你也可以通过CodePlex的发布页来获取它们。安装也是十分简单的:
安装步骤:
1) Unzip "ASP.NET MVC Snippets.zip" into "C:\Users\<username>\Documents\Visual Studio 10\Code Snippets\Visual Web Developer\My HTML Snippets", where "C:\" is your OS drive.
2) Visual Studio will automatically detect these new files.
敬请各位下载并试用一下这些资源,并将你认为可以更有助于你开发工作的想法反馈给我们。
重要链接:
【原文地址】An Alternative Approach To Strongly Typed Helpers
【原文发表日期】 Jun 02, 2009
MVC Futures项目有一个特色功能就是它允许开发者利用lambda表达式来生成强类型的动作响应链接(action links)。比如:
<%= Html.ActionLink<HomeController>(c => c.Index()) %>
上面的这行代码会生成一个指向HomeController的Index动作的链接。
这个技巧当然很优美,不过实际上它也有一些小问题。首先,它的语法就不像你高中毕业舞会上的舞伴那么吸引人。我猜你也许可以逐渐地去习惯它,不过很多人看见这段代码的第一反应就是觉得有点头晕。
另一个问题是在这个演示PPT中(是Brad Wilson告诉我的)所提到的效率问题。这组PPT的作者发现以上表达式的编译速度特别慢。
我之前以为我们可以通过某些利用缓存编译后的表达式的方法来缓解效率的问题,不过那也许无法解决一些现实问题。试想有如下的情况:
<% for(int i = 0; i < 20; i++) { %>
<%= Html.ActionLink<HomeController>(c => c.Foo(i)) %>
<% } %>
在这个循环中的表达式看起来是不变的:c => c.Foo(i)
但实际上变量"i"的值在每一次循环中都是不同的。如果我们试着缓存编译后的表达式,大家可以想象将会发生的事情。
于是我开始思考能不能找到另一种利用自动代码生成来解决以上问题的方式,于是我写了一封内部的email与微软的同事们开始讨论。一个可行的方法是自动生成特定的动作响应链接的代码。遵循这个思路,那么Home控制器(Home Controller)的about链接(为了演示起见,我们加了一个id参数)就可以如下表示:
<%= HomeAboutLink(123) %>
Brad多次提到虽然他喜欢lambda表达式,但他却不喜欢用它们来表示一个动作响应链接,他更倾向于用上面所提到的这种格式来编写某个特定的动作链接的方法(译注:就是HomeAboutLink(123)这样的写法)。那么如果我们可以帮助开发者来自动生成这样的链接,那不是很棒么?
这个email讨论开始几个小时后,David Ebbo已经完成了一个初步的实现。也许他在此之前就自己考虑过这个问题并尝试过解决了,我不清楚,我那天一直在开会。这可能是世界上最好的表述型编程方法(declarative programming)了,我“表述”了我大致的思路,然后便干其他的事去了,过了一会儿,好,代码就已经有了!
David的方法是利用BuildProvider的来对解决方案(solution)中的控制器(Controllers)和动作(Actions)来进行反射(reflection),然后给每一个都生成各自的动作响应函数。这里当然还有很多可以改进的地方,比如确保自动生成的代码会保证ActionNameAttribute的设置并且生成重载的函数,不过这至少已经是一个很清晰的概念实现(proof of concept)了。
与基于lambda表达式的帮助函数相比这个方法有一个不足之处就是它无法提供对重构的
支持。不过,如果你重命名了一个动作函数,你将会得到一个编译期的错误而不是运行期的做错,因此这至少比什么都没有要强些。这个方法的优势自然是它的效率更快,而且,它也不依靠那看着恼人的lambda表达式的语法了。
以上讨论的内容是我们权衡中的下一个ASP.NET MVC版本里可能包含的一些有趣的改进。
【原文地址】Writing A Page To A String
【原文发表日期】 May 29, 2009
ASP.NET页面通常是将它们内容直接输出到一个请求响应流(response stream)中。这对比较大型的页面来说应该是一个巨大的效率优化,因为这样做就不需要为页面显示而建立很大的缓冲区或者分配很大的字符串。而分配大型字符串的操作经常会在“大型对象堆栈”(Large Object Heap)上获取所需的内存,而这也意味着这些内存块不会被很快地资源回收。
然而,很多情况下你可能确实需要将一个页面的内容输出到一个字符串里以便进行一些后处理工作。关于这点,我N久之前也曾经写过一篇blog介绍了一个方法:就是使用response filter。
不过,最近我学到了Page类中的一个我从没有注意到过的方法,这个方法提供了以上问题的一个更轻量级的解决方案。
我所说的就是CreateHtmlTextWriter这个方法,它是一个保护(protected)成员函数的,而且也是一个虚(virtual)函数的。
以下是一个页面code-behind的代码示例,其中利用了这个函数来对页面的输出内容进行过滤,经此处理后的内容才最终显示在浏览器中。
public partial class FilterDemo : System.Web.UI.Page
{
HtmlTextWriter _oldWriter = null;
StringWriter _stringWriter = new StringWriter();
protected override HtmlTextWriter CreateHtmlTextWriter(TextWriter tw)
{
_oldWriter = base.CreateHtmlTextWriter(tw);
return base.CreateHtmlTextWriter(_stringWriter);
}
protected override void Render(HtmlTextWriter writer)
{
base.Render(writer);
string html = _stringWriter.ToString();
html = html.Replace("REPLACE ME!", "IT WAS REPLACED!");
_oldWriter.Write(html);
}
}
在CreateHtmlTextWriter方法中,我们首先是调用基类的该函数来创建一个原来的HtmlTextWriter,然后将它暂时存放在一个成员变量中。
然后我们还是调用基类的函数来创建一个新的HtmlTextWriter,不过这个对象实例会使用我们自己的StringWrtier作为底层的TextWriter。被传入到Render函数中的HtmlTextWriter就是这个新创建的实例。(在Render函数中)我们首先对这个新的HtmlTextWriter实例调用基类的方法,然后将底层StringWriter的输出内容取出,这样就可以对该部分内容进行所需的处理了。我们最后将最终的输出内容写到原先的HtmlTextWriter中去,因为原先的这个HtmlTextWriter是真正负责将结果写到请求响应中去的。
使用这个技巧的时候有很多值得特别注意的地方。首先,如我先前所提到的,对于大型的页面,以上所做的这些事可能会大大地影响你网页的运行效率和可伸缩性。而且,我也没有针对输出缓存、异步页面等等的情况下测试过上面的技巧,所以你很可能会遇到意想不到的实际结果。
注意,如果你是需要从一个页面调用另一个页面,然后在第一个页面中得到后者的输出内容,那么你可以将你自己的TextWriter实例传到Server.Execute函数中并得到结果,所以这种情况下你无需借助上面所介绍的这个技巧。