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

[ClientSide Routing] Launch v3 AB test / Simplify A/B testing #5099

Merged
merged 8 commits into from
Feb 24, 2020

Conversation

damassi
Copy link
Member

@damassi damassi commented Feb 22, 2020

Companion PR: artsy/reaction#3191 (needs to be merged first)

This sets up the A/B test for client-side routing as well as simplifies how we do A/B tests in the future across force / reaction boundaries via the use of express-http-context.

How it works:

  • In Force:
    • On the server, rather than needing access to Express's response (res) object in order to grab the A/B test identifier (res.locals.sd.SOME_AB_TEST), we use a new setSplitTest(ENV_VAR, value) util
    • We can then grab the value globally via getSplitTest('ENV_VAR')
  • In Reaction:
    • To get the value of the split test, we use the getENV('ENV_VAR') util. We used this util before as a way to smooth over accessing environmental variables in an isomorphic way -- on the server, we grab from process.env; on the client, from sharify.
    • However, this adds a third layer for the server: It first checks if a value exists in express-http-context, keyed by ENV_VAR
    • If it finds that, it uses that. If not, it falls back to process.env. If not found there, the value is undefined.

This simplifies things because we can build entire complex feature sets that can be turned on and off by ENV var, and then later, when an A/B test is needed to verify the feature, we don't need to change any code. It gives us an ENV-driven-development flow, where before we had to play a somewhat complex game of thread the needle, particularly on the server, and then go through an additional QA pass to ensure correctness.

setAliases({
"express-http-context": path.resolve(
Copy link
Member Author

@damassi damassi Feb 22, 2020

Choose a reason for hiding this comment

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

Since we're sharing context values across application boundaries, we need to be sure it still works while yarn linking. require-control forces the node process to look in a specific node_modules location for packages. Very useful lib that solved a lot of earlier yarn link problems.


const artworkSlug = location.pathname.replace(/\/artwork\//, "")
recordArtworkView(artworkSlug, sd.CURRENT_USER)
if (pageType === "artwork") {
Copy link
Contributor

Choose a reason for hiding this comment

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

Interesting, does this wind up firing as you navigate (to an artwork, when starting your session on a non-artwork page)?

Looks like the other things here (mediator.on hooks) just need to be called once in your session, in order to successfully be registered. Whereas this recordArtworkView should be called potentially on every navigation?

(sidenote- this is a mutation to record a view, firing on render. prob an oversight it's not in Reaction)

Copy link
Member Author

Choose a reason for hiding this comment

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

This was how you had it before -- i had revised the inside of this in a previous PR and only mounted the client bits if it was an exactly page match on SSR but realized last night that we need this client stuff mounted immediately as we can navigate to the page later. So I just re-added this how it was.

export const skipIfClientSideRoutingEnabled = (_req, _res, next) => {
if (
getSplitTest("EXPERIMENTAL_APP_SHELL") ||
Copy link
Contributor

Choose a reason for hiding this comment

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

Just to confirm, the DX flow is:

  • be able to toggle feature completely on or off via feature flag
  • ensure feature works totally on or off
  • staging is generally enabled (always on)
  • AB test value overrides feature flag value (and uses the new context lib)

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep, that's the flow!

@@ -0,0 +1,10 @@
import httpContext from "express-http-context"
Copy link
Contributor

Choose a reason for hiding this comment

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

seems pretty easy!

@@ -208,6 +209,18 @@ export default function(app) {
)
app.use("/(.well-known/)?apple-app-site-association", siteAssociation)

/**
Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for the code comment. This feels like the right place stack-wise for this (after those middlewares that will mess this up, but before the actual AB middleware and app routes).

@mzikherman
Copy link
Contributor

LGTM! Looking forward to playing with this.

Echoing my comment from artsy/reaction#3191 (comment), namely, should we hold these PR's open until the Node v12 upgrade is fully deployed to prod?

@damassi
Copy link
Member Author

damassi commented Feb 22, 2020

I'm personally not worried about Node 12 in prod -- the issue that we ran into before (seemed) to have been a bug in V8 JS engine that was fixed in node 10.4+. But yeah down for whatever ya'll think is best.

@ArtsyOpenSource
Copy link

ArtsyOpenSource commented Feb 24, 2020

Warnings
⚠️ The staging version of Metaphysics has breaking changes, this might not affect your build, but could mean your queries don't work the way you expect. See below for breaking changes:
  • ⚠️ Type 'CreateSubmissionMutationInput' was removed
  • ⚠️ Type 'CreateSubmissionMutationPayload' was removed
  • ⚠️ Type 'UpdateSubmissionMutationInput' was removed
  • ⚠️ Type 'UpdateSubmissionMutationPayload' was removed
  • ⚠️ Type 'Asset' was removed
  • ⚠️ Field 'ConsignmentSubmissionConnection.edges' changed type from '[ConsignmentSubmissionEdge]' to '[SubmissionEdge]'
  • ⚠️ Field 'internalID' was removed from object type 'ConsignmentSubmission'
  • ⚠️ Field 'artistID' was removed from object type 'ConsignmentSubmission'
  • ⚠️ Field 'authenticityCertificate' was removed from object type 'ConsignmentSubmission'
  • ⚠️ Field 'dimensionsMetric' was removed from object type 'ConsignmentSubmission'
  • ⚠️ Field 'editionNumber' was removed from object type 'ConsignmentSubmission'
  • ⚠️ Field 'editionSize' was removed from object type 'ConsignmentSubmission'
  • ⚠️ Field 'locationCity' was removed from object type 'ConsignmentSubmission'
  • ⚠️ Field 'locationCountry' was removed from object type 'ConsignmentSubmission'
  • ⚠️ Field 'locationState' was removed from object type 'ConsignmentSubmission'
  • ⚠️ Field 'userID' was removed from object type 'ConsignmentSubmission'
  • ⚠️ Field 'ConsignmentSubmission.category' changed type from 'SubmissionCategoryAggregation' to 'ConsignmentSubmissionCategoryAggregation'
  • ⚠️ Field 'ConsignmentSubmission.edition' changed type from 'Boolean' to 'String'
  • ⚠️ Field 'ConsignmentSubmission.state' changed type from 'SubmissionStateAggregation' to 'ConsignmentSubmissionStateAggregation'
  • ⚠️ Field 'Mutation.createConsignmentSubmission' changed type from 'CreateSubmissionMutationPayload' to 'CreateConsignmentSubmissionPayload'
  • ⚠️ Type for argument 'input' on field 'Mutation.createConsignmentSubmission' changed from 'CreateSubmissionMutationInput!' to 'CreateConsignmentSubmissionInput'
  • ⚠️ Field 'Mutation.updateConsignmentSubmission' changed type from 'UpdateSubmissionMutationPayload' to 'UpdateConsignmentSubmissionPayload'
  • ⚠️ Type for argument 'input' on field 'Mutation.updateConsignmentSubmission' changed from 'UpdateSubmissionMutationInput!' to 'UpdateConsignmentSubmissionInput'
  • ⚠️ Type for argument 'input' on field 'Mutation.addAssetToConsignmentSubmission' changed from 'AddAssetToConsignmentSubmissionInput!' to 'AddAssetToConsignmentSubmissionInput'
  • ⚠️ Input field 'submission_id' was added to input object type 'AddAssetToConsignmentSubmissionInput'
  • ⚠️ Input field 'gemini_token' was added to input object type 'AddAssetToConsignmentSubmissionInput'
  • ⚠️ Input field 'assetType' was removed from input object type 'AddAssetToConsignmentSubmissionInput'
  • ⚠️ Input field 'geminiToken' was removed from input object type 'AddAssetToConsignmentSubmissionInput'
  • ⚠️ Input field 'submissionID' was removed from input object type 'AddAssetToConsignmentSubmissionInput'
  • ⚠️ Field 'AddAssetToConsignmentSubmissionPayload.asset' changed type from 'Asset' to 'ConsignmentSubmissionCategoryAsset'

Generated by 🚫 dangerJS against 56ad49e

@damassi damassi merged commit 303ef7c into artsy:master Feb 24, 2020
@damassi damassi deleted the add-express-context branch February 24, 2020 23:46
@artsy-peril artsy-peril bot mentioned this pull request Feb 25, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants