科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件可重用代码的艺术

可重用代码的艺术

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

在整篇文章中,我们提供了关于代码组织的最佳实践,从桌面计算机编程借鉴来的全部风格,以及保持设备程序集始终最新的有用机制。是什么阻止您将移动应用程序看作重要的企业级解决方案?

作者:Jared Miniman 来源:MSDN 2007年9月1日

关键字: 可重用 代码

  • 评论
  • 分享微博
  • 分享邮件

简介

在内部代码管理的组织和在外部二进制文件的部署是在开发周期早期就应该被考虑的问题。本文的目的是强调一些可以应用到小型以及大型企业级应用程序的实用版本控制解决方案。这两个问题在移动开发领域内变得很关键,在该领域中,资源是稀缺的,而干净的代码就等同于有效率的、快速执行的代码。我们因而花费一些时间来解释可信计算如何应用到智能设备,以及您可以采取什么步骤来更好地保护您的代码。最后,我们将所有的理论结合在一个具有内置版本控制和更新的实际示例应用程序中。

智能设备和版本控制

一个易于使用且高度可自定义的工具 — Microsoft Visual Source Safe (VSS) — 允许开发小组(从一个人到数百人)对引入一个代码基或部署包的更改保持紧密的控制。任何类型的内容(从二进制文件到 XML 文档)都可以由 VSS 管理。不仅你们可以在小组成员间共享一个单独的项目或解决方案,在其他小组工作的其他小组成员也可以访问,而且如果赋予其足够的权限,他们可以修改您的代码基以及您的工作成果。因为任何添加到 VSS 的文件都在提供 VSS 服务的服务器上备份,所以如果需要,您始终可以回滚到一个先前的版本。任何小组成员都能看到他们有权限访问的文件的版本历史,在版本化文件间一行一行地比较差异,进行更改,或者在数据库中保存一个新的版本。

Visual Studio .NET 2003 中的版本控制

VSS 最新的更新 v6.0d 增加了 Visual Studio .NET 2003 集成,意味着只要您已经正确地管理了一个 VSS 数据库(参见此骤的产品文档),您就可以从 IDE 很容易地与数据库进行交互。我们假定我们已经打开了 IDE,而且系统管理员已经为我们创建了一个空的 VSS 数据库。我们选择小组领导的角色,这样我们可以添加我们认为适合的文件。从 Visual Studio .NET 的 Solution Explorer 中右键单击解决方案根,然后选择 Add Solution to Version Control。图 1 显示了用户从 Visual Studio .NET 2003 中将一个解决方案添加到 VSS。


图 1. 将解决方案从 Visual Studio .NET 2003 添加到 VSS

在本例中,我的数据库中没有任何文件,所以我将解决方案内的项目添加到数据库的根中。下一步您将看到所有文件已经被锁定并签入。作为一个提醒,签入主要意味着您已经放弃了修改一个文档的权利,并且该文档可以被其他小组成员自由签出以进行修改。图 2 显示了一个配置为通过 VSS 使用版本控制的解决方案。


图 2. 配置为通过 VSS 使用版本控制的解决方案

如果在任何时候您希望放弃自从签出后对文件做的更改,那么请右键单击该文件并选择 Get Latest Version 来覆盖您的更改。现在,如果您启动代码文件之一并试图做一个更改,系统将会提示您签出该文件或放弃您的更改,如图 3 所示。


图 3. VSS 的签出提示

一旦提示签出,就要为您的操作输入一个详细的注释。请注意,因为 VSS 为所有文件维护一个包括日期/时间戳的版本历史,所以没有必要在您的注释上附加一个日期或时间。Visual Studio .NET 2003 通过为您提供一个版本控制可停靠任务窗格来进一步显示其强大的功能,该任务窗格可以用来在其他小组成员可以访问整个代码基之前,监控需要被重新签入的文件。如图 4 所示,一旦您有文件签出,通过从 Solution Explorer 选择 Show Pending Checkins 也可以使用这个窗格。


图 4. Visual Studio .NET 挂起的签入任务窗格

我想要展示的最后一个功能(无须进入 VSS 提供的一些有趣的自定义)是,快速地在一个文件的标记版本(当您已经到达了某种里程碑并认为该版本将是未来所有工作的下一个基线,一个标签就被应用到您的代码基)或一个正常存档文件之间逐行比较差异的功能。您可以通过右键单击任何文件并选择 Compare Versions 访问这个功能。图 5 显示了出现的对话框。


图 5. 比较版本对话框

所有这种方便的 Visual Studio.NET 集成只不过是锦上添花。Visual Source Safe v6.0d 在记录开发工作方面是一种非常有用的工具,尤其在您的小组没有完全同地协作时。通过仔细地记录对您的代码基做出的所有更改,每个开发人员都被赋予了更大的责任来确保他或她的更改完全经过了组件及程序集测试,并且最终让您的解决方案不容易出错。

eVC v3.0/4.0 中的版本控制

以与您的托管代码相同的方式,您的本机代码可以从正确的版本控制获益。要将版本控制添加到一个本地项目,首先打开这个项目并展开 VCW (Visual C Workspace) 内的文件列表。图 6 显示用户将项目文件从 eVC 3.0/4.0 添加到一个 VSS 实例。


图 6. 将项目文件从 eVC 3.0/4.0 添加到一个 VSS 实例

与 Visual Studio .NET 2003 不同,在其中可以将文件自动递归添加到您的 VSS 实例,而这里您必须选择要包含在添加过程中的所有文件,如图 7 所示。


图 7. 添加到源控件对话框

下一步将要求您确认添加所选择的文件。您可以将单个文件保持为签出(例如,当您想将更改应用于共享代码基,但又希望为之后的版本继续工作时),或者只添加文件并强制自己在稍后签出。图 8 显示了用户将工作区/项目文件添加到 VSS 实例的结果。


图 8. 将工作区/项目文件添加到 VSS 实例的结果

一旦您的文件正确添加到了 Visual Source Safe,您就可以像使用 Visual Studio.NET 时一样签入/签出。如果您试图写入一个已签入文件,那么会要求您在做任何更改之前签出该文件。

 

智能设备和代码可维护性

尽管 Compact Framework 向经验丰富的桌面和服务器解决方案开发人员提供了围绕屏幕空间、内存可用性和有限处理能力的新挑战,但在开发过程自身方面,大多数概念都是从桌面扩展来的。在创建任何有价值的应用程序时,尽早从需求阶段就考虑应用程序在未来将如何使用,以及从未在早期阶段见过应用程序的新开发人员将如何在客户认为必须的地方创建功能并做出更改,这是至关重要的。当然,根本问题是代码的可维护性 — 这是大大小小的软件公司都在为之努力的事情。我愿意与您分享几条基本的指导原则,从而在您坐下来应对新的软件问题时引导您的思路。

命名约定

一个智能命名方案可以帮助您在最初看到应用程序时理解其逻辑。为代码中的命名组件提供一个抽象级,以便不会显示某些信息,例如一个函数是如何 工作的,而显示它是什么,这是很重要的。例如,在处理一个 Form 对象数组时,您可以使用一个名为 GetNextForm 而非 GetNextArrayItem 的函数。命名更像是一种艺术而不是科学,在足够清楚和过于冗长之间有一个艰难的平衡。有时,尽管有可能难以为人所理解,但更改一个变量名称来保持与编程语言标注的兼容是必要的。注意,以下内容是根据“命名约定”MSDN Library 桌面文档产生的,其中的元素对我们移动开发人员来说具有重要意义。

函数

决不要为函数或例程提供过于含糊不清的名称以至于会使它们不能捕获输出。例如,DoAnalysis() 可能是一个糟糕的选择。对于移动设备来说,WebService 调用是函数交互的一种常见形式,这是因为它们通常返回一个单个对象或基元,函数名称应该明确这一点。

在一个格式规范且正确使用了面向对象编程 (OOP) 的 Visual Basic .NET 或 C# 应用程序中,不要在属性、方法或函数中包含多余的类名称(如 AnimatedForm.FormCache(),而是使用 AnimatedForm.Cache())。通过避免函数中的冗余代码,这是一些可以很容易避免的事情,这在代码大小是关键因素时尤为重要。

使用后面跟有名词的操作来命名一个例程通常是很有帮助的 (FindGreatestInteger())。

如果您正在使用一种支持函数重载的语言,那么所有重载函数都做非常相似的工作是很重要的。否则,需要考虑重新命名这些函数以避免混淆。

为增强可读性,函数名称应该是使用 Pascal 大小写形式的 (MyFunctionName())。

变量

限制字母在应用程序中的使用。在类的顶部定义常量 (MAX_VALUE),或者如果客户在能够调整值时找到该值(参见下面的 ConfigReader),也可在一个独立的配制文件中定义该常量。

限制将无意义的计数器变量用于小的 for/while 循环或其他迭代结构,这是因为移动设备没有处理超过最基本递归的处理能力,迭代结构是很常见的。

布尔类型的变量应该包含单词“is”来表示一个 yes/no 值。

为增强可读性,函数名称应该是使用 camel 大小写形式的 (currentFormSize())。

为窗体控件赋予反映其类型的名称。例如 txtFirstName (用于包含第一个名称窗体的文本框,lblError 用于包含一个错误消息的标签,等等)。好的移动应用程序会在试图通过 RAPI、WebServices 和 RDA 调用远程服务之前在本地进行大量的基本验证。由于这类远程调用通过一个按每 KB GPRS 付费的连接发生,所以时间和金钱成本都很高。因此,您应该通过使用相应的控件名称来将事情简化。

使表名称保持其单数形式。

不要将表名称包含在字段名中(CarModelYear 在表 Car 中)。

不要在字段名中包含数据类型,这是因为之后对数据类型的更改需要额外的工作。

其他考虑事项

可以使用缩写,只要您保持一致且不将同一缩写用于多个概念。

尽量避免将相似的名称重复用于函数和变量(如函数 GenerateReceipt() 和名为 iGeneratedSales 的变量)。

注意拼写!很容易就会发生意外的拼写错误,并最终使流水线下游的开发人员产生迷惑。很多移动应用程序都是作为快速原型开始的。

文档

大多数开发人员都将代码文档视为一项杂务,不像设计精美的应用程序那样吸引人,而且因为智能设备应用程序跟与其相应的桌面应用程序相比在代码行数量上趋于更少,所以对于了解代码如何工作来说,注释看起来不是那么必需。但是,很容易理解为什么好的代码注释是很关键的:尽管外部文档可能是可用的(如设计文档、培训指南、版本历史记录等),但它们可能丢失或者与代码发布包是分开的。因此,代码注释应该从第一行开始就作为开发过程的一部分,而且保持与每个版本一起进行维护。即便有了一个出色的命名约定,在没有一点指导的情况下,代码也从不是百分之百可以理解的。稍后,我们将提醒您很容易将有用的注释加入您的代码,但在此之前,我们将讨论在编写注释时应该考虑的一些注意事项。

每个函数都应该以基础信息(例如,例程用途、输入假设、输出限制以及函数存在的主要原因)开始。还包括输入值(及类型)与输出值(及类型)的说明。

行尾注释可能难以读取,所以只有当您展开变量声明时才使用它们。确保将所有行尾注释在一个通用制表符结束处对齐。

避免将连字符和下划线用于一个注释块中的“框”。

保持您的注释干净:在代码交付以备后用之前,删除临时/无意义的注释。

如果您认为需要为特定的例程提供详尽的注释,您就需要改进变量命名,将函数拆分到若干辅助函数中,或者二者都进行。

使用正确的英语进行注释。注释的存在是为了便于理解,而不是为了带来混淆!

采取“现在编码,后面再注释”的态度会导致螺旋形下降。为什么不在此时函数逻辑在您头脑中还很清晰时花时间做这件事呢?

注释不应该是代码本身的伪代码,而应该是更高级的解释。

命名约定要与注释一致。使用一个所有编码人员都同意的相似样式。

注释 — 代码插入练习

由于 C# 语言提供很易懂的 XML 注释,关于他们为什么不应将其代码记入文档,C# 开发人员没有任何理由。产生后,C# 是唯一一种提供这种支持的语言,但是已经创建了一种方便的“powertoy”来在 Visual Basic .NET 下启用 XML,它叫做 VBCommenter PowerToy。在 C#中,XML 文档的添加是通过输入 3 个后面跟有 XML 格式注释的正斜杠来完成的。表 1 是我在智能设备应用程序中最常使用的标记的列表:

表 1. 智能设备应用程序常用标记。
标记 含义

<c>

给您一种方法来表明说明内的文本应被标记为代码。使用 <code> 来表明多行为代码。

<exception>

让您指定哪些异常会被引发。这个标记应用于一个方法定义。

/// Thrown when...

<param>

<param> 标记应该用在对方法声明的注释中,以描述该方法的参数之一。

/// <param name="Int1">Used to indicate status. </param>

<returns>

<returns> 标记应该用在对方法声明的注释中,以描述返回值。

<seealso>

<seealso> 标记让您指定您可能希望在 See Also 部分显示的文本。使用 <see> 从文本内指定一个链接。示例:

/// <summary> Some other method. 
 /// <seealso cref="SomeMethod(string)" > 
public int SomeOtherMethod()
{
return 0;
}

<summary>

应该用于描述一种类型或一个类型成员。

<value>

<value> 标记让您描述一个属性。注意,当您在 Visual Studio .NET 开发环境中通过代码向导添加一个属性时,它会为新属性添加一个 <summary> 标记。然后,您应该手动添加一个 <value> 标记来描述此属性表示的值。

当您创建一个新项目时,通常会在多个代码点为您插入“///”字符。您可以使用这些起始点来添加您的注释(IntelliSense 会试着为您推荐标记),但所有注释都必须使用格式规范的 XML,否则编译器会拒绝您的要求。让我们以一个干净的类开始,并定义一个不太重要的函数。

      private void computeSum(int i, int j)   
      {
      }

当您只是在第一行上方键入“///”并键入空格时,IntelliSense 会真的显示出来。看看 IntelliSense 显示什么:

      /// <summary>
      /// </summary>
      /// <param name="i"></param>
      /// <param name="j"></param>
      private void computeSum(int i, int j)   
      {
      }

这很容易!快速而不费力地将 XML 记入文档是 Visual Studio .NET 2003 优于文本编辑器的众多长处之一。现在我们已经很好地注释了代码,那么我们余下的开发工作会从中得到什么好处呢?IntelliSense 不断帮我们解决难题!当我填入上面的 summary 和 param属性时,看看 IntelliSense 弹出什么。

当您滚动到这两个参数时,它们也会将其类型和用途在 IntelliSense 输出中显示出来,如图 9 所示。


图 9. IntelliSense 对于您已经记入文档的函数或变量很奏效

注释 — 生成 XML 输出

用 XML 可以完成的很多有趣的事情之一是高可用的代码文档。在本节中,我们花费一些时间来说明如何利用一些 Visual Studio .NET 功能来消除手动创建文档的需要 — 如果操作正确,上述任务都可以用 IDE 来处理,从而为您节约宝贵的时间。使用上面的属性,您可以非常容易地生成看上去很专业的代码指南,可以承载如您所想要的数量的详细信息。正如您所预料到的,实际的 XML 文档对人眼来说并不是非常有用,但是,.NET 附带一种机制,通过它您可以将格式设置应用于 XML 并生成 HTML 文档。我们假设,我们有正确记入档案的项目并打开了 Visual Studio .NET。在默认情况下,智能设备应用程序在生成结果中不包括 XML 输出。让我们看一下如何逐步启用 XML 输出。右键单击您的项目并选择 Properties。现在选择 Project NameProperty Pages 对话框中的 Configuration Properties 文件夹,如图 10 所示。


图 10. 配置项目以生成一个 XML 文档文件。单击缩略图查看大图像。

一旦将 XML 文档启用为创建和部署过程的一部分,当函数错过正确的注释时您会接到警告,而且如果您的 XML 语法是无效的,您会一直收到一个编译时错误,了解这些是很重要的。XML 旅程的最后一步是创建一个在代码移交时值得检查的可交付版本。转到 Tools,然后选择 Build Comment Web Pages in Visual Studio .NET,出现图 11 中的对话框。


图 11.在 Visual Studio .NET 中创建注释 Web 页对话框

注意您可以为解决方案中的单个或所有项目创建文档。指定一个 HTML 输出路径,无论您希望将 HTML 标记嵌入到文档中(如果您的小组成员之一在属性中嵌入了一个有问题的链接,这可能会是一个安全风险),还是希望将文档添加到 Internet Explorer 收藏夹中。现在您的文档将会出现,并且您的解决方案将被项目分解,如图 12 所示。


图 12. 生成的 HTML 文档

毫无疑问,关于为什么您的代码没有详细的注释,Visual Studio .NET 的设计人员真的没有提供任何理由。IntelliSense 为您做了大量枯燥的工作,并且您可以从其他开发人员良好的注释实践中获益,其中有用的 IntelliSense 标记会在您继续访问其工作时出现。

 

智能设备和可信计算

强名称程序集简介

尽管您可能编写一个在断开了连接,且从不与同步提供程序(更不要说互联网)交互的 Pocket PC 上的应用程序,采取适当的措施确保代码的安全应该始终是高优先级的。作为在 .NET Framework 下生成的所有代码的生成块,程序集为正确的版本控制、重新使用和安全权限作准备。程序集还为公共语言运行库 (CLR) 提供其所需的所有信息以正确地执行使用给定程序集的应用程序。

由于程序集后面的许多概念都与完整的 .NET Framework 相同,本文并不旨在解释程序集的详细信息,而是解释如何将安全性应用于智能设备应用程序。首先,我们将提供使用安全程序集的动机,然后提供必要的步骤以确保您所生成的代码中具有正确的应用程序安全性。

在一个连接完善的企业网中,确保操作敏感数据的 PDA 正在运行“安全的”代码是极为重要的,这意味着代码是由经授权的个体部署的,并且没有被篡改。您的软件可能是通过无线或其他 Internet 连接安装的,谁能说没有人进入您的文件共享并用假的 DLL 替换了您真正的 DLL?.NET 支持“强名称程序集”的概念,它为引用代码提供了一个保证 — 给定的程序集集是可以信赖的,没有被攻击或被操纵。简而言之,强名称程序集是一个用强(唯一)名称签名的程序集,由一个数字签名、区域性详细信息、一个公钥、版本信息以及该程序集的文本名称 (MyAssembly) 组成。使用这样一个程序集我们能获得什么?

强名称是一个唯一的名称。签名密钥对(在下面讨论)共同生成一个完全唯一的名称,而且由于没有人能够正确地重新创建两个密钥,因此没有人能够将其程序集装扮得与您的程序集一样。

应用程序的版本树是可信的。因为只有您才能为程序集的未来版本签名,因此可以确保用户以后的版本是源自您而非其他人。

程序集的内容或关联行为没有被篡改。

数字签名是通过由 NIST 和 NSA 一起开发的 Secure Hashing Algorithm v1.0(或 SHA1)实现的。哈希算法在单向上有用:一旦已算出,一个哈希值就不能被解密。这意味着如果两个程序集生成同一哈希值,那么确信无疑,这两个程序集是相同的。反之,则包含不同的哈希值。但是我们如何保证哈希值没有被篡改呢?数字签名创建是相当复杂的,但概念是简单的。使用了两个相关数字、一个私钥和一个公钥:数据用公钥加密,但必须用私钥解密。

首先,从程序集生成哈希值。接着,将哈希值用私钥加密,并与公钥一起存储在您考虑的程序集本身中。图 13 图示该过程。


图 13. SHA 为 SampleAssembly 生成程序集哈希。单击缩略图查看大图像。

强名称程序集签名

如上面所述,为了对程序集进行数字签名,我们必须有一个私钥和公钥对。可以使用一个名为强名称工具 (sn.exe) 的简单工具来协调密钥的创建。尽管我们将保护一个为移动设备设计的程序集,我们使用同一个在桌面上支持的的工具。由于这里没有新步骤要介绍,我们没有理由不为您的生产移动代码签名!(从“Start”菜单上的“Visual Studio .NET Tools”)运行 Visual Studio .NET 命令提示,并输入命令 sn â

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章