打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
VS2010使用问题集合|网站技术 - 美国主机支持论坛 - Powered by php...




vs2010中,MSBuild与C++编译器无缝整合.无论使用vs2010生成的代码,还是转换vs2008或者是更低版本vs编译的C++代码.都会在工程编译后,都会提示一条错误:


C:\Program Files\MSBuild\Microsoft.Cpp\v4.0\Microsoft.CppBuild.targets(935,5): warning MSB8012: TargetPath(c:\users\kalmbach\documents\visual studio 2010\Projects\CPP_DLL2\..\bin\CPP_DLL2d.dll) does not match the Linker's OutputFile property value (c:\users\kalmbach\documents\visual studio 2010\Projects\bin\CPP_DLL2d.dll). This may cause your project to build incorrectly. To correct this, please make sure that $(OutDir), $(TargetName) and $(TargetExt) property values match the value specified in %(Link.OutputFile).


于是Google一下, 结果在这里发现了大家都发现同样的问题
我这里的编译习惯是这样的, 调试版无论dll, lib还是exe,都在工程名后加d加扩展名组成最后的名称,例如
cored.lib  engined.lib , Release版本没有d


因此,为了避免这个warning,只用将调试版的General节点上Target Name的值改为$(ProjectName)d
而有些工程的Librarian或者Link分支的Output File的值在转换升级的过程中会被修改. 同样可以统一修改为vs2010的风格



$(OutDir)$(TargetName)$(TargetExt)



usidc5 2011-01-23 15:13

性能,永远是程序员要考虑的问题。在单核时代,甚至在双核(多核)时代,一般是通过改善客户使用的计算机性能来提升程序的性能,如增加服务器、内存,配置负载均衡等手段来实现,我们称这个过程为享受性能免费大餐。天下没有免费的午餐,性能免费大餐也不能毫无止境,实际上,已经有了新的解决方案并行计算。并行计算就像是一道饕餮大餐而被人津津乐道,在本文中我们以烹饪为类比,通过对性能免费大餐的分析,使用 Visual Studio C++ 2010这把利器,应用并行编程模型大块朵颐的进行并行开发。

性能免费大餐已经结束

通过提升CPU的计算能力,确实能够改善应用程序性能。但在实际情况中,无论处理器性能提升多少,软件都有办法迅速吞噬。况且,计算机硬件毕竟受物理极限的约束,处理器主频的提升已经遇到了瓶颈。所以,享受性能免费大餐的日子已经结束,业界已经不能提供指数级增长的更快的处理器,而只能选择提供指数级增长的更多的处理器。多核将引领软件研发发生基础性的变化。

目前的电脑市场上,多核计算机的销量远远大于单核计算机,多核已经成为了一种主流。在这样的发展趋势下,如果把在单核下实现的应用程序拿到一台64核的机器上运行,你会看到任务管理器显示如下的画面只有1/64的计算能力得到了利用:

图 1 任务管理器显示64核机器上运行单线程应用程序,只有一个核在计算

通过上面的示例可以看出,传统的应用程序再也无法顺其自然地在更高端的硬件设备上获得更高的性能回报,能够充分发挥硬件设备性能的应用程序是未来软件开发的主流,作为开发人员,我们面临的抉择是什么呢?Herb Sutter在他的原文中明确地给出了答案:并行计算。如果在四年前说“并发将是软件开发史上的又一个重大变革”是一个预测,那么今天,并行计算已经成为软件开发的核心趋势之一。对于程序员来说,享受免费大餐的日子结束后,只能亲自下厨烹饪。

亲自下厨遇到了难题

我们都知道,应用程序的开发,有着完整的生命周期管理,从编写需求说明书、程序设计说明书,到编码、调试和性能优化,再到测试、发布,以及后期维护等一系列的行为都有其复杂性。而并行计算是在程序开发原有的复杂性上,更添加了一个维度。在这个过程中,程序员会遇到各种各样的问题,如下图所示:

图 2 开发并发应用程序面临的需要考虑的问题

开发并行应用程序,一直是令广大程序员头痛的事情,现如今我们又有哪些准备了呢。俗话说的好,巧媳妇难为无米之炊,一些准备好的食材、一本可供参考的菜谱、一套方便使用的厨具是必不可少的,希望这些必备品能为我们的烹饪带来便利。

食材、菜谱和厨具都很重要

2007年,微软宣布成立并行计算平台组,致力于简化并行应用程序的开发。随着Visual Studio 2010和.NET Framework 4的发布,微软为并行计算提供了完整的解决方案。

图 3 Visual Studio 2010和.NET Framework 4对并行开发的支持

食材并发运行时

不论是任务并行、数据并行,还是管道并行,都意味着需要把一个耗时的任务或数据分割成更小的单位。分割的颗粒度往往是由任务的性质决定的。细颗粒度并行的好处主要体现在可扩展性和负载平衡上。假设一个耗时的任务只被粗略分割成四个子任务并发执行,那么它对于多于四核的机器的扩展性就不够好;即使是在四核的机器上运行,也无法做到实时动态的负载平衡,可能发生三个子任务早早完成,而另一个任务还在一个核上苦苦等待的悲剧性事件。

为了支持细粒度并行,在Visual C++ 2010中提供了一套并发编程框架,支持常用的协同任务调度和硬件资源(CPU和内存)管理。.NET Framework 4也在已有的线程池(Thread Pool)基础上,实现了协同任务调度和工作窃取(work-stealing)算法。工作窃取算法充分利用了细颗粒度并行的优势,保证空闲的线程依照一定的顺序,从本地、全局,甚至是其他线程的任务队列中“偷取”任务执行。当然,默认的任务调度器可以被扩展或配置以支持特殊的调度策略。

并发运行时是 C++ 并发编程框架,使用该框架,可以简化并行编程,能够帮助我们编写可靠、可伸缩且具有响应能力的并行应用程序。

菜谱编程模型

高抽象级别的、统一的编程模式是简化并行程序开发的一个重要方向。因此在Visual Studio 2010和.NET Framework 4中看到许多新的语言和库功能,以及一系列面向任务的并行结构和算法。

在Visual C++ 2010中,并行模式库(Parallel Pattern Library)引入了支持任务并行的任务(Tasks)和任务组(Task Groups)概念。任务是一类计算,可将其分解为多个更精细的计算。在并行模式库中,task_handle包含执行细颗粒度的代码,用来代表一个任务。任务句柄(task_handle)非常重要,因为它们将管理封装的工作函数的生存期。 例如,将 task_handle 对象传递给任务组时,该 task_handle 对象必须保持有效,直到任务组完成为止。任务组是用来组组织、调度、等待或者取消某个或某些任务,它会将任务推入工作窃取队列, 计划程序从该队列中移除任务,并用可用的计算资源执行任务。下面示例代码并发执行若干个任务

为了方便将串行应用程序改为并行应用程序,并行模式库提供了parallel_for和parallel_for_each,我们可以很容易将自己写的 for和for_each循环代码改写为并发执行,并且不会降低代码的可读性;同样,对于管道并行,代理库(Agents Library)提供了基于数据流编程模型的C++模板库,通过使用消息传递在对象之间传输状态更改,可以隔离对共享资源的访问,从而提高可伸缩性。消息传递的优点就是它将同步绑定到数据,而不是绑定到外部的同步对象。这样就简化了组件之间的数据传输,可以消除应用程序中的编程错误。

在托管代码方面,任务并行库(Task Parallel Library)引入System.Threading.Tasks.Task类,以及Parallel.For和Parallel.ForEach来支持任务或数据并行。

此外值得一提的是PLINQ(Parallel Language-Integrated Query)。PLINQ作为LINQ的并行实现,对内存内的IEnumerable数据源进行分区,随后利用系统内的多核,并行在子数据源上操作。

无论是任务的组织、调度、执行,还是资源分配、内存共享,Visual C++ 2010为编写并发应用程序都给予了帮助,通过充分利用多核CPU性能来提升软件的性能,真正享受到亲自烹饪的性能大餐。

厨具开发工具

子曰:“工欲善其事,必先利其器”。好的开发工具是成功的一半。在Visual Studio 2010里包含了两个新的调试器窗口和一个新的性能可视化剖析器(Profiler)。有了这两个调试器窗口,我们可以在代码同等的抽象层面上也就是任务进行调试,看到任务的状态,彼此之间的关系,调用堆栈等等。当然如果感兴趣的话,也可以看到任务对应的线程,并利用一个全局的统一视图来查看所有线程的调用堆栈,以及彼此之间的关系。

图4 并行堆栈窗口

图 5 并行任务窗口

性能优化是软件开发过程中一项重要的工作,那么一个功能全面的性能探察器自然是必不可少的了。Visual Studio 2010里的并行性能可视化探查器可以看到应用程序对资源的利用情况,程序的哪个部分是受计算量限制的;也可以看到线程的执行情况,阻断的原因,线程在不同的核之间切换的情况,等等;同时还可以在线程执行的不同时间点上,跳转到相应的调用堆栈,去研究造成线程阻断的根本原因。

图6 探测器视图CPU利用率

图7 探测器视图线程

小结

我们习惯了串行思考问题,这叫思维定势,对于突如其来的并行思维,是需要一段时间才能够接受;其次,并行应用程序开发相对普通程序要难一些。改变串行(顺序)编程的这种思维方式并接受这样的编程挑战,还需要一个认识和学习的过程。就目前来说,对于大多数开发并发应用程序的程序员来说,仍是先从串行应用着手,确定了性能瓶颈后,针对关键代码段再进行并行化。有了Visual Studio 2010和.NET Framework 4这样利器,有了并行编程模型这样的好食材,编程就像烹饪,只有动手才能体会到其中的无穷乐趣,您还等什么呢?赶快行动起来吧!

原文链接:http://tech.it168.com/a2010/1215/1138/000001138613.shtml


usidc5 2011-01-23 15:14

在“从VC++6.0不足看Visual C++2010新特性” 一文中,我们了解到Visual C++ 2010在语言层面开始支持最新的C++标准,在IDE以及MFC库等方面,也都有了质的变化。对于集成开发环境(IDE)来说,以前的版本中也都有所改变,但都是几次不大的更新。Visual C++ 2010中对IDE有着革命性的增强。

我们知道Visual C++ 开发环境为项目管理与配置(包括更好地支持大型项目)、源代码编辑、源代码浏览和调试工具提供强力的支持,是开发过程中不可缺少的工具,是提高代码生产力的基本保障。在本文中,我们将对Visual C++ 2010 IDE新特性进行剖析,主要从MSBuild改进的项目和生成系统、更快的编译和更高的性能、更加智能的 IntelliSense、#include 自动完成功能、新的编辑环境等五个方面进行阐述。

Visual C++ 2010中,解决方案和项目的构建系统(build system)从原先基于VCBuild的构建系统,迁移到基于MSBuild(Microsoft Build Engine)的构建系统。那么MSBuild 是什么呢?MSBuild 是 Visual C++ 项目的标准生成系统,是一个基于 XML 的项目文件或可选设置文件的工具。它集成在Visual Studio的开发环境中,为Visual C++ 生成过程提供了便利,提高了效率。MSBuild的加入,使得“一次编码,多个平台运行”成为可能。

在Visual Studio的早期版本中,只能使用当前版本提供的工具集,如果您想使用新的集成开发环境(IDE),您必须等到能够迁移到新工具集的时候,这给一些时尚的开发人员带来了许多不便。Visual Studio 2010 允许您以多个工具集版本为目标进行生成系统。通过 Visual Studio 2010,您可以将应用程序编译为在若干 .NET Framework 版本的任意一个上运行。 例如,可以将同一个应用程序编译为既能在 .NET Framework 3.5 版本上运行,也能在 .NET Framework 4 版本上运行。下图显示了属性页上的本机多定向设置,您可以将 Visual C++ 9.0 编译器和库作为目标,同时在 Visual Studio 2010 中工作。

另外,由于MSBuild 使用基于 XML 的项目文件格式,该格式直接明了,可扩展性强,同时也增强了C++ 生成系统的可扩展性。当默认生成系统不足以满足您的需求时,可以通过添加自己的工具或任意其他生成步骤来扩展该系统。MSBuild使用任务作为可执行代码的可重复使用单元来执行生成操作,您可以通过在XML文件中定义自己的任务来扩展系统,MSBuild会使用这些XML文件动态生成任务。

下面的示例描述通过XML文件动态生成任务。该项目包含两个任务:一个是 GenerateResource 任务,用于编译资源;一个是 Csc 任务,用于编译源代码文件和编译的资源文件。 由 GenerateResource 任务编译的资源文件存储在 Resources 项中并传递给 Csc 任务。

Visual Studio 2010通过增强编译器后端的代码生成功能来提高生成应用程序的编译速度、质量和性能。主要表现以下几个方面:

通过优化单指令多数据(SIMD)的代码生成功能,提高代编译器的性能和代码质量。其中的改进主要包括打破错误依赖关系,向量化常量向量初始化,更好地分配 XMM 寄存器消除多余的负载、存储和移动。

通过优化x64 代码生成提高x64 平台上的编译速度。LTCG编译(链接时间代码生成)通常会比非LTCG 编译占用更长的时间,尤其是对于大型的应用程序。在 Visual Studio 2010 中,LTCG 编译速度提高高达 30%。在该版本中引入了一个写入 PDB 文件的专用线程,因此您在使用 /DEBUG 开关时会看到链接时间的缩减。

通过添加对被检测二进制文件的非锁定版本的支持,PGO(按配置优化)检测的运行速度有所提高。还有一个新的 POGO 选项 PogoSafeMode,用于指定优化应用程序时使用安全模式还是快速模式。快速模式是默认行为。安全模式是线程安全的,但比快速模式要慢。

编译器生成的代码的质量也有所提高。现在完全支持高级矢量扩展 (AVX),这对于 AMD 和 Intel 处理器中通过固有选项和 /arch:AVX 选项进行大量浮点计算的应用程序非常重要,使用 /fp:fast 选项可以使浮点计算更为精确。

更加智能的 IntelliSense

Visual Studio 2010 中包含了全新的 IntelliSense 和浏览基础结构。除了帮助调整和响应具有大型基本代码的项目,此基础结构改进还带来了一些新的设计时效率功能。

如实时错误报告和快速信息工具提示这样的 IntelliSense 功能基于新的编译器前端,即使代码文件正在修改中,该前端也能分析完整的转换单元以提供关于代码语义的丰富且准确的信息。

所有代码浏览功能(如类视图和类层次结构)现在都使用 SQL 数据库中存储的源代码信息,该数据库启用了索引功能并具有固定的内存占用量。与以前的版本不同,Visual Studio 2010 IDE 始终具有响应能力,当编译单元由于头文件发生更改而重新分析时,您不再需要等待。

IntelliSense 实时错误报告(在错误下显示红色波浪下划线)在浏览和编辑代码时显示编译器质量语法和语义错误。将鼠标悬停在错误上即可查看错误消息。错误列表窗口也会显示当前查看的文件中的错误以及编译单元其他位置的 IntelliSense 错误。不必进行生成即可获得所有这些信息。若要显示导致问题的代码,请在“错误列表”窗口中双击错误。

该功能的增强,可以提供智能化且特定于上下文的建议,方便处理更多的文件、更加复杂的项目。值的注意的是,虽然所有代码浏览功能都可用于纯 C++ 和 C++/CLI,但像实时错误报告和快速信息这样的 IntelliSense 相关功能在 Visual Studio 2010 最终版中不可用于 C++/CLI。

#include 自动完成功能

在包含头文件时,也增加了自动完成和过滤功能。键入 #include 时,集成开发环境将自动创建一个包含有效的头文件的下拉列表供您选择。如果你继续输入一个文件名,集成开发环境将自动根据您的输入加以过滤。在任何时候,你都可以根据这个列表来选择你想要包含的文件。因此,这一功能可以让程序员快速地包含那些尚不确切知道文件名的文件。

新的编辑环境

1. 新的搜索定位功能

新的“定位到”功能。选择菜单“编辑”中的“定位到”,该功能可以帮助您更有效的搜索文件或符号。根据您输入的字符串实时搜索到相应的结果,将您的输入字符串与项目中的符号和文件对照匹配。此功能还适用于 C# 和 Visual Basic 文件,并且可进行扩展。

2. 新的调用层次结构

调用层次结构(Ctrl+K、Ctrl+T)可以定位到从某一特定函数调用的所有函数,以及对特定函数进行调用的所有函数。这是以前的 Visual Studio 版本中存在的“调用浏览器”功能的改进版本。“调用层次结构”窗口组织得更好,对同一窗口中出现的任何函数同时提供调用来源和调用目标树。

3. 灵活的查找引用功能

此版本中还对其他一些主要编辑器功能做出了改进。例如,用于在整个解决方案中搜索对代码元素(类、类成员、函数等)的引用的“查找所有引用”功能现在更为灵活。使用右键单击上下文菜单中的“解析结果”选项可进一步精简搜索结果。

在编辑器方面,除了上面改进的功能外,常规编辑器在 Visual Studio 2010 中也得到了增强。为消除混乱并提高可读性,新的基于WPF(Windows Presentation Foundation)的 IDE 经过了重新设计。像代码编辑器和设计视图这样的文档窗口现在可以浮动在主 IDE 窗口之外,并可在多个监视器中显示。使用 Ctrl 键和鼠标滚轮可以轻松缩放代码编辑器窗口。

而在我们熟悉的VC++ 6.0的IDE里面,微软对开发人员就没有这么优待了,它没有“定位到”的功能。在VC++ 6.0里,定位和搜索只能是使用“查找”和“转到”的功能,实现定位到需要查找的位置,则要经过很多步的操作,显然,这不是特别灵活,用户体验不是很友好。下图是“查找”和“转到”窗口。

对于“调用层次结构”和“查找引用”等功能,更是少之又少了。选中某一个成员方法,只有“列出成员”、“转到定义”等一些功能,不能像Visual C++ 2010那样显示类之间的调用关系,仅仅是一个简单的罗列。如下图,选中成员方法的列出成员操作。

以上,简单列举了VC++ 6.0相对于Visual C++ 2010在编辑环境方面的一些差异,无论从用户体验,还是从性能方面,Visual C++ 2010有着巨大的改进,VC++ 6.0是远远不能攀比的。

小结

通过以上五个方面的介绍,我们可以明确看出,在Visual C++ 2010版本中,微软真是绞尽脑汁的进行了一场翻天覆地的变化,给一直受到冷落的Visual C++一次重新崛起的机会。增强的IDE,不仅改善了效率,同时也改善了用户体验,这些增强能大大提高程序员们的开发效率,同时带来更高的代码生产力与开发、调试的便捷。Visual C++ 2010实现了我们目标:更优、更快、更便捷。

usidc5 2011-01-23 15:15

我们期待已久的Visual Studio 2010已经发布一个月了,相信在这一个月中,大家都已经通过各种途径下载并试用了Visual Studio 2010。我想问问大家,Visual Studio 2010给你的第一感觉是什么?
界面很酷!
速度很快!
带来很多新的语法特性!
.NET Framework 4.0带来很多新的内容。
Visual C++ 2010这次一定会革了Visual C++ 6.0的命!
没错,这些都是Visual Studio 2010给我们说带来的一份份大礼。上面这些说法,都只是从一个宏观的高度来概括Visual Studio 2010所带来的新特性,今天,我们将眼睛放近一点,戴个放大镜,来深入体验Visual Studio 2010这款全新的IDE。
忆苦思甜话Visual Studio

只有忆苦才能思甜。我们来回忆一下Visual C++ 2010之前那些“苦难”日子。从读大学开始,我就开始接触C++,那时候使用的是经典的Visual C++ 6.0,那时候的Visual C++ 6.0虽然对标准支持的不是很好,但是IDE的效率高,编译速度也很快,同时因为MFC的成熟,使得它得到了广泛的应用。然后开始工作,也一直从事跟 C++相关的开发,然后开始使用Visual C++ 2005和Visual C++ 2008这些新版本,这些版本虽然对C++标准的支持有所改进,单是IDE和编译器的效率明显不如Visual C++ 6.0,用它们做开发,不得不忍受它“蜗牛”般的速度。在我用Visual C++做开发的十年间,从最开始的Visual C++ 6.0,到现在的Visual C++ 2010,VisualC++的每一个版本我都或长或短地使用过。在Visual C++ 2010发布之前,虽然中间有Visual C++ 2005,Visual C++ 2008等多个中间版本发布,但是,这些版本都未能取代最经典的Visual C++ 6.0。正是这些经历,让我可以对这个新生的Visual C++ 2010有太多的期待。现在,Visual C++ 2010终于闪亮登场来到我们面前,她也不负众望,无论是对C++标准的支持还是IDE和编译器的效率,它都以卓越的风姿倾倒了无数C++开发人员。作为一个Visual C++老用户的我,真是内牛满面,不辜负我这么多年的期待啊。现在,我们就来对Visual C++ 2010做一个深度探索,看看她是如何让我们着迷的。

usidc5 2011-01-23 15:18

C++2010在c++语言里面增加了一个特殊的新特性,c++语言可以自动判别数据类型,
而无需跟以前的c++语言一样,需要先定义数据,再使用,c++编译器将自动识别数据类型,
给程序员带来了更多的灵活性与便捷!
auto这个关键字来自VC++ 6.0标准。在VC++ 6.0中它没有什么作用,C++ 0x中“借用”它来作为自动类型推演(automatic type deduction)。当auto出现在声明中时,它表示“请用初始化我的表达式类型作为我的类型”。数据类型可以在编译时推演, 有了auto关键字再也不用写又长又烦的代码了。
请见下列代码,基于vc++2010编译器编译成功,采用图的数据结构进行演示。



  1. #include "stdafx.h"
    #include <map>
    #include <vector>
    #include <string>
    #include <iostream>

    using namespace std;

    #ifdef UNICODE
        #define tcout wcout
    #else
        #define tcout cout
    #endif

    const vector< basic_string<TCHAR> >* PrintContents(const map<int, vector< basic_string<TCHAR> > >& theMap)
    {
        for each (auto m in theMap)
        {
            tcout << _T("Map element ") << m.first << _T(": ");
            for each(auto e in m.second)
            {
                tcout << _T("'") << e << _T("', ");
            }
            tcout << endl;
        }
        return NULL;
    }

    int _tmain(int argc, _TCHAR* argv[])
    {
        // / /定义一个图的数据结构,一个整数的字符串类型的字符串
        map<int, vector< basic_string<TCHAR> > > myMap;
        // 填充图数据
        vector< basic_string<TCHAR> > vec1;
        vec1.push_back(_T("string 1-1"));
        vec1.push_back(_T("string 1-2"));
        vec1.push_back(_T("string 1-3"));
        myMap[1] = vec1;

        vector< basic_string<TCHAR> > vec2;
        vec2.push_back(_T("string 2-1"));
        vec2.push_back(_T("string 2-2"));
        vec2.push_back(_T("string 2-3"));
        myMap[2] = vec2;

        // 输出图数据
        tcout << _T("Map contents:") << endl;
        for (map<int, vector< basic_string<TCHAR> > >::const_iterator citer = myMap.begin();
            citer != myMap.end(); ++citer)
        {
            tcout << _T("Map element ") << (*citer).first << _T(": ");
            for (vector< basic_string<TCHAR> >::const_iterator citer2 = (*citer).second.begin();
                citer2 != (*citer).second.end(); ++citer2)
            {
                tcout << _T("'") << (*citer2) << _T("', ");
            }
            tcout << endl;
        }
        tcout << endl;

        // 输出图数据采用自动类型判别
        tcout << _T("采用自动类型判别:") << endl;
        for (auto citer = myMap.begin(); citer != myMap.end(); ++citer)
        {
            tcout << _T("Map element ") << (*citer).first << _T(": ");
            for (auto citer2 = (*citer).second.begin(); citer2 != (*citer).second.end(); ++citer2)
            {
                tcout << _T("'") << (*citer2) << _T("', ");
            }
            tcout << endl;
        }
        tcout << endl;

        // 输出图数据采用自动类型判别(兼容 VC++ 2010)
        tcout << _T("自动类型判别:") << endl;
        for each (auto m in myMap)
        {
            tcout << _T("Map element ") << m.first << _T(": ");
            for each(auto e in m.second)
            {
                tcout << _T("'") << e << _T("', ");
            }
            tcout << endl;
        }
        tcout << endl;

        // 打印图数据使用函数指针
        const vector< basic_string<TCHAR> >* (*p)(const map<int, vector< basic_string<TCHAR> > >&) = &PrintContents;
        tcout << _T("Map contents using a function pointer:") << endl;
        p(myMap);
        tcout << endl;

        //打印 图数据借助自动类型输出使用函数指针
        auto f = &PrintContents;
        tcout << _T("Map contents using auto as a function pointer:") << endl;
        f(myMap);
        tcout << endl;

        return 0;
    }




usidc5 2011-01-23 15:19
VC++2010在c++语言里面增加了一个特殊的新特性,safeint是一种安全数据类型,
能够保证运算是安全的,使用安全数据类型能够够规避软件异常,以及软件测试检测的
常规性很多错误,具体安全数据类型的请见代码演示,
代码由vc++2010调试通过!备有详细的注释!

  1. #include "stdafx.h"
    #include <safeint.h>
    #include <iostream>


    using namespace std;
    using namespace Microsoft::Utilities;


    class CMySafeIntException : public SafeIntException
    {
    public:
    static void CMySafeIntException::SafeIntOnOverflow()
    {
    cout << "捕获SafeInt溢出异常!" << endl;
    }


    static void CMySafeIntException::SafeIntOnDivZero()
    {
    cout << "捕获SafeInt被零除!" << endl;
    }
    };


    int _tmain(int argc, _TCHAR* argv[])
    {
    while (1)
    {
    unsigned int a, b;
    cout << "输入前8位无符号整数: ";
    cin >> a;
    cin.ignore();
    cout << "输入第二个8位无符号整数: ";
    cin >> b;
    cin.ignore();


    // 添加两个变量
    cout << "添加两个数字的8位整数:" << endl;


    // 新增两个整数使用正常调用
    unsigned __int8 i1 = a;
    unsigned __int8 i2 = b;
    cout << "    标准运算,结果=";
    unsigned __int8 iResult = i1 + i2;
    cout << (int)iResult << endl;


    // 新增两个整数使用SafeInt对象
    SafeInt<unsigned __int8, CMySafeIntException> si1(i1);
    SafeInt<unsigned __int8, CMySafeIntException> si2(i2);
    cout << "    Using SafeInt objects, result=";
    SafeInt<unsigned __int8, CMySafeIntException> siResult = si1 + si2;
    cout << (int)siResult << endl;


    // 整数相除
    cout << endl << "整数相除:" << endl;


    // 两个整数正常除法
    cout << "     标准运算,结果=";
    if (i2 != 0) // Prevent a crash!
    {
    iResult = i1 / i2;
    cout << (int)iResult << endl;
    }
    else
    cout << "中止因为除以零." << endl;


    //两个整数除以使用SafeInt对象
    cout << "    使用SafeInt对象, 结果=";
    siResult = si1 / si2;
    cout << (int)siResult << endl;


    cout << endl << endl;
    }


    return 0;
    }






usidc5 2011-01-23 15:22
泛型编程(generic programming)关注于产生通用的软件组件,让这些组件在不同的应用场合都能很容易地重用。在c++中,类模板和函数模板是进行泛型编程极为有效的机制。
什么是临时对象?定义:当且仅当离开一段上下文(context)时在对象上执行的仅有的操作是析构函数时,一个对象被看成是临时的。这里上下文可能是一个表达式,也可能是一个语句范围,例如函数体。
创建、复制和销毁临时对象是vc++编译器干的最多的事情,但临时对象会降低性能.转移构造函数就是解决C++存在的不必要的复制问题的方法。
对象生成器对象生成器是一种函数模板,依据其参数产生新的对象。可以把它想象成泛型化的构造函数。有些情况下,欲生成的对象的精确类型很难甚至根本无法表示出来,这时对象生成器可就管用了。对象生成器的优点还在于它的返回值可以直接作为函数参数,而不像构造函数那样只有在定义变量时才会调用。移动构函数就是为了解决C++存在的不必要的复制问题的方法。
VC++2010在c++语言里面增加了一个特殊的新特性,转移构造函数,解决C++存在的不必要的复制问题的方法。


代码由vc++2010调试通过!备有详细的注释!



  1. #include "stdafx.h"
    #include <map>
    #include <vector>
    #include <string>
    #include <iostream>

    using namespace std;

    #ifdef UNICODE
        #define tcout wcout
    #else
        #define tcout cout
    #endif

    const vector< basic_string<TCHAR> >* PrintContents(const map<int, vector< basic_string<TCHAR> > >& theMap)
    {
        for each (auto m in theMap)
        {
            tcout << _T("Map element ") << m.first << _T(": ");
            for each(auto e in m.second)
            {
                tcout << _T("'") << e << _T("', ");
            }
            tcout << endl;
        }
        return NULL;
    }

    int _tmain(int argc, _TCHAR* argv[])
    {
        // / /定义一个图的数据结构,一个整数的字符串类型的字符串
        map<int, vector< basic_string<TCHAR> > > myMap;
        // 填充图数据
        vector< basic_string<TCHAR> > vec1;
        vec1.push_back(_T("string 1-1"));
        vec1.push_back(_T("string 1-2"));
        vec1.push_back(_T("string 1-3"));
        myMap[1] = vec1;

        vector< basic_string<TCHAR> > vec2;
        vec2.push_back(_T("string 2-1"));
        vec2.push_back(_T("string 2-2"));
        vec2.push_back(_T("string 2-3"));
        myMap[2] = vec2;

        // 输出图数据
        tcout << _T("Map contents:") << endl;
        for (map<int, vector< basic_string<TCHAR> > >::const_iterator citer = myMap.begin();
            citer != myMap.end(); ++citer)
        {
            tcout << _T("Map element ") << (*citer).first << _T(": ");
            for (vector< basic_string<TCHAR> >::const_iterator citer2 = (*citer).second.begin();
                citer2 != (*citer).second.end(); ++citer2)
            {
                tcout << _T("'") << (*citer2) << _T("', ");
            }
            tcout << endl;
        }
        tcout << endl;

        // 输出图数据采用自动类型判别
        tcout << _T("采用自动类型判别:") << endl;
        for (auto citer = myMap.begin(); citer != myMap.end(); ++citer)
        {
            tcout << _T("Map element ") << (*citer).first << _T(": ");
            for (auto citer2 = (*citer).second.begin(); citer2 != (*citer).second.end(); ++citer2)
            {
                tcout << _T("'") << (*citer2) << _T("', ");
            }
            tcout << endl;
        }
        tcout << endl;

        // 输出图数据采用自动类型判别(兼容 VC++ 2010)
        tcout << _T("自动类型判别:") << endl;
        for each (auto m in myMap)
        {
            tcout << _T("Map element ") << m.first << _T(": ");
            for each(auto e in m.second)
            {
                tcout << _T("'") << e << _T("', ");
            }
            tcout << endl;
        }
        tcout << endl;

        // 打印图数据使用函数指针
        const vector< basic_string<TCHAR> >* (*p)(const map<int, vector< basic_string<TCHAR> > >&) = &PrintContents;
        tcout << _T("Map contents using a function pointer:") << endl;
        p(myMap);
        tcout << endl;

        //打印 图数据借助自动类型输出使用函数指针
        auto f = &PrintContents;
        tcout << _T("Map contents using auto as a function pointer:") << endl;
        f(myMap);
        tcout << endl;

        return 0;
    }




usidc5 2011-01-23 15:24
Visual C++2010 编译参数的设置。主要通过IDE的菜单项Project->Settings->C/C++页来完成。我们可以看到这一页的最下面Project Options中的内容,一般如下:
/nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WIN
DOWS" /D "_AFXDLL" /D"_MBCS" /Fp"Debug/WritingDlgTest.pch" /Yu"st
dafx.h" /Fo"Debug/" /Fd"Debug/" /FD /GZ /c
各个参数代表的意义,可以参考Msdn.比如/nologo表示编译时不在输出窗口显示这些设置(我们可以把这个参数去掉来看看效果)等等。一般我们不会直接修改这些设置,而是通过这一页最上面的Category中的各项来完成。
1.General:
Warning level
用来控制警告信息,其中Level 1是最严重的级别;
Warnings as errors
将警告信息当作错误处理;
Optimizations
是代码优化,
可以在Category的Optimizations项中进行更细的设置;
Generate browse info
用以生成.sbr文件,记录类、变量等符号信息,
可以在Category的Listing Files项中进行更多的设置。
Debug info
生成调试信息;
None
不产生任何调试信息(编译比较快)
Line Numbers Only
仅生成全局的和外部符号的调试信息到.OBJ文件或.EXE文件,减小目标文件的尺寸
C 7.0- Compatible
记录调试器用到的所有符号信息到.OBJ文件和.EXE文件
Program Database
创建.PDB文件记录所有调试信息
Program Database for "Edit & Continue"
创建.PDB文件记录所有调试信息,并且支持调试时编辑
2.C++ Language:
pointer_to_member representation
用来设置类定义/引用的先后关系,一般为Best-Case Always表示在引用类之前该类肯定已经定义了
Enable Exception Handling
进行同步的异常处理
Enable Run-Time Type Information
迫使编译器增加代码在运行时进行对象类型检查
Disable Construction Displacements
设置类构造/析构函数调用虚函数问题
3.Code Generation:
Processor
表示代码指令优化,可以为80386、80486、Pentium、Pentium Pro,或者Blend表示混合以上各种优化。
Use run-time library
用以指定程序运行时使用的运行时库(单线程或多线程,Debug版本或Release版本),有一个原则就是,一个进程不要同时使用几个版本的运行时库。

Single-Threaded
静态连接LIBC.LIB库
Debug Single-Threaded
静态连接LIBCD.LIB库
Multithreaded
静态连接LIBCMT.LIB库
Debug Multithreaded
静态连接LIBCMTD.LIB库
Multithreaded DLL
动态连接MSVCRT.DLL库
Debug Multithreaded DLL
动态连接MSVCRTD.DLL库。连接了单线程库就不支持多线程调用,连接了多线程库就要求创建多线程的应用程序。

Calling convention
可以用来设定调用约定,有三种:__cdecl、__fastcall和__stdcall。各种调用约定的主要区别在于,函数调用时,函数的参数是从左到右压入堆栈还是从右到左压入堆栈;在函数返回时,由函数的调用者来清理压入堆栈的参数还是由函数本身来清理;以及在编译时对函数名进行的命名修饰(可以通过Listing Files看到各种命名修饰方式)。

Struct member alignment
用以指定数据结构中的成员变量在内存中是按几字节对齐的,根据计算机数据总线的位数,不同的对齐方式存取数据的速度不一样。这个参数对数据包网络传输等应用尤为重要,不是存取速度问题,而是数据位的精确定义问题,一般在程序中使用#pragma pack来指定。
4.Customize:
Disable Language Extensions
表示不使用微软为标准C做的语言扩展
Eliminate Duplicate Strings
主要用于字符串优化(将字符串放到缓充池里以节省空间),使用这个参数,使得
char *sBuffer = "This is a character buffer";
char *tBuffer = "This is a character buffer";
sBuffer和tBuffer指向的是同一块内存空间;
Enable Function-Level Linking
告诉编译器将各个函数按打包格式编译
Enables minimal rebuild
通过保存关联信息到.IDB文件,使编译器只对最新类定义改动过的源文件进行重编译,提高编译速度
Enable Incremental Compilation
同样通过.IDB文件保存的信息,只重编译最新改动过的函数
Suppress Startup Banner and Information Messages
用以控制参数是否在output窗口输出

5.Listing Files:
Generate browse info
的功能上面已经提到过。这里可以进行更多的设置。
Exclude Local Variables from Browse Info
表示是否将局部变量的信息放到.SBR文件中。
Listing file type
可以设置生成的列表信息文件的内容:Assembly-Only Listing仅生成汇编代码文件(.ASM扩展名)
Assembly With Machine Code
生成机器代码和汇编代码文件(.COD扩展名)

Assembly With Source Code
生成源代码和汇编代码文件(.ASM扩展名)
Assembly, Machine Code,and Source
生成机器码、源代码和汇编代码文件(.COD扩展名)
Listing file name
为生成的信息文件的路径,一般为Debug或Release目录下,生成的文件名自动取源文件的文件名。
6.Optimizations:
Maximize Speed
生成最快速的代码
Minimize Size
生成最小尺寸的程序
Customize
Assume No Aliasing
不使用别名(提高速度)
Assume Aliasing Across Function Calls
仅函数内部不使用别名
Global Optimizations
全局优化,比如经常用到的变量使用寄存器保存,或者循环内的计算优化,如:
i = -100;
while( i < 0 ){ i += x + y;}
会被优化为
i = -100;
t = x + y;
while( i < 0 ){i += t;}
Generate Intrinsic Functions
使用内部函数替换一些函数调用(提高速度
Improve Float Consistency
浮点运算方面的优化
Favor Small Code
程序(exe或dll)尺寸优化优先于代码速度优化
Frame-Pointer Omission
不使用帧指针,以提高函数调用速度
Full Optimization
组合了几种参数,以生成最快的程序代码
Inline function expansion
内联函数扩展的三种优化(使用内联可以节省函数调用的开销,加快程序速度):
Disable不使用内联;
Only __inline,仅函数定义前有inline或__inline标记使用内联;
Any Suitable,除了inline或__inline标记的函数外,编译器“觉得”应该使用内联的函数,都使用内联。
7.Precompiled Headers:预编译头文件的设置。使用预编译可以提高重复编译的速度。IDE一般将一些公共的、不大变动的头文件(比如afxwin.h等)集中放到stdafx.h中,这一部分代码就不必每次都重新编译(除非是Rebuild All)。
8.Preprocessor:预编译处理
可以定义/解除定义一些常量。Additional include directories,可以指定额外的包含目录,一般是相对于本项目的目录,如……\\Include.
连接参数的设置。主要通过IDE的菜单项Project->Settings->Link页来完成。我们可以看到这一页的最下面Project Options中的内容,一般如下:
/nologo /subsystem:windows /incremental:yes /pdb:"Debug/WritingDlgTest.pdb" /debug /machi ne:I386 /out:"Debug/WritingDlgTest.exe" /pdbtype:sept
Category中的各项设置
1.General:一些总体设置
可以设置生成的文件路径、文件名;连接的库文件;
Generate debug info,生成Debug信息到.PDB文件(具体格式可以在Category->Debug中设置);
Ignore All Default Libraries,放弃所有默认的库连接;
Link Incrementally,通过生成. ILK文件实现递增式连接以提高后续连接速度,但一般这种方式下生成的文件(EXE或DLL)较大;
Generate Mapfile,生成.MAP文件记录模块相关信息
Enable Profiling,这个参数通常与Generate Mapfile参数同时使用,而且如果产生Debug信息的话,不能用.PDB文件,而且必须用Microsoft Format。
2.Customize:这里可以进行使用程序数据库文件的设置
Force File Output ,强制产生输出文件(EXE或DLL);Print Progress Messages,可以将连接过程中的进度信息输出到Output窗口。
3.Debug:设置是否生成调试信息,以及调试信息的格式
格式可以有Microsoft Format、COFF Format(Common Object File Format)和Both Formats三种选择;Separate Types,表示将Debug格式信息以独立的.PDB文件存放,还是直接放在各个源文件的.PDB文件中。选中的话,表示采用后者的方式,这种方式调试启动比较快。
4.Input:这里可以指定要连接的库文件,放弃连接的库文件
还可以增加额外的库文件目录,一般是相对于本项目的目录,如..\Lib。Force Symbol References,可以指定连接特定符号定义的库。
5.Output:Base Address可以改变程序默认的基地址(EXE文件默认为0x400000,DLL默认为x10000000),操作系统装载一个程序时总是试着先从这个基地址开始
Entry-Point Symbol可以指定程序的入口地址,一般为一个函数名(且必须采用__stdcall调用约定)。一般Win32的程序,EXE的入口为WinMain,DLL的入口为DllEntryPoint;最好让连接器自动设置程序的入口点。默认情况下,通过一个C的运行时库函数来实现:控制台程序采用mainCRTStartup (或wmainCRTStartup)去调用程序的main (或wmain)函数;Windows程序采用WinMainCRTStartup (或 wWinMainCRTStartup)调用程序的WinMain (或 wWinMain,必须采用__stdcall调用约定);DLL采用_DllMainCRTStartup调用DllMain函数(必须采用__stdcall调用约定)。Stack allocations,用以设置程序使用的堆栈大小(请使用十进制),默认为1兆字节。Version Information告诉连接器在EXE或DLL文件的开始部分放上版本号。
值得注意的是,上面各个参数是大小写敏感的;在参数后加上“-”表示该参数无效;各个参数值选项
有“*”的表示为该参数的默认值;可以使用页右上角的“Reset”按钮来恢复该页的所有默认设置。
其它一些参数设置
1.Project->Settings->General
可以设置连接MFC库的方式(静态或动态)。如果是动态连接,在你的软件发布时不要忘了带上MFC的DLL。
2.Project->Settings->Debug
可以设置调试时运行的可执行文件,以及命令行参数等。
3.Project->Settings->Custom Build
可以设置编译/连接成功后自动执行一些操作。比较有用的是,写COM时希望IDE对编译通过的COM文件自动注册,可以如下设置:
Description: Register COM
Commands: regsvr32 /s /c $(TargetPath)
echo regsvr32 exe.time > $(TargetDir)\$(TargetName).trg
Outputs: $(TargetDir)\$(TargetName).trg
4.Tools->Options->Directories
设置系统的Include、Library路径。
一些小窍门(针对Visual C++)
1.有时候,你可能在编译的时候,计算机突然非法关机了(可能某人不小心碰了电源或你的内存不稳定等原因)。当你重启机器后打开刚才的项目,重新进行编译,发现IDE会崩掉。你或许以为你的编译器坏了,其实不然(你试试编译其它项目,还是好的!),你只要将项目的.ncb、.opt、.aps、.clw文件以及Debug、Release目录下的所有文件都删掉,然后重新编译就行了。
2.如果你想与别人共享你的源代码项目,但是把整个项目做拷贝又太大。你完全可以删掉以下文件:.dsw、.ncb、.opt、.aps、.clw、. plg文件以及Debug、Release目录下的所有文件。
3.当你的Workspace中包含多个Project的时候,你可能不能直观地、一眼看出来哪个是当前项目。可以如下设置:Tools->Options->Format,然后在Category中选择Workspace window,改变其默认的字体(比如设成Fixedsys)就行了。
4. 如何给已有的Project改名字?将该Project关掉。然后以文本格式打开.dsp文件,替换原来的Project名字即可。
5.VC6对类成员的智能提示功能很有用,但有时候会失灵。你可以先关掉项目,将.clw和.ncb删掉,然后重新打开项目,点击菜单项View->ClassWizard,在弹出的对话框中按一下“Add All”按钮;重新Rebuild All。应该可以解决问题。

usidc5 2011-01-23 15:26

随着微软Visual Studio 2010 Ultimate Beta2版本的发布,除了它提供协同一致的ALM(应用程序生命周期)管理工具外,MSF for Agile Software Development过程框架从4.2升级到5.0,并且是以Scrum模型为基础导向扩展,并且结合了VSTS2010工具的众多特性,从而成为微 软.NET相关技术人员手中不可多得的利器。
在本文中,笔者将介绍Visual Studio 2010 Ultimate Beta2版本中的MSF for Agile Software Development V5.0的Scrum思想以及实施方法,通过对这些内容的阐述,让读者了解VSTS2010的敏捷之道,以便于.NET管理和开发人员能随心所欲的应用在 自己的项目中,从而构建出高效的软件开发团队。
1.引言
道 是天地万物演变的本体或本原,是存在之根本。一个行业或者一个事物既然现实地存在着,那么它的发展必然遵循着本身的自然规律。
谈起敏捷 之道,令笔者不禁想起在《笑傲江湖》中描写令狐冲独孤九剑的精髓行云流水,任意所至。这就是活学活用,实战中随手配合招式的变招。风清扬教令狐冲将 这华山派的三四十招融会贯通,设想如何一气呵成,然后全部将它忘了,忘得干干净净,一招也不可留在心中。其实是将华山剑法一招一式固有的套路动作拆开使 它不存任何招数,再自由组合套路形成浑然一体的招式使出来。这都是活学活用,而这只是第一步。做到出手无招,才是真正踏入了高手的境界。真正的无招是没有 主观的招式,根本并无招式,敌人如何来破你的招式?
软件开发的敏捷之道也是如此,当开发团队为了求得高质量、高效的完成软件产品的交互 过程,无论项目管理者还是团队成员都需要全方面地学习,包括工具的熟练使用、学习UML、OOAD等技术和收集前人开发过程中的经验等等,从而使个人以及 团队综合素质的大大增强,这就是为学的过程,最后把这些零碎无序的知识系统化后再全部统统忘掉,达到出手无招、随心所欲,全是下意识自然而然的行动, 无变之变,这就是敏捷之道,这可能就是做项目管理及开发的最高境界吧!
敏捷的含义就是速度的最大化。当你咖啡杯从你的手中悄然滑落的时 候,你却下意识地接到了它,这种直线运动是最快的,其实里面蕴藏着一种意境和思想。这种下意识就是一种境界思维,它没有经过大脑,条件反射的方式以最短最 快的速度取得了结果。
这种现象又让笔者又联想起了李小龙的截拳道,它的一个特点就是充分运用节约的经济线(两点间的直线)的技 击原理,所以它打击对方的机会和实用性最佳,而且最快,这种下意识的境界就是一种太极哲理,搏击之最高境界。万物皆有道,这都是从道的本体中演化出来 的!
2.敏捷之简易
简单通常是一个好的设计具备特征,这些设计是经典的并且很难再改进的。 例如,Lego积木(参考图1所示),经过许多年还保留着原来的样子,因为没有人能想出更简单的设计让人们将木块组合再拆开。人们无法再改进这些设计,因 为它们不能够再简化,而将它们设计得更复杂也无法让它们更好用。

图1 Lego 积木
敏捷团队注重简易,这样做可以消除那些没必要的复杂。只需专注于开发当前所 需要的功能和最简单的设计。如果能使用简单来帮助一个敏捷团队开发出马上就需要的软件,而不浪费人力和资源,这就是他们给那些投资的用户以最好和最直接利 益的方法。

我们再从《易经》中的简易、变易、不易的角度思考,可以把它看做是对易理的高度抽象易理对宇宙的高度抽象 简易指变与不变都是道的体现,自然而然而非刻意求变,万事万物都只是按其本性生生不息而已。所以,简易之理是对大自然万事万物高度的抽象;变 易是指变化,任何生生不息都是处在不断的变化之中,没有停止过,宇宙中的万物没有一样东西是不变的;不易是指万事万物的变化都有其不变的本 性,同时又有当变则变、不当变则不变的含义。宇宙中万事万物虽然不断变化着,但是却有一项永远不变的东西存在,就是能变出万事万物的那个东西,是 永恒存在的,中国传统哲学里称之为道。
2001年2月由17位世界轻量级方法学家提出了一份敏捷联盟宣言,这个宣言只是简单的四 句话,但却是敏捷方法的精髓,也是对敏捷的高度抽象,这便是敏捷之道的最高境界:
个体与交互 胜过 过程与工具
可以 工作的软件 胜过 面面俱到的文档
客户协作 胜过 合同谈判
响应变化 胜过 遵循计划
3.Scrum 敏捷过程模型
在Visual Studio 2010中,项目过程模板变化很大,微软把Scrum作为基本Agile开发模型(Scrum模型为基础参考导向),如图2所示。TFS2010中集成了 MSF for Agile Software Development v5.0,可操作性上又融合了敏捷等软件开发流程思想模型。
Scrum最初的含义是英式橄榄球争球队,是敏捷软件开发模型中的一种。Scrum 将软件开发团队比拟成橄榄球队,有明确的最高目标,熟悉开发流程中所需具备的最佳技术,具有高度自主权,紧密地沟通合作,以高度弹性解决各种挑战,确保每 天、每个阶段都明确的朝向目标推进。Scrum令人痛苦之处就在于你不得不根据自己的具体情况来对它进行调整,如果能够随心所欲应变,那么你就会体会 到它的强大。

图2 Scrum for Agile
敏捷Scrum开发过程框架中,产品backlog是 Scrum的核心,也是一切的起源。从根本上说,它就是一个需求、或故事、或特性等组成的列表,按照重要性的级别进行了排序。它里面包含的是客户想要的东 西,并用客户的术语加以描述,通常叫它故事(story),有时候也叫做backlog条目。
例如,我们建立一个产品 BACKLOG(示例),如表1所示。

表1 产品 BACKLOG(示例)
我们的故事包括这样一些字段:
ID:统一 标识符,就是个自增长的数字而已,以防重命名故事以后找不到它们。
名称(Name):简短的、描述性的故事名。它必须要含义明确,这样 可以跟其他故事区分开。

重要性:(Importance):产品负责人评出一个数值,指示这个故事有多重要。例如:
20或100。分数越高越重要。避免优先级这个说法,因为一般说来优先级1都表示最高优先级,如果后来有其他更重要的东西就麻烦了。它的优先级 评级应该是什么呢?优先级0?优先级-1?
初始估算(Initial estimate):团队的初步估算,表示与其他故事相比,
完成该故事所需的工作量。最小的单位是故事点(story point),一般大致相当于一个理想的人天(man-day)。
如 何做演示(How to demo):它大略描述了这个故事应该如何在sprint 演示上进行规范,本质就是一个简单的测试规范。
笔 者借鉴过很多敏捷书籍和在实战的应用中尝试过很多字段,但最后发现,只有上面提到的六个字段我们会一直使用下去,这也就是一种最简化。

我们可以把backlog存放在TFS2010服务器上,或者共享在TFS2010的 Excel或者Project(参考图3所示)文档里面,这是为了多个用户可以同时编辑它。

图3 在TFS2010中的Project Product Backlog模板
虽然正规意义上 这个文档应该归产品负责人所有,但是我们并不想把其他用户排斥在外,开发人员常常要打开这个文档,弄清一些事情,或者修改估算值。
VSTS2010已经支持Scrum的Product Backlog的模板,并且可以进行Backlog的迭代,如下图4所示。

图4 Product Backlog模板
打开Product Backlog,建立User Story,如图5所示。

图5 建立User Story

编写相关Story条目内容,如图6所示。

图6 编辑Story条目
当编写完Story条目内容后,我们可以在Web端的Project Portal查看user story的内容与条目,如图7和图8所示。

图7 打开Web端的Project Portal


图8 Project Portal显示条目

在share point的Project Portal中,我们可以对该story进行编辑等操作。如图9所示。

图9 share point站点中编辑条目
我们可以对表1进行扩展,如表2所示。

表2 产品 BACKLOG扩展
Backlog组件 ID Important Estimate How To Demo Notes
组件用处 事件的编号 事件的重要性,用一个分数来表示。分数越高越重要(但重要的事件,内容不一定多) 初始的估算,也就是完成某个事件所需要的工作量。 事件的简单测试 用简洁的语句进行注解、说明等。
Backlog组件 Track Components Requestor BugTrack
组件用处 对产品的分类 产品由哪些部份组成 记录最先提出的需求,并在后续的开发过程中进行反馈。 Bug跟踪
注:有颜色的组件可 以说是必需的!
在TFS2010中支持Reports的生成Excel报表,内容包括backlog、工作项等,如图10、11、12 所示。

图10 创建报表Excel


图11 选择创建报表Excel生产类型
生成报表,如图11所示。

图12 生成Excel报表
在Scrum敏捷框架中,最强的就是快速应对客户需求的灵活变化。 Scrum中有四个很标致性也很核心的词:backlog , sprint、迭代、反馈。结合VSTS2010的工具,可以快速进行story的变化,并且快速完成。例如,在产品 BACKLOG(参考表1),在每个Spint中,实现特性How To Demo,通过VSTS2010的Architecture绘制SSO统一登录的UML顺序(如图13所示),完成Spint Demo(可以是Spint中一部分)。

图13 绘制SSO统一登录的UML顺序
敏捷软件开发的核心是:使用项目行为的轻 量但足够的规则以及使用以人为本的规则及面向沟通的规则。Scrum的Sprint计划会议非常关键,应该算是Scrum中最重要的活动(这当然是我的 主观意见)。要是它执行的不好,整个sprint甚至都会被毁掉。

图14 TFS2010集成平台的开发项目的合作

举办Sprint计划会议,是为了让团 队获得足够的信息,能够在几个星期内不受干扰地工作,也是为了让产品负责人能对此有充分的信心。Sprint计划会议会产生一些实实在在的成果:
sprint目标。
团队成员名单(以及他们的投入程度,如果不是100%的话)。
sprint backlog(即sprint中包括的故事列表)。
确定好sprint演示日期。
确定好时间地点,供举行每日 scrum会议。

图15 Scrom敏捷过程管理
Scrom敏捷过程管理实施流程,如图15所示。将整个产品的 backlog分解成Sprint Backlog,这个Sprint Backlog是按照目前的人力物力条件可以完成的。召开sprint planning meeting,划分,确定这个Sprint内需要完成的任务,标注任务的优先级并分配给每个成员。注意这里的任务是以小时计算的,并不是按人天计算。进 入sprint开发周期,在这个周期内,每天需要召开Daily Scrum meeting。整个sprint周期结束,召开Sprint review meeting,将成果演示给Product Owner.团队成员最后召开Sprint retrospective meeting,总结问题和经验。这样周而复始,按照同样的步骤进行下一次Sprint.
最终结果是,每个Sprint都产生出一个可 见的、可用的交付产品,并向用户进行展示。一个增量可能是中期的,也可能是可交付的,但是它应该是独立的。 Sprint的目标是完成尽可能多的优质软件来确实质性进展,而不是用纸上里程碑(paper milestones)作为依据。
4.Scrum 索引卡(白板文化)
在大多数sprint 计划会议上,大家都会讨论产品 backlog中的故事细节。对故事进行估算、重定优先级、进一步确认细节、拆分,等等都会在会议上完成。敏捷开发中提倡建立物理索引卡。要想收到好的效 果,不妨创建一些索引卡,把它们放到墙上(或一张大桌子上)。
笔者在这里也有个扩展方法,可以制作电子版的索引卡,如图16所示。可以 清晰、直观的显示燃尽图和索引卡等信息。

ScrumDashboard是微软站点中的一个开源项目,最新版本 ScrumDashboard2.4.0.8,大家可以到http://scrumdashboard.codeplex.com/ 下载数据脚本以及源码。

图15 ScrumDashboard界面
5.总结
VSTS2010的增强的功能特点结合MSF for Agile Software Development V5.0中的Scrum敏捷过程框架,使从事在微软.NET技术相关工作方向的人们拥有了一把利剑。
写到此笔者不禁又想起了在《神雕侠 侣》中杨过得到的独孤求败的三柄剑:
利剑、重剑、木剑;
如果我们把微软VSTS2010工具,看成是敏捷开发团队 中,在不同阶段中所使用的剑,随着你的功夫和意境提高,你手中的利器就显着不重要了,无剑的境界便是最高的追求。敏捷有时也为灵感所致,如果敏捷团队 的人们能锻炼出这种境界,便是软件开发之最高境界,那就是敏捷之道了。所以,敏捷的开发团队也是讲究天人合一(团队敏捷意识合而为一),敏捷也是哲学的。
除了工具和Scrum外,令人忽视的就是团队成员的素质能力和意识。我在《我也能做CTO程序员职业规划》书中也讲过,如果公司团队人员始终保持不被开 除的水平,他就不能自动自发。天底下水是最自动自发地朝下流,但是你要让你的团队成员整体地自动往上走。例如,有目的、有计划,有要求的业绩,有期限,有 质量的标准。做到这些才仅仅是外因。

图16 内部驱动力雷达图
内因就是驱动员工愿意干事情,要有内在驱 动力。每个人敏感程度不同,给每个类型程序员的驱动力也不同。所有的员工自动自发的工作都是有内因的,(参见图16所示),扫描你的团队成员属于哪种类 型。例如,他是家庭感情型,你就可以在某个节日或者事件里到他家做客,体现领导对他的重视和认可。让家人觉得领导得好,家庭的力量对他施加自动自发的内因 驱动力。如果程序员是危机风险型,你就提供他创新的机会和平台,发挥他的最大内因驱动力等。当然,这都必须结合外因才会可度量、可操作、可监控和有目 标方向。

usidc5 2011-01-23 15:27
VS2010正式版马上就要发布了,从09年国庆节后开始使用VS2010 Beta2测试版,到现在也已4个月了,VS2010的的变化很大,但是给我带来比较大影响的反而是几个小的功能变革。
VS2010改变了我对WPF观念
在听说VS2010是WPF开发之前,我总觉得WPF由于要实现这么多绚丽的界面,在性能上肯定损耗的不少。在之前,由于对美好界面的渴望,我也自己学习过WPF,由于公司日常工作用不到WPF,也就是写写小程序玩玩,但是能用WPF来开发VS2010,在此之前我是无论如何都没有想到的,非常吃惊,这就是我当初听到VS2010要用WPF来开发的感受。在使用VS2010这么久后,VS2010测试版虽然有时候会时不时没有响应,但是它的速度,性能,一点都不比我装在同一台机子上的VS2008差。VS2010 RC 版据说解决了那些没有响应的问题,同时速度优化了很多,由于我要用到Silverlight 4 的开发,就没装 VS2010 RC 版,VS2010的正式版确实很值得期待。网上说 VS2010 RC 版对性能的改进体验非常深刻,参看:.NET 4 RC版 发布了 这篇博客。
代码智能提示的改进
.NET Framework 的函数库越来越强大,也越来越多,不是特长常用的,函数名确实难以记住,VS2008 开发环境的智能提示是根据方法或者属性的起始字母来选择的,如下图所示:


VS2010中则搜索的是包含搜索词的所有函数和属性。这样如下图所示,我们搜索 edit ,不仅仅可以搜索出 EditIndex,还可以搜索出字母中间带Edit的方法,属性,事件。


这样,那些我们没有精确记忆的属性和方法就会出现在智能提示中,对我们的编程非常方便实用。
有关这方面的内容你可以参看: VS 2010 和 .NET 4.0 系列之《VS 2010代码智能提示的改进》篇

导航和查询代码的改进
当我们阅读一个代码非常膨大,而不是又不是特别熟悉它的代码结构时,如何找到并定位代码,会是一个难题。这个功能VS2010新增的功能对我们非常有用。如下图:(Ctrl+逗号)的键盘快捷键就可以打开下面的“Navigate To(导航到)”对话框。在Search terms 中我们输入2个关键字:“cache action”,就可以搜索出包含这两个关键字的方法,类,属性,事件。这跟上面的智能提示一样,是包含,而不是以某个字开头。


有关这方面的内容你可以参看: VS 2010 和 .NET 4.0 系列之《在VS 2010中查询和导航代码》篇

鼠标滚轮滚动,对应字体大小的变化
这个功能对演示代码非常有帮助,比如公司内部,我在给大家演示一些代码时,由于现在的屏幕分辨率越来越大,我又习惯用最大的分辨率,这样稍稍离我远点的,就看不清楚编辑器的内容,以前我是在演示时,修改VS开发环境编辑器的默认字体大小,不演示了,再改回去,现在我不需要反复的改来改去,直接用鼠标中键滚轮来回滚动,就可以轻松实现字体的放大和缩小,非常实用,非常方便,我经常使用它。
使编程更容易;让我们对WPF更有信心。这就是我对VS2010的感觉。



本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
STL
map 自定义排序规则(通过定义函数对象)
map中自定义key排序函数
带你玩转Visual Studio——带你理解多字节编码与Unicode码
boost 学习笔记
浅谈构造函数 析构函数 虚析构函数
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服