Feature flags are a powerful tool in software development, allowing developers to enable or disable features in their applications dynamically. This can be particularly useful for continuous delivery, A/B testing, and managing the rollout of new features. In this blog, we will explore how to implement feature flags using Flipt, a self-contained feature flag solution, with Golang and gRPC. We will also delve into the benefits of using gRPC and how it can enhance internal communication and feature testing.

What is Flipt?

Flipt is an open-source, self-hosted feature flag application that allows you to run experiments across services in your environment. It is built with Go and uses gRPC for communication, making it highly performant and scalable. The UI is built with Vue.js, providing a clean and intuitive interface for managing feature flags. (Here is the link to the GitHub page of Flipt: https://github.com/flipt-io/flipt )

Key Features of Flipt

  • Feature flags allow you to enable or disable features without modifying the source code or requiring a redeploy. This can be done at runtime, giving you the flexibility to control feature visibility without code changes.

  • gRPC and REST APIs: Flipt supports both gRPC and REST APIs, allowing for high-performance and low-latency communication. This flexibility makes it easy to integrate with applications written in various languages.

  • Client-Side Evaluation: Flipt supports client-side evaluation, which reduces the number of requests to the server and improves performance. This is particularly useful for applications that require real-time feature flag evaluations.

  • GitOps Integration: Flipt is designed to integrate seamlessly with GitOps workflows, enabling continuous configuration and deployment. This ensures that feature flags are managed in a version-controlled manner, enhancing reliability and traceability. This is a reason alone to prefer Flipt because we are huge fans and longtime users of GitOps.

  • Security and Control: Flipt supports various authentication methods, including HTTPS, OIDC, JWT, OAuth, and API tokens. This ensures that your feature flags are secure and can be managed without exposing your systems to external risks.

  

What is gRPC?

gRPC is a high-performance RPC framework that allows for efficient communication between microservices. It uses Protocol Buffers (protobuf) as the interface definition language and message format. gRPC is designed to work well with large-scale systems and is used by companies like Google and Netflix.

As a platform engineer, you may want to use gRPC for internal communication between services because it provides a number of benefits, including:

gRPC's explicit versioning and non-breaking changes ensure compatibility between different service versions. By defining API contracts in .proto files, clients and servers can negotiate capabilities during the RPC connection handshake. This allows for seamless communication even with different versions or extensions. gRPC supports non-breaking changes like adding new services, methods, or fields, ensuring existing clients continue to function without updates. This backward compatibility reduces the need for client notifications and updates, making it easier to manage service evolution.

  • Improved performance: gRPC can help improve the performance of your services by reducing the overhead of serialization and deserialization.

  • Simplified error handling: gRPC provides a robust error handling mechanism that makes it easier to handle errors between services.

  • Improved security: gRPC provides built-in support for authentication and encryption, which can help improve the security of your services.

gRPC offers several advantages that make it well-suited for microservices architecture. Its high performance and low latency design are ideal for real-time applications. The framework supports load balancing and failover, ensuring efficient scalability. gRPC's multi-language support allows for seamless integration with various programming languages, while its efficient protobuf serialization reduces data transfer overhead, resulting in faster communication between services.

Implementing Feature Flags with Flipt Using Golang and gRPC 

(https://github.com/flipt-io/flipt/tree/main/sdk/go)

Step 1: Setting Up Flipt

To start using Flipt, you need to set up the server. You can do this by following the installation documentation provided by Flipt (https://docs.flipt.io/introduction). Once the server is up and running, you can manage your feature flags through the UI or via the REST or gRPC APIs.

Step 2: Creating a Golang Client

To integrate Flipt with your Golang application using gRPC, you need to generate the gRPC client. Flipt provides a pre-generated gRPC client for Go, which you can use directly.

Example Golang Client Code

package main

import (
	"context"
	"fmt"
	"log"

	flipt "go.flipt.io/flipt/rpc/flipt"
	"go.flipt.io/flipt/rpc/flipt/evaluation"
	sdk "go.flipt.io/flipt/sdk/go"
	fliptgrpc "go.flipt.io/flipt/sdk/go/grpc"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)

func main() {
	conn, err := grpc.NewClient("localhost:9000", grpc.WithTransportCredentials(insecure.NewCredentials()))

	if err != nil {
		log.Fatal("error while connecting: ", err)
	}
	defer conn.Close()

	transport := fliptgrpc.NewTransport(conn)

	sdk := sdk.New(transport)

	// For boolean flags
	fliptClient := sdk.Flipt()
	flag, err := fliptClient.GetFlag(context.Background(), &flipt.GetFlagRequest{
		// NamespaceKey: "my_namespace", // optional - uses the default namespace
		Key: "test",
	})
	if err != nil {
		log.Fatalf("error in fetching flag: %v", err)
	}

	fmt.Println("Flag name: ", flag.Name)

Step 3: Integrating Feature Flags into Your Application

Once you have the gRPC client set up, you can integrate feature flags into your application. This involves calling the EvalFlag method to determine whether a feature should be enabled or disabled for a given user.

Example Integration

package main

import (
	"context"
	"fmt"
	"log"

	flipt "go.flipt.io/flipt/rpc/flipt"
	"go.flipt.io/flipt/rpc/flipt/evaluation"
	sdk "go.flipt.io/flipt/sdk/go"
	fliptgrpc "go.flipt.io/flipt/sdk/go/grpc"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)

func main() {
	conn, err := grpc.NewClient("localhost:9000", grpc.WithTransportCredentials(insecure.NewCredentials()))

	if err != nil {
		log.Fatal("error while connecting: ", err)
	}
	defer conn.Close()

	transport := fliptgrpc.NewTransport(conn)

	sdk := sdk.New(transport)

	// For boolean flags
	fliptClient := sdk.Flipt()
	flag, err := fliptClient.GetFlag(context.Background(), &flipt.GetFlagRequest{
		// NamespaceKey: "my_namespace", // optional - uses the default namespace
		Key: "test",
	})
	if err != nil {
		log.Fatalf("error in fetching flag: %v", err)
	}

	fmt.Println("Flag name: ", flag.Name)

	// For variant flags
	evaluationClient := sdk.Evaluation()
	variantFlag, err := evaluationClient.Variant(context.Background(), &evaluation.EvaluationRequest{
		// NamespaceKey: "my_namespace",
		FlagKey:  "Color",
		EntityId: "my_entity_id",
	})

	if err != nil {
		log.Fatalf("error in fetching variant flag: %v", err)
	}
	fmt.Println("Variant name: ", variantFlag.FlagKey) 
}

Adding features in application (feature testing)

Feature testing is the process of testing new features in your application before they are released to production. This can be done using a variety of techniques, including:

  • Canaries: deploying a new feature to a small percentage of users to test its performance and behavior.
  • A/B testing: deploying two versions of a feature to different groups of users to compare their performance and behavior.
  • Feature flags: using feature flags to enable or disable features in your application, and testing their performance and behavior.

By using feature flags, you can test new features in your application without affecting the user experience. You can also use feature flags to roll back features if they are not performing well. 

What is OpenFeature?

OpenFeature is a CNCF (Cloud Native Computing Foundation) Sandbox project aimed at developing an open standard for feature flag management. It provides a unified API and SDK, allowing for a developer-first, cloud-native implementation with extensibility for open-source and enterprise use cases.

Flipt's OpenFeature provider offers a standardized and extensible way to manage feature flags. It integrates with Flipt's feature flags using the OpenFeature API, supporting both HTTP(s) and gRPC transports. The provider ensures compliance with the OpenFeature specification and includes hooks for custom actions. This integration benefits users by providing a standardized approach, fostering community-driven development, and simplifying integration with existing applications.

Community and Support

Flipt encourages community involvement and support for its OpenFeature integration. Users can reach out through Discord or email for feedback, to request specific language support, or to learn more about how Flipt can help their organization with feature flags.

Flipt's support for OpenFeature enhances its feature management capabilities by providing a standardized, extensible, and developer-friendly way to manage feature flags, aligning with the principles of cloud-native and DevOps practices.

Conclusion

Implementing feature flags with Flipt using Golang and gRPC offers a robust and scalable solution for managing the rollout of new features, conducting A/B testing, and ensuring continuous delivery. Flipt's use of gRPC ensures high-performance and low-latency communication, while its support for both gRPC and REST APIs enables easy integration with various applications. The client-side evaluation feature reduces server load, and GitOps integration enhances reliability and traceability. Flipt provides robust security measures and simplified error handling. 

However, setting up Flipt and managing code complexity are initial challenges. Ensuring scalability and properly managing toggle configuration are also crucial considerations.