Security News
tea.xyz Spam Plagues npm and RubyGems Package Registries
Tea.xyz, a crypto project aimed at rewarding open source contributions, is once again facing backlash due to an influx of spam packages flooding public package registries.
@bkknights/prosper
Advanced tools
Readme
\\//,
ProsperA continuously improving, experimentation framework.
npm i @bkknights/prosper
yarn add @bkknights/prosper
Prosper provides a means of:
The non-Prosper way:
The Prosper way:
@pick(symbol)
with class properties.This is considered 'long-term' code. Our goal is that we want to find out if a Vulcan reply string is better, based on some user interaction.
class ReplyHandler {
reply() {
return 'See ya!';
}
}
class Service {
replyHandler: ReplyHandler = new ReplyHandler();
async setup(httpEvent): Promise<void> {}
run(): string {
return this.replyHandler.reply();
}
}
Using Feature Flags, and a hypothetical function findBestReplyIndex
, which finds the best index for user.
Note: We now have to change from sync to async, which changes usage as well.
class ReplyHandler {
async reply(): string {
// short lived code
const index = await findBestReplyIndex();
// long lived code
const defaultValue = 'See ya!';
// short lived code
if (featureFlagsEnabled()) { // If's can get tricky, when experimenting...
switch (index) {
case 0: return 'Live long, and prosper.';
// Others?
}
}
return defaultValue;
}
}
class Service {
replyHandler: ReplyHandler = new ReplyHandler();
async setup(httpEvent): Promise<void> {}
// Note: Changed from sync to async
async run(): string {
return await this.replyHandler.reply();
}
}
Using Experiments
// Imports
import { BaseExperiment, Variant } from '@bkknights/prosper';
// Create a symbol to reference ReplyHandler
const replyHandlerSymbol = Symbol('ReplyHandler');
//
class Experiment extends BaseExperiment {
// pretend I've connected it up to database
}
// Setup short lived experimentation Code
function whichReply(): Experiment {
class VulcanReply extends ReplyHandler {
reply(): string {
return 'Live Long And Prosper';
}
}
// Setup both defaults, and control set against experiment
return new Experiment('Which Reply Is Best?', [
new Variant('A: Control Set', {
[replyHandlerSymbol]: ReplyHandler
}),
new Variant('B: Vulcan Greeting/Reply', {
...defaults,
[replyHandlerSymbol]: VulcanReply
}),
]);
}
// Instantiate Prosper, with whichReply experiment set
const prosper = new Prosper().with(whichReply());
class Service {
prosper = prosper; // Note: Or inject?
// Note: Now "picking" from multiple ReplyHandler's, associated in setup
@pick(replyHandlerSymbol) replyHandler: ReplyHandler;
// Note: Need to allow prosper to both setup and bind to a value that persists over time in 1 key location within codebase
async setup(httpEvent): Promise<void> {
await this.prosper.setForUser(httpEvent.userId);
}
// Note: usage stayed the same
run(): string {
return this.replyHandler.reply();
}
}
Interacting with Prosper is done by creating a single instance of prosper used on classes where @pick(Symbol)
is used.
import { Prosper, pick } from '@bkknights/prosper';
const prosper = new Prosper();
class MyClass {
prosper: Prosper = prosper;
@pick(Symbol('foo')) foo: Function;
bar() {
this.foo();
}
}
Prosper is interacted with by extending the abstract class BaseExperimentSet
import { Prosper, pick } from '@bkknights/prosper';
import { BaseExperiment } from '@bkknights/prosper/base-experiment';
export class MyExperiment extends BaseExperiment<AlgorithmType> {
public async getExperiment(): Promise<IExperiment | null> {
}
public async upsertExperiment(experiment: IExperiment): Promise<void> {
}
public async deleteExperiment(experiment: IExperiment): Promise<void> {
}
public async getUserExperiment(userId: string, experimentId: string): Promise<IUserVariant | null> {
}
public async upsertUserVariant(userVariant: IUserVariant): Promise<void> {
}
public async deleteUserVariant(userExperiment: IUserVariant): Promise<void> {
}
public async deleteUserVariants(): Promise<void> {
}
public async getAlgorithm(): Promise<Algorithm> {
}
public async upsertAlgorithm(algorithm: Algorithm): Promise<void> {
}
public async deleteAlgorithm(): Promise<void> {
}
public async getVariantIndex(algorithm: Algorithm): Promise<number> {
}
public async rewardAlgorithm(algorithm: Algorithm, userVariantIndex: number, reward: number): Promise<Algorithm> {
}
}
new Prosper().with(setupEvents(new MyExperiment()))
Variants are written and added to an MyExperiment
import { Prosper } from '@bkknights/prosper';
import { BaseExperiment } from '@bkknights/prosper/base-experiment';
import { Variant } from '@bkknights/prosper/variant';
const fooSymbol = Symbol('foo');
const foo1 = () => {
// do default
};
const foo2 = () => {
// do experiment!
};
class Experiment extends BaseExperiment {
constructor(name: string, variants: Variant[]) {
super();
this.name = name;
this.variants = variants;
}
}
const prosper = new Prosper()
.with(
new Experiment('My Experiments', [
new Variant('Control Set: A', {
[fooSymbol]: foo1
}),
new Variant('Deveation: B', {
[fooSymbol]: foo2
}),
])
);
// call and `await prosper.setForUser(key)` just after database connectivity!
// elsewhere in codebase
class MyClass {
prosper = prosper;
@pick(fooSymbol) foo: Function;
myMethod() {
this.foo(); // calls either `foo1` or `foo2`, whichever the algorithms is indicating
}
}
...Vulcan's are cool.
FAQs
A continuously improving, experimentation framework
The npm package @bkknights/prosper receives a total of 1 weekly downloads. As such, @bkknights/prosper popularity was classified as not popular.
We found that @bkknights/prosper demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Tea.xyz, a crypto project aimed at rewarding open source contributions, is once again facing backlash due to an influx of spam packages flooding public package registries.
Security News
As cyber threats become more autonomous, AI-powered defenses are crucial for businesses to stay ahead of attackers who can exploit software vulnerabilities at scale.
Security News
UnitedHealth Group disclosed that the ransomware attack on Change Healthcare compromised protected health information for millions in the U.S., with estimated costs to the company expected to reach $1 billion.