Skip to content

How to scale monolith?

Posted on:July 5, 2022 at 02:05 AM

🏆 How Feature Flags enable monolith agility❓❓

Feature flags, those dynamic conditional switches that can be swiftly altered, have emerged as a game-changer for modern software development. They empower developers to control the behavior of their applications without changing code, facilitating better testing, scalability, and a more agile development process. In this post, let’s delve deeper into how feature flags can be a game-changer for modular monolith architectures, and how they can enable efficient module management and enhanced scalability.

🔗 Dynamic Module Management with Feature Flags

In the world of modular monoliths, managing and evolving individual modules can be quite challenging.

This is where feature flags come to the rescue. By utilizing feature flags during application startup, you can dynamically enable or disable modules based on their respective feature flag states. This means that during initialization, you can make decisions on whether to register a particular module’s dependencies or skip them entirely.

🧪 Empowering Testing and Isolation

Feature flags play a pivotal role in enhancing your testing strategies. By enabling the isolation of modules, you can test them independently. This not only streamlines the testing process but also reduces the complexities of troubleshooting issues. Your development teams can focus on perfecting one module at a time without having to grapple with intricate dependencies or entangled code, they don’t have to setup configuration from others module and test only public interfaces or message consumers.

🌐 Scaling Strategically with Agility

Scaling modular monoliths can be a double-edged sword. Transitioning to microservices for the sake of scalability can introduce a slew of operational and architectural complexities. Feature flags provide an alternative avenue.

By enabling the dynamic activation of modules, you can selectively scale only the required parts of your application. This approach proves especially powerful when dealing with variable workloads, where some modules might require more resources than others.

Image description

As your project’s demands increase, feature flags let you scale the necessary modules while maintaining the overall cohesiveness of your monolith.

💡 When to consider extraction

While feature flags grant incredible flexibility, there might come a point when scaling via flags becomes cumbersome or leads to a convoluted codebase. If feature flag-based scalability starts to hinder development agility, it might be time to consider transitioning specific modules into microservices. However, this decision should be made judiciously, considering the added complexity and operational overhead associated with microservices architectures.

🔗 This is really simple!

Integrating feature flags into a .NET environment is remarkably uncomplicated. Through the installation and registration of the Microsoft NuGet package, you can effortlessly handle feature flag configuration.

// Define Module class
internal record Module(string Value)
{
    internal static readonly Module Offers = new("Offers");
    internal static readonly Module Passes = new("Passes");
    internal static readonly Module Reports = new("Reports");

    public static implicit operator string(Module module) => module.Value;
}

// Install Nuget Microsoft Feature Managment
// Register Microsoft Feature Managment
builder.Services.AddFeatureManagement();

// Create 'IsModuleEnabled' extension method
public static class ModuleAvailabilityChecker
{
  public static bool IsModuleEnabled(this IServiceCollection services, string module) => services.BuildServiceProvider().GetRequiredService<IFeatureManager>().IsEnabledAsync(module).Result;

  public static bool IsModuleEnabled(this IApplicationBuilder applicationBuilder, string module) => applicationBuilder.ApplicationServices.GetRequiredService<IFeatureManager>().IsEnabledAsync(module).Result;
}

// Use 'IsModuleEnabled' in your module registration
public static class PassesModule
{
    public static void RegisterPasses(this WebApplication app, string module)
    {
        if (!app.IsModuleEnabled(module)) return;

        app.UsePasses();
        app.MapPasses();
    }

    public static IServiceCollection AddPasses(this IServiceCollection services, IConfiguration configuration,
        string module)
    {
        if (!services.IsModuleEnabled(module)) return services;

        services.AddDataAccess(configuration);
        services.AddMediator(Assembly.GetExecutingAssembly());
        services.AddConsumers();

        return services;
    }

    private static IApplicationBuilder UsePasses(this IApplicationBuilder applicationBuilder)
    {
        applicationBuilder.UseDataAccess();

        return applicationBuilder;
    }
}

// Register Module
builder.Services.AddPasses(builder.Configuration, Module.Passes);
...
app.RegisterPasses(Module.Passes);
{
  "FeatureManagement": {
    "Contracts": false,
    "Offers": true,
    "Passes": false,
    "Reports": false
  }
}

🚀 In Conclusion

Feature flags are a dynamic force that can reshape the landscape of modular monoliths. By enabling dynamic control over module activation and deactivation, feature flags pave the way for more agile development, enhanced testing strategies, and strategic scalability. So, whether you’re looking to optimize your monolith or cautiously venture into microservices territory, feature flags can be your guiding light toward a more efficient and adaptable software architecture.