【问题标题】:code design for continuous integration持续集成的代码设计
【发布时间】:2011-04-28 03:26:11
【问题描述】:

在使用小型且经常提交的持续集成范例时,设计代码的最佳实践是什么?例如,给定一个大特征,如何将其分解为更小的部分?如何在旧的还活着的时候开发改进的功能。等等。

例如,可以使用“功能切换”,以便新功能在代码中处于休眠状态,直到准备就绪。

我感兴趣的领域语言是 Java/C# 等。

更新:请注意,我不是在问一般如何启用 CI。这样的答案妨碍了设置构建服务器、进行自动化测试等的需要。问题是如何设计代码,以便频繁、少量的提交工作。例如,所有测试都通过。在引入新功能和修改功能时都意味着。

【问题讨论】:

    标签: continuous-integration


    【解决方案1】:

    首先你要尝试遵守Open/Closed Principle

    来自维基百科:

    “这个想法是,一旦完成,类的实现只能被修改以纠正错误;新的或更改的功能将需要创建不同的类。该类可以通过继承重用原始类的编码。派生的子类可能与原始类具有相同的接口,也可能不同。”

    应用此技术,您最终会在代码库中同时存在该功能的两个版本。当您开始实现切换时,只需在运行时在两个版本的代码之间切换,可能会使用某种带有依赖注入的配置值。

    对于需要修改底层数据架构的代码更改,您可以设置一种“连续转换”,它可以在运行时在两个实现之间动态转换数据。来自 ebay 的 Randy Shoup 比我在 InfoQ 上的 Evolvable Systems 演讲中更好地解释了这一点。

    这些技术应该允许您对代码库进行较小的更改并更频繁地集成。

    我认为 Josh 提出的所有观点也有助于实现这一目标。无论采用何种技术来降低更改系统的风险,都可以让您以更快的速度工作。

    【讨论】:

      【解决方案2】:

      这将引发很多争论,但持续集成和 TDD 齐头并进。您需要的不仅仅是“它可以编译吗?”测试级别,以确保不断变化的代码是健壮的。

      如果您遵循高度的测试覆盖率,那么您推送的任何功能都将在构建中进行全面测试,然后才能被接受。这意味着您必须以一种允许您快速获取整个功能片段的方式进行编码,然后进行构建而不是构建。 (垂直切片)。

      这在代码方面是什么意思?

      你需要严重依赖Dependency Inversion Principle

      而不是这个:

      public class PersonService
      {
          private SqlDataAccess DataAccess = new SqlDataAccess();
      
          public void SavePerson(Person person)
          {
              DataAccess.SavePerson(person);
          }
      }
      

      你应该这样做:

      public class PersonService
      {
          private IDataAccess DataAccess {get; set;}
      
          public PersonService(IDataAccess dataAccess)
          {
              if(dataAccess == null)
                  throw new ArgumentNullException("dataAccess");
      
              DataAccess = dataAccess;
          }
      
          public void SavePerson(Person person)
          {
              DataAccess.SavePerson(person);
          }
      }
      

      这是一个简单的示例,但让您能够做出决定,例如在充实 UI 和主要功能的同时实现内存中的数据访问层。仍然可以编写测试,因为您可以模拟服务,并且您可以更快地推送功能,因为并非每个部分都必须 100% 存在。随着需求开始固化,您可以对数据访问做出更明智的决定,只需将临时组件替换为更永久的组件,而无需担心破坏现有代码。

      当然,您运行自动集成测试,以确保您不会破坏代码库的其余部分;)

      【讨论】:

      • 问题不在于如何为 TDD 编写代码,而在于 CI。例如,我有一个功能,所有测试都运行良好,现在我需要更改它。我怎样才能稍微改变它,以便该功能继续工作?
      • @IttayD - 这就是在新分支上工作应该发挥作用的地方。完成用户故事,对其进行测试,然后将其合并回主干/主干中,以便与您的 CI 服务器一起使用。
      • @IttayD - TDD 仅与我在回答中概述的整体设计相切相关。即使没有 TDD,该模式仍然是您能够轻松更改代码而不会破坏代码的最佳选择。但老实说,两者是齐头并进的。如果您需要以较小的增量更改某个功能并确保它继续工作,那么您应该做的第一件事是编写一个测试来覆盖那一小部分功能。构建足够的代码以使其工作,然后将其集成到您的构建过程中。您的构建机器应该运行所有这些测试以确保您的构建没有损坏。
      • @Lieven - 不在分支上工作与 CI 相矛盾?当您在分支中提交时,您并没有“不断地集成”
      • 总有一些时候,你的新 superduper 代码还没有准备好进入黄金时段,但你确实希望它处于版本控制之下。请注意,我说的是短暂的分支,最多几天。长寿的分支确实会与 CI 相矛盾。
      猜你喜欢
      • 1970-01-01
      • 2011-09-07
      • 2010-09-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-27
      • 2017-07-22
      相关资源
      最近更新 更多