Skip to content

Instantly share code, notes, and snippets.

@BioPhoton
Last active February 24, 2020 10:14
Show Gist options
  • Save BioPhoton/8bbf8fbd539015ac182b01975c195d62 to your computer and use it in GitHub Desktop.
Save BioPhoton/8bbf8fbd539015ac182b01975c195d62 to your computer and use it in GitHub Desktop.

How to maintain the MigrationTimeLine

Workflow

Lets say we want to deprecate the resultSelector of the operator generate: https://github.com/ReactiveX/rxjs/blob/6.5.3/src/internal/observable/generate.ts#L68

Automated Crawling of Deprecations

Get a good amount of new deprecations automatically crawled from the repository over following tooling (find-deprecations)[https://github.com/timdeschryver/find-deprecations]

Demo Result:

{
        "version": "7.0.0-alpha.1",
        "date": "2019-12-27T16:17:16.024Z",
        "sourceLink": "https://github.com/ReactiveX/rxjs/tree/7.0.0-alpha.1"
        "deprecations": [
            {
                "itemType": "deprecation",
                "subject": "AsyncSubject",
                "subjectAction": "method-subscribe-~subjectAction~",
                "subjectSymbol": "class",
                "reason": "@TODO",
                "implication": "@TODO",
                "sourceLink": "https://github.com/ReactiveX/rxjs/tree/7.0.0-alpha.1/src/internal/AsyncSubject.ts#17",
                "deprecationMsgCode": "This is an internal implementation detail, do not use.",
                "exampleAfter": "@TODO",
                "exampleBefore": "@TODO"
            },
        ]
    },

Manual Creation of Deprecations

  1. Collect information for following things:
  • Source Link
    Link to the lines of code in GitHub in the version it got introduced. Following things should be considered:
    • The link should target the tag e.g. .../blob/6.5.4/src/...
    • The link should target the exact line of code e.g. .../src/.ts#L42
      • If multiple lines are effected the link should include all of them e.g. .../src/.ts#L21-L42 https://github.com/ReactiveX/rxjs/blob/6.5.4/src/internal/observable/generate.ts#L68
  • Deprecation Message The part from the code placed next to @deprecated section. The Pattern for the text in the source code is: <HumanReadableShortMessage> - see <LinkToDeprecationPage>
  • Reason
    Short explanation of why the deprecation got introduced
  • Implication
    This section is an explanation that accompanies the 'before deprecation' and 'after deprecation' snippets. It explains the different between the two versions to the user in a detailed way to help the user to spot the differences in code.
  • Code Example Before
    Code example showing the situation before the deprecation. Consider following guide lines:
    • No '$' notation
    • One line between imports asn code
    • const source ... => ... source.subscribe(next: n => console.log(n));
    • It has to work in StackBlitz in the right version
    • Code should log a result
  • Code Example After See code example before
  • Estimated Breaking Version Version of breaking change

Data collected for generate look like this:

const deprecation = {
    sourceLink: `https://github.com/ReactiveX/rxjs/blob/6.5.4/src/internal/observable/zip.ts#L37`,
    breakingChangeVersion: '7',
    deprecationMsg: `use the map operator instead of a result selector`,
    reason: `By removing the result selector from generate we get a smaller bundle since and better maintainability. Refactoring to use a map operation instead.',
    implication: 'For generate, the removal of the resultSelector argument means that if callers want to
                     perform a projection, they will have to move this code into an additional map operator.
                     To refactor this, take the function used as resultSelector and place it into a map operator below.`,
    exampleBefore: `
    import { generate} from 'rxjs';
    
    const initialState: number = 0;
    const condition: (v: number) => boolean = x => x < 3;
    const iterate:  (state: number) => number =  x => x + 1; 
    const resultSelector: (v: number) => number = x => x * 1000;
    
    const source = generate(initialState, condition, iterate, resultSelector);
    source.subscribe(n => console.log(n));
    `,
    exampleAfter: `
    import { generate} from 'rxjs';
    import { map} from 'rxjs/operators';
     
    const initialState: number = 0;
    const condition: (v: number) => boolean = x => x < 3;
    const iterate:  (state: number) => number =  x => x + 1; 
    const resultSelector: (v: number) => number = x => x * 1000;
    
    const source = generate(initialState, condition, iterate)
    .pipe(
      map(resultSelector)
    );
    source.subscribe(n => console.log(n));
    `
}
  1. To get a unique id for this item we need some more information:
  • Subject
    The subject of migration. What piece is effected?
  • Subject Type This helps to generate the item id. As the docs ApiSymbo is reused we get a nice icon that shows us the type of the subject i.e. class, function etc.
    • class
    • functions
    • constant
    • var
    • let
  • Subject Action Short string that explains the action to the item.
    • What happened to the subject?
    • What attribute of the piece is effected? By default 'deprecated'
const deprecation = {
  // ... previous information
  subject: 'generate',
  subjectType: 'function',
  subjectAction: 'resultSelector-deprecated'
}
  1. Collect information for breakingChange item. Here the only thing we need to know is what happens to the deprecated code. In our case it get's removed. This information is needed to fill the subjectAction of the breaking change. For our deprecation we would use the string 'resultSelector-removed'. This information is needed to enable linking in the docs page.

  2. Create the deprecation message following the pattern: @deprecated <HumanReadableShortMessage> - see <LinkToDeprecationPage> where <HumanReadableShortMessage> is the field deprecationMsg and <LinkToDeprecationPage> follows the pattern: <URL>#<version>_deprecation-<subjectType>-<subject>-<subjectAction>

The final deprecation message could loot like this: @deprecated use the map operator instead of a result selector - see https://rxjs.dev/migration#6.5.4_deprecation-function-generate-resultSelector-deprecated

  1. Insert the message into code

  2. Insert deprecation object into release list:

const list = [
  {
    version: '6.5.4',
    deprecations: [
        // new deprecation here
    ] 
  }
];
  1. Add the breakingChange information:
const deprecation = {
    // ... previous information
    "breakingChangeVersion": "7.0.0",
    "breakingChangeSubjectAction": "resultSelector-removed",
    "breakingChangeMsg: 'Operator generate removed argument resultSelector'
};

Based on this information the breakingChange can be derived from the deprecation item.

  1. Autogenerate breakingChange object into release list: (happens automatically)
const list = [
  {
    version: '7.0.0',
    breakingChanges: [
        // autogenerated breakingChange here
    ] 
  }
];

Supporing Manual Editing of Deprecations

As help I created a form that contains drop downs for all enumerable fields and other time saving features. The form shows the time and the maintainer can check the provided code and open it in StackBlitz in the correct version of deprecation and breaking change.

After the maintainer ensures correctness of the data a copy-to-clipboard button is provided for the deprecation message in code as well as for the json data. The generated data respects open versions e.g. 7.x and could do other checks against the existing data.

Support for Issues for Github

If a user uses a broken link a support form pops up and collects data over the above described form. On click the user gets redirected to github with the issue template prefilled for an issue for a missing deprecation information.

@BioPhoton
Copy link
Author

BioPhoton commented Jan 21, 2020

The form can be found if you navigate to have a propper URL in the search bar and then just delete the last char to have to helper for showing up.

maintainance-form

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment