DEV Community

Matheus de Camargo Marques
Matheus de Camargo Marques

Posted on

Are Feature Flags Bullsh*t? Why Your "IF" is Killing Performance (and the Planet)

Are Feature Flags Bullsh*t? Why Your "IF" is Killing Performance (and the Planet)

My name is Matheus de Camargo Marques. I’m not sure how my last article relates to this one; all I know is that a lot of time has passed and much has changed.

Let’s start at the beginning. How I arrived at this conclusion isn't the point right now. For years, I’ve been studying Computable Cognitive Architectures alongside Erlang, Elixir, and the Actor Model.

Recently, I remembered a professor named Simão, whose research focused on the Notification Oriented Paradigm (NOP). Back then, I didn't fully grasp it. I had read a little, and while I still don't claim to understand every detail today, I’ve begun to comprehend certain techniques that make immense sense—both in practice and in theory.

However, for something to be practical, we must be open to a paradigm shift: the thought process, the idea, the architecture, and the design—everything changes.

Where the Actor Model Meets NOP

During my research, I came across Fabio Negrini’s dissertation on NOPL Erlang-Elixir technology. My takeaway? This paradigm proposes the reduction of those redundant ifs in a system that don't make sense, allowing the execution flow to be as direct as possible.

You know the saying, "The answer is already no"? If the system already knows a condition is false, why re-evaluate that expression constantly?

The traditional implementation of Feature Flags introduces a silent technical debt: temporal redundancy. It is the repetitive re-evaluation of an expression whose result remains unchanged for long periods. The software "asks" the same question millions of times, receiving the same answer.

In Elixir, we are used to the Actor Model (isolated processes exchanging messages). But NOP brings "useful gossip" to the table:

  • In the Actor Model: A process sends a message saying "do this" (a command).
  • In NOP: A process shouts a Fact ("Hey, my state changed!"). Whoever is interested can take action.

The Elements of NOP

Imagine transforming "dead" code into a living network where components talk to each other only when necessary. The structure of NOP is based on a graph of collaborative entities:

1. Factual Entities (What the system "knows")

  • FBE (Fact Base Element): Represents an object or concept (e.g., a User or a Sensor).
  • Attributes: The properties (e.g., the flag status). When an attribute changes, it proactively notifies those who depend on it.

2. Logical-Causal Entities (What the system "does")

  • Premise: The smallest unit of decision. Unlike a common if, it only works when the Attribute notifies it: "Hey, I changed!"
  • Condition & Rule: These group premises together. If satisfied, they trigger an Action via Instigation.

In the imperative paradigm (Java, C#, etc.), the CPU must evaluate every if inside a loop to see what changed. In NOP, Premises are like stationary guards; processing only occurs at the "front line" where a change actually happened.


Hardware Sympathy: The Physical Cost of the "If"

Removing an if is a micro-architecture optimization. Modern processors use deep pipelines and speculative execution (Branch Prediction).

  • The Problem: An if forces the CPU to "guess" the path. If it guesses wrong, a Pipeline Flush occurs, discarding work and wasting energy.
  • Green Coding: NOP eliminates billions of useless micro-operations (Load, Compare, Jump). This is energy savings at data center scale.

The Implementation: Dynamic Compilation in Elixir

Using Elixir's metaprogramming (Code.compile_quoted) and the BEAM’s Hot Code Swapping, we can transform a configuration flag into a reactive recompilation. Instead of asking if a flag is active, the system is structurally altered to execute only the necessary code.

1. The Dynamic Compiler

This module generates the optimized version where the if is resolved during the "reactive recompilation" phase.

defmodule FeatureCompiler do
  def recompile_module(feature_enabled?) do
    # The 'if' is executed ONLY ONCE during recompilation.
    function_body =
      if feature_enabled? do
        quote do: NewPaymentProcessor.process(amount)
      else
        quote do: LegacyPaymentProcessor.process(amount)
      end

    module_ast =
      quote do
        defmodule PaymentProcessor do
          def process(amount) do
            unquote(function_body)
          end
        end
      end

    # Hot Swapping on the BEAM
    [{module, binary}] = Code.compile_quoted(module_ast)
    :code.load_binary(module, ~c"nofile", binary)

    {:ok, module}
  end
end

Enter fullscreen mode Exit fullscreen mode

2. The Notification Agent (FlagWatcher)

This implements the reactivity. Upon receiving an update, it triggers the compiler.

defmodule FlagWatcher do
  use GenServer

  def handle_cast({:update_flag, new_val}, _state) do
    # NOP Notification: Changed? Recompile!
    FeatureCompiler.recompile_module(new_val)
    {:noreply, new_val}
  end
end

Enter fullscreen mode Exit fullscreen mode

Benchmark: The Numbers Don't Lie

I ran tests comparing the traditional approach (runtime check) against the Dynamic NOP approach (Hot Swap):

  • Dynamic NOP (No If): 311.99 ips (average 3.21 ms)
  • Traditional Ifs (With If): 32.11 ips (average 31.14 ms)

The Result: The NOP-inspired approach was 9.72x faster.


Conclusion

The "Feature Flag is Bullsh*t" thesis is a warning against our own complacency. By applying NOP and the capabilities of the BEAM, we remove temporal and structural redundancy. We transform passive configurations into reactive architecture.

Software doesn't have to be a blind flow that asks the same question a billion times. It can be the exact manifestation of its current configuration. So, will you keep wasting CPU cycles, or will you let your system react only to what truly matters?


References:

Github: https://github.com/matheuscamarques/pon_feature_flag

Top comments (0)