最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

orm - How to Apply Feature Flags in Domain Entities Without Adding Dependencies? - Stack Overflow

programmeradmin1浏览0评论

We use domain objects to encapsulate business logic. Sometimes, we need to change the behavior of an entity due to new system requirements. A common approach is to modify the method or property by adding an if statement that checks a feature flag:

public class Entity : IEntity
{
    public void SomeMethod() 
    {
        if (Feature.NewRequirement())
        {
            DoTheNewStuff();
        }
        else
        {
            DoTheOldStuff();
        }
    }
}

The feature flag determines when the new behavior should be enabled and allows us to turn it off if necessary. Typically, after the feature has been running in production for a few weeks or months, we remove the flag and keep only the new implementation.

Problems With This Approach

  • Feature Flag as a Static Dependency – The Feature class is static and depends on a cache holding the feature flag configuration. This makes unit testing difficult since shared state in tests can cause flakiness and prevent parallel execution.
  • Injecting the Feature Flag? – We could pass the feature flag as a constructor argument to Entity or as a method parameter, but we prefer to keep domain objects as pure as possible, without dependencies on infrastructure. Most of the time, entities are either created by an aggregate or fetched from a database via an ORM.

How can we make our domain entities behave differently based on feature flags while minimizing dependencies and avoiding static calls inside the entity?

We use domain objects to encapsulate business logic. Sometimes, we need to change the behavior of an entity due to new system requirements. A common approach is to modify the method or property by adding an if statement that checks a feature flag:

public class Entity : IEntity
{
    public void SomeMethod() 
    {
        if (Feature.NewRequirement())
        {
            DoTheNewStuff();
        }
        else
        {
            DoTheOldStuff();
        }
    }
}

The feature flag determines when the new behavior should be enabled and allows us to turn it off if necessary. Typically, after the feature has been running in production for a few weeks or months, we remove the flag and keep only the new implementation.

Problems With This Approach

  • Feature Flag as a Static Dependency – The Feature class is static and depends on a cache holding the feature flag configuration. This makes unit testing difficult since shared state in tests can cause flakiness and prevent parallel execution.
  • Injecting the Feature Flag? – We could pass the feature flag as a constructor argument to Entity or as a method parameter, but we prefer to keep domain objects as pure as possible, without dependencies on infrastructure. Most of the time, entities are either created by an aggregate or fetched from a database via an ORM.

How can we make our domain entities behave differently based on feature flags while minimizing dependencies and avoiding static calls inside the entity?

Share Improve this question asked Mar 13 at 15:50 DaggenDaggen 611 silver badge5 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 0

You can use the strategy pattern to encapsulate different behaviors based on the feature flag.

  • Interface

    public interface ISomeMethodStrategy
    {
        void Execute();
    }
    
  • Implementations

    public class OldSomeMethodStrategy : ISomeMethodStrategy
    {
        public void Execute() => DoTheOldStuff();
    }
    
    public class NewSomeMethodStrategy : ISomeMethodStrategy
    {
        public void Execute() => DoTheNewStuff();
    }
    
  • New domain entity with strategy

    public class Entity : IEntity
    {
        private readonly ISomeMethodStrategy _strategy;
    
        public Entity(ISomeMethodStrategy strategy)
        {
            _strategy = strategy;
        }
    
        public void SomeMethod() => _strategy.Execute();
    }
    

And then, before creating the entity, determine which strategy to use:

var strategy = featureService.IsNewRequirementEnabled() 
    ? new NewSomeMethodStrategy() 
    : new OldSomeMethodStrategy();

var entity = new Entity(strategy);

If you want avoid the static in domain object or injection in domain object, you can just have 2 methods differents (follow the rule of extensibility) to implement new and old feature, like :

public class Bar
{  
    public void DoNewFeature() 
    {
        // ...
    }

    public void DoOldFeature() 
    {
        // ...
    } 
}

And after you use a feature service to choose which method to use in your use case, like :

public class BarService(IFeatureFlagService feature)
{  
    public void DoSomething(int idBar) 
    {
        var myBar = this.GetById(idBar);
        if (feature.Enabled("barNew")
        {
            myBar.DoNewFeature();
        }
        else 
        {
            myBar.DoOldFeature();
        }
    } 
}

The feature flipping isn't a domain object rule, so it's better to have this in service.

发布评论

评论列表(0)

  1. 暂无评论