Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sample feature flagging system to next.js template #259

Merged
merged 42 commits into from
Dec 8, 2023
Merged

Conversation

aligg
Copy link
Contributor

@aligg aligg commented Dec 4, 2023

Changes

  • Add a service class for retrieving flags from evidently
  • Add example consuming the flags
  • Updated docs
  • tests

Context for reviewers

  • This is followup / related work alongside last week's platform infra changes.

Testing

  • I'd love some help testing this out against the platform infra.

Copy link
Contributor

@lorenyu lorenyu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, looks great! Left a high level comment on the architectural pattern

app/src/services/FeatureFlagManager.ts Outdated Show resolved Hide resolved
app/src/services/FeatureFlagManager.ts Outdated Show resolved Hide resolved
app/src/services/FeatureFlagManager.ts Outdated Show resolved Hide resolved
app/__mocks__/@aws-sdk/client-evidently.ts Outdated Show resolved Hide resolved
app/src/services/FeatureFlagManager.ts Outdated Show resolved Hide resolved
app/src/services/FeatureFlagManager.ts Outdated Show resolved Hide resolved
app/src/services/FeatureFlagManager.ts Outdated Show resolved Hide resolved
app/.env.development Show resolved Hide resolved
app/src/pages/index.tsx Outdated Show resolved Hide resolved
app/src/services/FeatureFlagManager.ts Outdated Show resolved Hide resolved
app/__mocks__/@aws-sdk/client-evidently.ts Outdated Show resolved Hide resolved
app/.env.development Show resolved Hide resolved
@aligg aligg requested a review from lorenyu December 7, 2023 00:18
sawyerh and others added 2 commits December 7, 2023 11:16
… into aligg/ff

# Conflicts:
#	app/src/pages/index.tsx
docs/feature-flagging.md Outdated Show resolved Hide resolved
docs/feature-flagging.md Outdated Show resolved Hide resolved
docs/feature-flagging.md Outdated Show resolved Hide resolved
docs/feature-flagging.md Outdated Show resolved Hide resolved
app/src/i18n/messages/en-US/index.ts Outdated Show resolved Hide resolved
app/src/pages/index.tsx Outdated Show resolved Hide resolved
app/src/pages/index.tsx Outdated Show resolved Hide resolved
app/src/services/feature-flags/FeatureFlagManager.ts Outdated Show resolved Hide resolved
app/src/services/feature-flags/LocalFeatureFlagManager.ts Outdated Show resolved Hide resolved
package-lock.json Outdated Show resolved Hide resolved
aligg and others added 9 commits December 7, 2023 14:45
Co-authored-by: Sawyer Hollenshead <git@sawyerh.com>
Co-authored-by: Sawyer Hollenshead <git@sawyerh.com>
Co-authored-by: Sawyer Hollenshead <git@sawyerh.com>
Co-authored-by: Sawyer Hollenshead <git@sawyerh.com>
Co-authored-by: Sawyer Hollenshead <git@sawyerh.com>
Copy link
Contributor

@sawyerh sawyerh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking good, thanks for iterating and debugging things! I was able to test this successfully locally using the Platform IAM credentials (left a comment with relevant instructions).

docs/feature-flags.md Outdated Show resolved Hide resolved
docs/feature-flags.md Show resolved Hide resolved
@@ -2,11 +2,13 @@ import { axe } from "jest-axe";
import Index from "src/pages/index";
import { render, screen } from "tests/react-utils";

jest.mock("src/services/feature-flags/setup");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can get rid of this line as well as the __mocks__ file now since the moduleNameMapper change fixed the original issue.

isFeatureEnabled(feature: string, userId?: string): Promise<boolean>;
}

export const manager: FlagManager = process.env.FEATURE_FLAGS_PROJECT
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we may still want to add the NODE_ENV !== "test" check here, since we are getting rid of the Jest mock. It's not causing issues at the moment since there's no test for getServerSideProps so the feature flag check is never executed in a test, but the NODE_ENV check would be useful for when a project adds test coverage for code that calls isFeatureEnabled.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer not to do environment checks in our source code since that breaks 12 factor app principles. A couple of reasons: (1) if the logic in the code has branches based on environment variables, it means that we have less confidence that the code branch that's covered in one environment (e.g. automated test suite) would work the same as the code branch that's covered when deployed to production and. Relatedly, in terms of test coverage tools, one entire branch of code will not be covered. (2) it makes it harder to implement automated integration tests if the test suite is forced to not use the AWS flag manager.

If we want to be more explicit about when we're using one flag manager type over the other without having to comment out or remove the FEATURE_FLAGS_PROJECT env var, we could always add an extra env var like FEATURE_FLAG_MANAGER_TYPE that is either "aws" or "local" e.g.

manager = process.env.FEATURE_FLAG_MANAGER_TYPE === "aws" ? new AWSFeatureFlagManager(process.env.FEATURE_FLAGS_PROJECT) : new LocalFeatureFlagManager();

would that address the issue you mentioned without a NODE_ENV check?

Copy link
Contributor

@sawyerh sawyerh Dec 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cross-posting from Slack:

Sorry, I caused confusion with an inaccurate statement — Next.js only loads env vars into the test environment from the .env file, but it doesn’t load the vars in files like .env.development or .env.local so I think ultimately Ali your existing condition that just checks the FF project var would be enough.

app/tests/pages/index.test.tsx Show resolved Hide resolved
# Feature flagging

- [AWS Evidently](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Evidently.html) is used for feature flagging
- For more information about the decision-making behind using Evidently, [this infra ADR is available](https://github.com/navapbc/template-infra/blob/main/docs/decisions/infra/0010-feature-flags-system-design.md)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR is merged, so you can probably reference the ADR directly on the main branch

Comment on lines 12 to 14
## Local development

Out-of-the-box, local calls to Evidently will fail with feature flag values defaulting to false. If you want to test Evidently locally, use your AWS IAM credentials. Once you set AWS environment variables locally for the environment you wish to connect to, calls to Evidently will succeed
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think we should provide a local feature flag implementation that doesn't rely on evidently. config files and environment variables are the approaches that jump to mind, but if there's an approach that leverages Next.js's local hot reloading that'd be nice to have.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

app/__mocks__/@aws-sdk/client-evidently.ts Outdated Show resolved Hide resolved
app/src/services/feature-flags/setup.ts Outdated Show resolved Hide resolved
isFeatureEnabled(feature: string, userId?: string): Promise<boolean>;
}

export const manager: FlagManager = process.env.FEATURE_FLAGS_PROJECT
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer not to do environment checks in our source code since that breaks 12 factor app principles. A couple of reasons: (1) if the logic in the code has branches based on environment variables, it means that we have less confidence that the code branch that's covered in one environment (e.g. automated test suite) would work the same as the code branch that's covered when deployed to production and. Relatedly, in terms of test coverage tools, one entire branch of code will not be covered. (2) it makes it harder to implement automated integration tests if the test suite is forced to not use the AWS flag manager.

If we want to be more explicit about when we're using one flag manager type over the other without having to comment out or remove the FEATURE_FLAGS_PROJECT env var, we could always add an extra env var like FEATURE_FLAG_MANAGER_TYPE that is either "aws" or "local" e.g.

manager = process.env.FEATURE_FLAG_MANAGER_TYPE === "aws" ? new AWSFeatureFlagManager(process.env.FEATURE_FLAGS_PROJECT) : new LocalFeatureFlagManager();

would that address the issue you mentioned without a NODE_ENV check?

@lorenyu
Copy link
Contributor

lorenyu commented Dec 8, 2023

I meant to just add one inline comment in response to a thread, not sure why it posted an entire review with what seems to be outdated comments. Sorry!

edit: oh it looks like i had review comments pending that i just never remembered to submit. maybe worth looking at the comments but apologies in advance if any of them are no longer relevant.

Co-authored-by: Sawyer Hollenshead <git@sawyerh.com>
@aligg aligg merged commit 7c7d5f5 into main Dec 8, 2023
6 checks passed
@aligg aligg deleted the aligg/ff branch December 8, 2023 18:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants