1

在代码库中实现小的客户特定更改时,您如何处理以及有哪些最佳实践?

该特定产品被 10-20 位客户使用,并作为 Web 应用程序交付。当一个客户想要其他客户不想要或没有购买的特定功能时,我发现很难管理并且不会弄乱代码。

我已经查看了使用 if 语句解决此问题的早期代码:

if(customerId == Customer.One) {
 // code goes here...
}

或者

if(customer.hasThisSpecificFeature()) {
 // code goes here.
 }

这样做的问题是,当拥有多个特定功能时,它真的很难维护。代码不可读且难以调试。

有没有一个好的和干净的方法来解决这个问题?

4

2 回答 2

1

延伸阅读:策略模式模板方法模式控制反转(IoC)。

一种方法是提取必须倾听客户特定功能的逻辑并注入实现而不是将其烘焙到代码中。例如,使用一个接口:

public int GetAge(Person p)
{
    return p.Age;
}

一位客户想谎报年龄,因此要求您将所有年龄加 1:

public int GetAge(Person p)
{
    var age = p.Age;

    // Imagine all this exists...
    if (CustomerContext.CurrentCustomer == Customer.One)
    {
        age++;
    }

    return age;
}

这个想法是提取年龄的后处理:

public int GetAge(Person p, IAgePostProcessor ageProcessor)
{
    var age = p.Age;
    return ageProcessor.Process(age);
}

public interface IAgePostProcessor
{
    int Process(int age);
}

然后除此之外,当您知道您所处的客户环境时,您可以决定在启动时配置策略。

对于那个客户,您提供了一个年龄 +1 的实现,对于其他所有人,您提供一个什么都不做的传递实现。

您可以利用其他 DI/IoC 框架(Ninject、Castle Windsor、StructureMap)来帮助处理这些东西。


或者,您的“界面”可能只是Func<int, int>

public int GetAge(Person p, Func<int, int> postProcessAge)
{ 
    if (postProcessAge == null)
        postProcessAge = a => a; // Do nothing.

    return postProcessAge(p.Age);
}

这再次将依赖关系移到此方法之外,并允许您在其他地方对逻辑做出决定,也许在启动时集中一次。


所有方法的好处是,您可以独立于用于证明每个客户满足验收标准的客户特定实施进行测试。

于 2013-08-08T09:38:48.713 回答
0

我觉得开发人员应该远离客户特定的代码

如果您允许对您的产品进行自定义,则应该将自定义抽象出来,以便任何客户都可以更改自定义/功能的“设置”以进行特定安装。即使该功能是全新的,这也会为您的产品添加新功能,并且您希望让您的任何客户获得相同的好处。

这些自定义的设置应包含在配置文件或数据库表中。这允许任何客户使用您正在构建的功能,并允许每个客户根据他们的要求更改设置,而无需更改代码和重新部署。

它可能会提前做更多的工作,但可以防止您的代码库因每个客户的定制而变得混乱,并使对该功能的调整/调整变得更加容易。

于 2013-08-08T15:22:36.270 回答