Conseil
Cette leçon fait partie d’un cours qui vous apprend à créer une application New Relic à partir de zéro. Si vous ne l’avez pas déjà fait, consultez la présentation.
Chaque leçon du cours s'appuie sur la précédente, alors assurez-vous d'avoir terminé la dernière leçon, Personnaliser les données NRQL, avant de commencer celle-ci.
Dans les leçons précédentes, vous avez créé une expérience utilisateur dans votre application qui comprend des graphiques et un bouton pour terminer votre test A/B. Vous avez également configuré vos graphiques pour interroger les données réelles de la base de données de New Relic. Cependant, vous avez laissé des données fictives dans deux graphiques :
- Tests passés
- Total des annulations par version
Ces deux graphiques contiennent des données que vous ne pouvez pas obtenir à partir de New Relic. Les Past tests affichent des informations historiques sur les tests, tandis que Total cancellations per version indique le nombre d'annulations que chaque version voit au fil du temps. Concentrez-vous d'abord sur Past tests.
Les Past tests affichent des informations historiques sur les tests. Vous devez donc stocker des informations sur chaque test une fois terminé. Et vous disposez de tous les outils nécessaires pour accomplir cette tâche. Tout d’abord, vous disposez d’un bouton End test qui déclenche l’action de sauvegarde. Deuxièmement, vous savez comment utiliser NerdGraph et NerdStorage pour conserver les informations de test.
Enregistrer les informations de test sur NerdStorage
Accédez au répertoire add-nerdstorage/ab-test
du référentiel de cours:
$cd nru-programmability-course/add-nerdstorage/ab-test
Ce répertoire contient le code que nous attendons de votre application à ce stade du cours. En naviguant vers le bon répertoire au début de chaque leçon, vous laissez votre code personnalisé derrière vous, vous protégeant ainsi du transport de code incorrect d'une leçon à l'autre.
Dans nerdlets/ab-test-nerdlet/end-test.js
, créez une méthode, EndTestButton.endTest()
:
import React from 'react';import { AccountStorageMutation, BlockText, Button, Grid, GridItem, HeadingText, Modal, Select, SelectItem,} from 'nr1';
class VersionSelector extends React.Component { constructor(props) { super(props); }
render() { return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}> <SelectItem value={'A'}>Version A</SelectItem> <SelectItem value={'B'}>Version B</SelectItem> </Select> }}
class EndTestButton extends React.Component { constructor() { super(...arguments);
this.state = { modalHidden: true, }
this.showModal = this.showModal.bind(this); this.closeModal = this.closeModal.bind(this); this.endTest = this.endTest.bind(this); }
closeModal() { this.setState({ modalHidden: true }); }
showModal() { this.setState({ modalHidden: false }); }
endTest() { const today = new Date(); const dd = String(today.getDate()).padStart(2, '0'); const mm = String(today.getMonth() + 1).padStart(2, '0'); const yyyy = today.getFullYear(); const endDate = `${mm}-${dd}-${yyyy}`
AccountStorageMutation.mutate( { accountIds: this.props.accountIds, actionType: AccountStorageMutation.ACTION_TYPE.WRITE_DOCUMENT, collection: "past-tests", documentId: endDate, document: { versionADescription: this.props.versionADescription, versionBDescription: this.props.versionBDescription, winner: this.props.selectedVersion, } } )
this.closeModal(); }
render() { return <div> <Button type={Button.TYPE.DESTRUCTIVE} onClick={this.showModal}>End test</Button>
<Modal hidden={this.state.modalHidden} onClose={this.closeModal}> <HeadingText>Are you sure?</HeadingText> <BlockText> If you end the test, all your users will receive the version you selected: </BlockText>
<BlockText spacingType={[BlockText.SPACING_TYPE.LARGE]}> <b>Version {this.props.selectedVersion}</b> </BlockText>
<Button onClick={this.closeModal}>No, continue test</Button> <Button type={Button.TYPE.DESTRUCTIVE} onClick={this.closeModal}>Yes, end test</Button> </Modal> </div> }}
export default class EndTestSection extends React.Component { constructor() { super(...arguments);
this.state = { selectedVersion: 'A', };
this.selectVersion = this.selectVersion.bind(this); }
selectVersion(event, value) { this.setState({ selectedVersion: value }); }
render() { return <Grid className="endTestSection"> <GridItem columnSpan={12}> <HeadingText className="endTestHeader"> Pick the winner of your A/B test: </HeadingText> </GridItem> <GridItem columnStart={5} columnEnd={6} className="versionSelector"> <VersionSelector selectedVersion={this.state.selectedVersion} selectVersion={this.selectVersion} /> </GridItem> <GridItem columnStart={7} columnEnd={8}> <EndTestButton selectedVersion={this.state.selectedVersion}>End test</EndTestButton> </GridItem> </Grid> }}
Avec ce code, vous créez une chaîne de date formatée, endDate
. Ensuite, vous modifiez le stockage du compte avec un appel à AccountStorageMutation.mutate()
. Vous transmettez votre identifiant de compte, le type d'action WRITE_DOCUMENT
, « tests passés » comme nom de collection, endDate
comme documentId
et les données du document, qui incluent les descriptions de version et le gagnant.
Vous transmettez WRITE_DOCUMENT
car vous créez un nouveau document ou mettez à jour un document, s'il en existe déjà un avec une collection correspondante et documentId
. documentId
est endDate
, ce qui est utile pour ne créer qu'un seul enregistrement par jour.
Conseil
Si vous pensez que vous pourriez effectuer plusieurs tests en une journée, vous devrez changer cette logique.
Notez this.props.closeModal()
à la fin de la méthode. Cela ferme la fenêtre modale qui s'affiche lorsque vous essayez de terminer un test. Par conséquent, vous pouvez remplacer le rappel onClick
de votre bouton Yes, end test dans EndTestButton.render()
:
import React from 'react';import { AccountStorageMutation, BlockText, Button, Grid, GridItem, HeadingText, Modal, Select, SelectItem,} from 'nr1';
class VersionSelector extends React.Component { constructor(props) { super(props); }
render() { return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}> <SelectItem value={'A'}>Version A</SelectItem> <SelectItem value={'B'}>Version B</SelectItem> </Select> }}
class EndTestButton extends React.Component { constructor() { super(...arguments);
this.state = { modalHidden: true, }
this.showModal = this.showModal.bind(this); this.closeModal = this.closeModal.bind(this); this.endTest = this.endTest.bind(this); }
closeModal() { this.setState({ modalHidden: true }); }
showModal() { this.setState({ modalHidden: false }); }
endTest() { const today = new Date(); const dd = String(today.getDate()).padStart(2, '0'); const mm = String(today.getMonth() + 1).padStart(2, '0'); const yyyy = today.getFullYear(); const endDate = `${mm}-${dd}-${yyyy}`
AccountStorageMutation.mutate( { accountIds: this.props.accountIds, actionType: AccountStorageMutation.ACTION_TYPE.WRITE_DOCUMENT, collection: "past-tests", documentId: endDate, document: { versionADescription: this.props.versionADescription, versionBDescription: this.props.versionBDescription, winner: this.props.selectedVersion, } } )
this.closeModal(); }
render() { return <div> <Button type={Button.TYPE.DESTRUCTIVE} onClick={this.showModal}>End test</Button>
<Modal hidden={this.state.modalHidden} onClose={this.closeModal}> <HeadingText>Are you sure?</HeadingText> <BlockText> If you end the test, all your users will receive the version you selected: </BlockText>
<BlockText spacingType={[BlockText.SPACING_TYPE.LARGE]}> <b>Version {this.props.selectedVersion}</b> </BlockText>
<Button onClick={this.closeModal}>No, continue test</Button> <Button type={Button.TYPE.DESTRUCTIVE} onClick={this.endTest}>Yes, end test</Button> </Modal> </div> }}
export default class EndTestSection extends React.Component { constructor() { super(...arguments);
this.state = { selectedVersion: 'A', };
this.selectVersion = this.selectVersion.bind(this); }
selectVersion(event, value) { this.setState({ selectedVersion: value }); }
render() { return <Grid className="endTestSection"> <GridItem columnSpan={12}> <HeadingText className="endTestHeader"> Pick the winner of your A/B test: </HeadingText> </GridItem> <GridItem columnStart={5} columnEnd={6} className="versionSelector"> <VersionSelector selectedVersion={this.state.selectedVersion} selectVersion={this.selectVersion} /> </GridItem> <GridItem columnStart={7} columnEnd={8}> <EndTestButton selectedVersion={this.state.selectedVersion}>End test</EndTestButton> </GridItem> </Grid> }}
Lorsque vous terminez le test, endTest
stocke vos données de test dans le stockage du compte et ferme la fenêtre modale. Ceci n’est que la moitié du comportement dont vous avez besoin pour remplir votre table, vous devez également interroger cette collection à partir du stockage du compte.
Dans le fichier index.js
de votre Nerdlet, transmettez l'ID de compte et les descriptions de version à EndTestSection
:
import React from 'react';import { ChartGroup, Grid, GridItem } from 'nr1';import EndTestSection from './end-test';import NewsletterSignups from './newsletter-signups';import PastTests from './past-tests';import TotalCancellations from './total-cancellations';import TotalSubscriptions from './total-subscriptions';import VersionDescription from './description';import VersionPageViews from './page-views';import VersionTotals from './totals';
const ACCOUNT_ID = 123456 // <YOUR NEW RELIC ACCOUNT ID>const VERSION_A_DESCRIPTION = 'The newsletter signup message says, "Sign up for our newsletter"'const VERSION_B_DESCRIPTION = 'The newsletter signup message says, "Sign up for our newsletter and get a free shirt!"'
export default class AbTestNerdletNerdlet extends React.Component { render() { return <div> <Grid className="wrapper"> <GridItem columnSpan={6}> <VersionDescription description={VERSION_A_DESCRIPTION} version="A" /> </GridItem> <GridItem columnSpan={6}> <VersionDescription description={VERSION_B_DESCRIPTION} version="B" /> </GridItem> <GridItem columnSpan={12}><hr /></GridItem> <GridItem columnSpan={12}><NewsletterSignups /></GridItem> <GridItem columnSpan={6}><TotalSubscriptions /></GridItem> <GridItem columnSpan={6}><TotalCancellations /></GridItem> <GridItem columnSpan={6}> <VersionTotals version='a' accountId={ACCOUNT_ID} /> </GridItem> <GridItem columnSpan={6}> <VersionTotals version='b' accountId={ACCOUNT_ID} /> </GridItem> <ChartGroup> <GridItem columnSpan={6}> <VersionPageViews version='a' /> </GridItem> <GridItem columnSpan={6}> <VersionPageViews version='b' /> </GridItem> </ChartGroup> <GridItem columnSpan={12}> <EndTestSection accountId={ACCOUNT_ID} versionADescription={VERSION_A_DESCRIPTION} versionBDescription={VERSION_B_DESCRIPTION} /> </GridItem> <GridItem columnSpan={12}><PastTests /></GridItem> </Grid> </div> }}
Important
Assurez-vous de remplacer <YOUR NEW RELIC ACCOUNT ID>
par votre identifiant de compte New Relic actuel.
Désormais, EndTestSection
peut accéder à ces variables dans ses accessoires.
Transférez votre identifiant de compte et les descriptions de version de EndTestSection
à EndTestButton
:
import React from 'react';import { AccountStorageMutation, BlockText, Button, Grid, GridItem, HeadingText, Modal, Select, SelectItem,} from 'nr1';
class VersionSelector extends React.Component { constructor(props) { super(props); }
render() { return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}> <SelectItem value={'A'}>Version A</SelectItem> <SelectItem value={'B'}>Version B</SelectItem> </Select> }}
class EndTestButton extends React.Component { constructor() { super(...arguments);
this.state = { modalHidden: true, }
this.showModal = this.showModal.bind(this); this.closeModal = this.closeModal.bind(this); this.endTest = this.endTest.bind(this); }
closeModal() { this.setState({ modalHidden: true }); }
showModal() { this.setState({ modalHidden: false }); }
endTest() { const today = new Date(); const dd = String(today.getDate()).padStart(2, '0'); const mm = String(today.getMonth() + 1).padStart(2, '0'); const yyyy = today.getFullYear(); const endDate = `${mm}-${dd}-${yyyy}`
AccountStorageMutation.mutate( { accountIds: this.props.accountIds, actionType: AccountStorageMutation.ACTION_TYPE.WRITE_DOCUMENT, collection: "past-tests", documentId: endDate, document: { versionADescription: this.props.versionADescription, versionBDescription: this.props.versionBDescription, winner: this.props.selectedVersion, } } )
this.closeModal(); }
render() { return <div> <Button type={Button.TYPE.DESTRUCTIVE} onClick={this.showModal}>End test</Button>
<Modal hidden={this.state.modalHidden} onClose={this.closeModal}> <HeadingText>Are you sure?</HeadingText> <BlockText> If you end the test, all your users will receive the version you selected: </BlockText>
<BlockText spacingType={[BlockText.SPACING_TYPE.LARGE]}> <b>Version {this.props.selectedVersion}</b> </BlockText>
<Button onClick={this.closeModal}>No, continue test</Button> <Button type={Button.TYPE.DESTRUCTIVE} onClick={this.endTest}>Yes, end test</Button> </Modal> </div> }}
export default class EndTestSection extends React.Component { constructor() { super(...arguments);
this.state = { selectedVersion: 'A', };
this.selectVersion = this.selectVersion.bind(this); }
selectVersion(event, value) { this.setState({ selectedVersion: value }); }
render() { return <Grid className="endTestSection"> <GridItem columnSpan={12}> <HeadingText className="endTestHeader"> Pick the winner of your A/B test: </HeadingText> </GridItem> <GridItem columnStart={5} columnEnd={6} className="versionSelector"> <VersionSelector selectedVersion={this.state.selectedVersion} selectVersion={this.selectVersion} /> </GridItem> <GridItem columnStart={7} columnEnd={8}> <EndTestButton accountIds={this.props.accountIds} selectedVersion={this.state.selectedVersion} versionADescription={this.props.versionADescription} versionBDescription={this.props.versionBDescription} > End test </EndTestButton> </GridItem> </Grid> }}
Récupérer les informations de test depuis NerdStorage
Dans past-tests.js
, mettez à jour PastTests
pour récupérer les données du stockage du compte et les afficher dans TableChart
:
import React from 'react';import { AccountStorageQuery, HeadingText, Spinner, TableChart,} from 'nr1';
export default class PastTests extends React.Component { render() { const historicalData = { metadata: { id: 'past-tests', name: 'Past tests', columns: ['endDate', 'versionADescription', 'versionBDescription', 'winner'], }, data: [], }
return <div> <HeadingText className="chartHeader"> Past tests </HeadingText> <AccountStorageQuery accountIds={this.props.accountIds} collection="past-tests"> {({ loading, error, data }) => { if (loading) { return <Spinner />; } if (error) { console.debug(error); return 'There was an error fetching your data.'; } data.forEach( function (currentValue, index) { historicalData.data.push({ endDate: currentValue.id, versionADescription: currentValue.document.versionADescription, versionBDescription: currentValue.document.versionBDescription, winner: currentValue.document.winner, }) }, data ) return <TableChart data={[historicalData]} fullWidth /> }} </AccountStorageQuery> </div> }}
Tout d’abord, vous avez supprimé les données simulées de historicalData
. Ensuite, vous avez utilisé AccountStorageQuery
pour récupérer des données depuis NerdStorage. Vous avez transmis votre identifiant de compte et le nom de la collection dans laquelle vous avez stocké le document.
Notez qu'il y a trois valeurs de retour de la requête :
loading
error
data
Si la requête est en cours, loading
est true
. Dans ce cas, vous affichez un composant utilisateur d'interface Spinner
pour faire savoir à l'utilisateur que la table n'est pas encore prête. Si la requête a renvoyé une erreur, vous pouvez voir des informations sur cette erreur dans la variable error
. Vous enregistez ces informations dans la console à des fins de débogage et renvoyez un message d'erreur. Si la requête est renvoyée avec succès, vous pouvez accéder aux données de la variable data
. Étant donné que les données ne correspondent pas au format requis par TableChart
, vous parcourez les données et les formatez conformément aux spécifications TableChart
. Enfin, vous passez historicalData
à votre TableChart
.
Dans le fichier index.js
de votre Nerdlet, transmettez votre ACCOUNT_ID
à PastTests
:
import React from 'react';import { ChartGroup, Grid, GridItem } from 'nr1';import EndTestSection from './end-test';import NewsletterSignups from './newsletter-signups';import PastTests from './past-tests';import TotalCancellations from './total-cancellations';import TotalSubscriptions from './total-subscriptions';import VersionDescription from './description';import VersionPageViews from './page-views';import VersionTotals from './totals';
const ACCOUNT_ID = 1234567 // <YOUR NEW RELIC ACCOUNT ID>const VERSION_A_DESCRIPTION = 'The newsletter signup message says, "Sign up for our newsletter"'const VERSION_B_DESCRIPTION = 'The newsletter signup message says, "Sign up for our newsletter and get a free shirt!"'
export default class AbTestNerdletNerdlet extends React.Component { render() { return <div> <Grid className="wrapper"> <GridItem columnSpan={6}> <VersionDescription description={VERSION_A_DESCRIPTION} version="A" /> </GridItem> <GridItem columnSpan={6}> <VersionDescription description={VERSION_B_DESCRIPTION} version="B" /> </GridItem> <GridItem columnSpan={12}><hr /></GridItem> <GridItem columnSpan={12}><NewsletterSignups /></GridItem> <GridItem columnSpan={6}><TotalSubscriptions /></GridItem> <GridItem columnSpan={6}><TotalCancellations /></GridItem> <GridItem columnSpan={6}> <VersionTotals version='a' accountId={ACCOUNT_ID} /> </GridItem> <GridItem columnSpan={6}> <VersionTotals version='b' accountId={ACCOUNT_ID} /> </GridItem> <ChartGroup> <GridItem columnSpan={6}> <VersionPageViews version='a' /> </GridItem> <GridItem columnSpan={6}> <VersionPageViews version='b' /> </GridItem> </ChartGroup> <GridItem columnSpan={12}> <EndTestSection accountId={ACCOUNT_ID} versionADescription={VERSION_A_DESCRIPTION} versionBDescription={VERSION_B_DESCRIPTION} /> </GridItem> <GridItem columnSpan={12}> <PastTests accountId={ACCOUNT_ID} /> </GridItem> </Grid> </div> }}
Important
Assurez-vous de remplacer <YOUR NEW RELIC ACCOUNT ID>
par votre identifiant de compte New Relic actuel.
Accédez à la racine de votre Nerdpack à nru-programmability-course/add-nerdstorage/ab-test
.
Générez un nouvel UUID pour votre Nerdpack :
$nr1 nerdpack:uuid -gf
Étant donné que vous avez cloné le référentiel de cours qui contenait un Nerdpack existant, vous devez générer votre propre identifiant unique. Cet UUID mappe votre Nerdpack à votre compte New Relic. Il permet également à votre application de faire requests Nerdgraph au nom de votre compte.
Présentez votre demande localement :
$nr1 nerdpack:serve
Accédez à https://one.newrelic.com?nerdpacks=local et affichez votre application sous Apps > Your apps.
Au début, vous ne devriez voir aucune donnée.
Cliquez sur End test et approuvez votre action dans la fenêtre modale. Vous voyez maintenant les données des Past tests.
Conseil
Si quelque chose ne fonctionne pas, utilisez les outils de débogage de votre navigateur pour essayer d'identifier le problème.
Assurez-vous de :
- J'ai copié correctement le code de la leçon
- Générer un nouvel UUID
- Remplacé toutes les instances de
<YOUR NEW RELIC ACCOUNT ID>
dans votre projet par votre identifiant de compteNew Relic actuel
Une fois que vous avez terminé, arrêtez de diffuser votre application New Relic en appuyant sur CTRL+C
dans la fenêtre de terminal de votre serveur local.
Excellent travail ! Vous avez maintenant de l’expérience dans l’utilisation des composants de requête et de mutation NerdStorage. Cependant, il existe encore un autre graphique avec des données simulées : le nombre total d'annulations par version.
Le nombre total d'annulations par version est différent des autres graphiques de votre application de test A/B. Étant donné que New Relic ne sait rien du nombre d'utilisateurs qui se désabonnent de votre newsletter, vous devez demander cette information à une source externe. Pour les besoins de ce cours, nous avons créé un service de données externes qui fournit de fausses données d'annulation de newsletter que vous pouvez utiliser dans votre application. Ce service fictif se trouve à l'adresse https://api.nerdsletter.net/cancellations.
Les applications New Relic sont des applications React, ce qui signifie que vous pouvez utiliser les fonctionnalités React et Javascript pour collecter des données non seulement à partir de New Relic, mais également de tout service externe. Dans une leçon ultérieure, vous apprendrez à rechercher au-delà de New Relic des données qui vous informeront de la manière dont votre logiciel vous aide à atteindre vos objectifs commerciaux. Mais avant d’apprendre cela, vous devez savoir quelque chose sur notre service de données fictives : il nécessite un en-tête d’autorisation !
Dans cette leçon, vous avez appris à utiliser NerdStorage pour interroger et muter des données dans le datastore de votre application. Bien que NerdStorage soit un excellent endroit pour de nombreuses catégories de données, il n'est pas adapté aux données sensibles, comme un jeton que vous transmettriez dans un en-tête d'autorisation à un service externe. Pour cela, vous utiliseriez NerdStorageVault.
Conseil
Cette leçon fait partie d’un cours qui vous apprend à créer une application New Relic à partir de zéro. Passez à la leçon suivante : accédez à NerdStorageVault depuis votre nerdlet.