dd-sdk-android icon indicating copy to clipboard operation
dd-sdk-android copied to clipboard

feat: Openfeature Provider implementation powered by DD Flags

Open typotter opened this issue 3 weeks ago • 2 comments

What does this PR do?

This PR adds a new OpenFeature provider module (dd-sdk-android-flags-openfeature) that integrates the Datadog Feature Flags SDK with the OpenFeature API, enabling developers to use standardized feature flag management while leveraging Datadog's observability platform.

Key components:

  • DatadogFlagsProvider: OpenFeature FeatureProvider implementation that adapts the OpenFeature API to Datadog's FlagsClient
  • Type Converters: Bidirectional conversion between OpenFeature Values and JSON types, preserving type information
  • Factory Methods: Three factory methods (create(), create(name), create(name, sdkCore)) for flexible provider instantiation, paralleling FlagsClient's create methods
  • Extension Function: FlagsClient.asOpenFeatureProvider() for convenient wrapping of existing clients
  • Static-Context Paradigm: Implements OpenFeature's static-context model with global context management

Motivation

Why OpenFeature Integration?

  1. Standardization: OpenFeature provides a vendor-neutral, community-driven specification for feature flagging
  2. Ecosystem: Enables integration with OpenFeature-compatible tools and libraries
  3. Migration Path: Allows customers to adopt OpenFeature API while using Datadog as the backend
  4. Multi-Vendor: Customers can switch between feature flag providers without code changes

Additional Notes

Architecture Decisions

Static-Context Paradigm

  • This provider implements the static-context paradigm per OpenFeature spec
  • Global context is set via OpenFeatureAPI.setEvaluationContext()
  • Per-evaluation (invocation) contexts are not supported - OpenFeature spec does not support invocation contexts in static-paradigm providers

Type Conversion Strategy

  • JSON → OpenFeature Value: Intelligent type promotion (e.g., Long within Int range becomes Value.Integer)
  • OpenFeature Value → JSON: Preserves type information (Integer→Int, Boolean→Boolean)
  • Null Handling: JSONObject.NULL sentinel values are converted to Value.Null
  • Special Values: Handles NaN, Infinity, nested structures, large collections

Error Handling

  • Specific exception catching (JSONException, ClassCastException, IllegalStateException)
  • Appropriate OpenFeature error codes (PARSE_ERROR, TYPE_MISMATCH, GENERAL)
  • Graceful degradation - returns default values on errors
  • Comprehensive logging for debugging

Thread Safety

  • Provider methods are thread-safe, delegating coordination to FlagsClient
  • No synchronization locks (upstream FlagsClient handles concurrency)

Implementation Details

Module Structure:

dd-sdk-android-flags-openfeature/
├── DatadogFlagsProvider.kt       # Main provider implementation
├── FlagsClientExt.kt             # Extension function
└── internal/adapters/
    ├── Converters.kt             # Context & error code converters
    └── ValueConverters.kt        # JSON ↔ OpenFeature Value converters

Test Coverage:

  • new unit tests

CI/CD Integration:

  • Added to detekt pipeline (:features:dd-sdk-android-flags-openfeature:customDetektRules)
  • Publishing configured (publish:release-flags-openfeature)
  • License compliance updated (Apache-2.0 for OpenFeature)

Known Limitations & Future Work

TODO FFL-1442: Implement observe() method for provider state observation

  • Requires upstream changes in flags module to expose FlagsClient state changes
  • Currently uses default implementation (returns empty Flow)

Manual Testing:

val provider = DatadogFlagsProvider.create()
OpenFeatureAPI.setProviderAndWait(provider)
val client = OpenFeatureAPI.getClient()
val isEnabled = client.getBooleanValue("my-feature", false)

Review checklist (to be filled by reviewers)

  • [ ] Feature or bugfix MUST have appropriate tests (unit, integration, e2e)
  • [ ] Make sure you discussed the feature or bugfix with the maintaining team in an Issue
  • [ ] Make sure each commit and the PR mention the Issue number (cf the CONTRIBUTING doc)

typotter avatar Nov 10 '25 18:11 typotter

Codecov Report

:x: Patch coverage is 47.23247% with 143 lines in your changes missing coverage. Please review. :white_check_mark: Project coverage is 70.86%. Comparing base (6c2f8ab) to head (ef411d2).

Files with missing lines Patch % Lines
.../android/flags/openfeature/DatadogFlagsProvider.kt 23.08% 81 Missing and 9 partials :warning:
...s/openfeature/internal/adapters/ValueConverters.kt 68.52% 12 Missing and 5 partials :warning:
.../flags/openfeature/internal/adapters/Converters.kt 57.14% 14 Missing and 1 partial :warning:
...in/kotlin/com/datadog/android/flags/FlagsClient.kt 0.00% 13 Missing :warning:
...atadog/android/flags/internal/FlagsStateManager.kt 86.36% 3 Missing :warning:
.../datadog/android/flags/internal/NoOpFlagsClient.kt 50.00% 2 Missing :warning:
...id/flags/internal/evaluation/EvaluationsManager.kt 93.33% 1 Missing :warning:
...lags/internal/repository/DefaultFlagsRepository.kt 0.00% 0 Missing and 1 partial :warning:
...om/datadog/android/flags/model/FlagsClientState.kt 83.33% 1 Missing :warning:
Additional details and impacted files
@@                   Coverage Diff                   @@
##           feature/flags-ofeat    #2998      +/-   ##
=======================================================
- Coverage                71.10%   70.86%   -0.24%     
=======================================================
  Files                      860      865       +5     
  Lines                    31311    31565     +254     
  Branches                  5275     5334      +59     
=======================================================
+ Hits                     22263    22368     +105     
- Misses                    7556     7673     +117     
- Partials                  1492     1524      +32     
Files with missing lines Coverage Δ
...atadog/android/flags/openfeature/FlagsClientExt.kt 100.00% <100.00%> (ø)
...tadog/android/flags/internal/DatadogFlagsClient.kt 88.41% <100.00%> (-1.30%) :arrow_down:
...id/flags/internal/evaluation/EvaluationsManager.kt 91.18% <93.33%> (+1.89%) :arrow_up:
...lags/internal/repository/DefaultFlagsRepository.kt 64.00% <0.00%> (-1.31%) :arrow_down:
...om/datadog/android/flags/model/FlagsClientState.kt 83.33% <83.33%> (ø)
.../datadog/android/flags/internal/NoOpFlagsClient.kt 93.10% <50.00%> (-6.90%) :arrow_down:
...atadog/android/flags/internal/FlagsStateManager.kt 86.36% <86.36%> (ø)
...in/kotlin/com/datadog/android/flags/FlagsClient.kt 35.59% <0.00%> (-2.59%) :arrow_down:
.../flags/openfeature/internal/adapters/Converters.kt 57.14% <57.14%> (ø)
...s/openfeature/internal/adapters/ValueConverters.kt 68.52% <68.52%> (ø)
... and 1 more

... and 37 files with indirect coverage changes

:rocket: New features to boost your workflow:
  • :snowflake: Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

codecov-commenter avatar Nov 10 '25 18:11 codecov-commenter

🎯 Code Coverage
Patch Coverage: 100.00%
Total Coverage: 71.03% (-0.22%)
View detailed report

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: ef411d2 | Docs | Datadog PR Page | Was this helpful? Give us feedback!