Skip to content

Latest commit

 

History

History
350 lines (270 loc) · 15 KB

life_of_a_language_feature.md

File metadata and controls

350 lines (270 loc) · 15 KB

Lifecycle of a language feature

This document describes the process from creation to the shipping and release of a language feature. This document serves as a walkthrough for what's needed to build a language feature.

  1. User issues and feature requests
  2. Design, feedback, and iteration
  3. Acceptance
  4. Team communication (eg. kick-off meetings)
  5. Implementation and testing
  6. Migrations
  7. Shipping

User issues and feature requests

Features arise from perceived user issues or feature requests. These issues are documentation of the user issue to be solved.

Note

These feature requests are filed in the language repo, and are labelled request.

We may close issues that we believe we won't address for whatever reason. We may also keep issues open indefinitely if we believe they are something that we might want to address in the future.

How does the team choose which feature request to accept?

There are many factors that determine why we might choose to do one feature over another, such as feasibility, difficulty, or popularity. Often, we will take a look through the most 👍-reacted issues to see what our users are interested in.

Design, feedback, and iteration

Interested parties may propose several (competing) language features to a single request/problem.

A "language feature" issue (labelled feature) will be created for tracking the solution to the user issue/problem or feature under consideration.

Proposal checklist

  • An issue labelled feature for discussion of a proposed solution.
    • Links to and from the request issue they are trying to address.
  • A link to an initial feature specification writeup of the proposed solution in the feature issue.
    • Located in a sub-directory with the name of the feature (/ [feature-name]/), inside the working directory of the language repository.
    • File is named feature-specification.md.
      • All written plans, specs, and materials must be written using GitHub Markdown format format, and must use the .md extension.

Proposals may be iterated on in-place.

For smaller and non-controversial features, we will sometimes skip this step and proceed directly to the Acceptance phase.

External (outside of the language team) feedback

We use the Github issue tracker as the primary place for accepting feedback on proposals, solicited or unsolicited.

If we solicit feedback, we will open an issue for discussion and feedback. We highly recommend filing and splitting off different issues for different threads of discussion. We generally expect to formally solicit at least one round of feedback on significant changes.

Acceptance

If consensus is reached on a specific proposal and we decide to accept it, a member of the language team will be chosen to shepherd the implementation.

The implementation will be tracked via two artifacts:

  • The feature specification document
  • The feature project

Feature specification

The 'feature specification' is a single canonical writeup of the language feature which serves as the implementation reference. The feature specification should follow the Proposal Checklist.

Once we've chosen a specification, we'll update it throughout the implementation process. For example, we could add new information to the specification if we encounter edge-cases we didn't think of initially or remove parts of it if a certain behavior isn't feasible to implement.

Feature project

We'll create a project in dart-lang with the title [Language] <feature-name>. This project will link to and from all the Github issues that we need to track to complete and ship the feature.

Tip

Generate all the issues for the project automatically with https://github.com/itsjustkevin/aviary.

This script generates all the issues that need to be tracked and added to the project. If there are any issues or implementation areas that are unnecessary, you can close them out immediately, but each issue is worth thinking through.

Meta implementation issue

The meta implementation issue (labelled implementation) will be filed in the language repository for tracking the implementation process.

This issue must contain links to:

  • The related request and feature issues (if they exist)
  • A link to the feature specification
  • All implementation issues

Note

Once you're done making the implementation issue, copy the link of the issue and add it to the Dash Feature Tracker board.

Team communication

One of the most important parts of the language feature process is communicating with all the implementation teams and any other stakeholders.

Channels for communication

We'll send out an announcement email to the entire team, letting them know that work for the feature is beginning.

We may create a mailing list or a Google chat group to organize communication between the different teams working on the language feature.

Kick-off meetings

We need to get sign-off from all of the relevant implementation teams indicating that they understand the proposal, believe that it can reasonably be implemented, and feel that they have sufficient details to proceed. We do this in the form of kick-off meetings.

Since feature specification documents are usually long and very detailed, we like to begin this sign-off process with a set of kick-off meetings, typically one for each affected implementation team. These meetings are on opportunity for a language team representative to present a broad outline of the new feature, give some concrete examples, and collect insights from the implementation teams about what aspects of the implementation might need special attention.

Get sign-off from the following teams:

  • Analyzer team
  • CFE team
  • Back-end teams:
    • Dart VM Team
    • Dart Web Team
    • Dart2Wasm Team

Note

If a feature consists entirely of a new piece of syntactic sugar, it can be tempting to assume that it's not necessary to consult with any back-end teams since the CFE will lower the new syntax into a kernel form that is already supported, but this can be a dangerous assumption. It's easy to forget that even in features that appear to consist purely of syntactic sugar, some back-end support may be needed in order to properly support single-step debugging or hot reload.

Also, some work may need to be done on back-end code generators in order to make sure that the new feature is lowered into a form that can be well optimized.

To avoid missing things, we prefer to err on the side of asking teams whether they're affected, rather than assuming they won't be.

Implementation and testing

Feature flag

Most new language features should be implemented using a feature flag. The feature flag serves several purposes:

  • It allows the feature to be implemented over a series of CLs without destabilizing the SDK. If it comes time to ship a new release of the SDK before the feature is ready, the feature flag can remain off, so users won't be exposed to a partially-implemented or buggy feature before it's ready.
  • It allows users to opt in to trying out features that have not yet been released, by turning on the feature flag locally.
  • Once the feature is enabled, the feature flag logic ensures that it will only affect users who have set their language version to a version that includes the new feature. This is especially important for package developers who may want to support a range of versions of the Dart SDK.

Note

Implementing a language feature using a feature flag is frequently more work than implementing it without a feature flag, since the compiler and analyzer must faithfully implement both the old and new behaviors. Occasionally the language team may decide that the benefits of using a feature flag don't justify this extra work. But this is a rare scenario. If you are working on a feature and believe you don't need to use a feature flag, please consult with the language team to be sure.

How to add a new language feature flag

  • Add an entry to tools/experimental_features.yaml describing the feature, in the top section (above the line that says Flags below this line are shipped).
  • Run dart pkg/front_end/tool/fasta.dart generate-experimental-flags to update pkg/_fe_analyzer_shared/lib/src/experiments/flags.dart and pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart.
  • Run dart pkg/analyzer/tool/experiments/generate.dart to update pkg/analyzer/lib/src/dart/analysis/experiments.g.dart.
  • Add a static final declaration to the Feature class in pkg/analyzer/lib/dart/analysis/features.dart.
  • Increment the value of AnalysisDriver.DATA_VERSION in pkg/analyzer/lib/src/dart/analysis/driver.dart.

Example CL: https://dart-review.googlesource.com/c/sdk/+/365545

Tip

Keep a WIP CL which enables your feature flag by default in the latest version. Rebase it occasionally to get a good idea of how your feature breaks the SDK and other dependencies. This is very helpful for getting insight on what migrations and breaking changes you'll be making.

Language testing

The language team will generally write a preliminary set of language tests for a feature, in the SDK's tests/language subdirectory. These tests are not intended to be exhaustive, but should illustrate and exercise important and non-obvious features. Implementation teams are encouraged to write additional language or unit tests. The language team may also coordinate the writing of additional tests.

An important use case for any new language feature is to ensure that the feature isn't accidentally used by package authors that have not yet opted into a language version that supports it. So in addition to testing that the new language feature works when the feature flag is turned on, the tests added to tests/language should verify that when the feature flag is turned off, the previous behavior of the SDK is preserved.

One important exception to preserving previous SDK behavior is that it's permissible (and even encouraged) to improve error messages so that if the user tries to use a disabled language feature, they receive an error explaining that they need to enable it, rather than, say, a confusing set of parse errors.

To enable the feature in a language test

// SharedOptions=--enable-experiment=$FEATURE

Include this comment near the top of the test (before the first directive), where $FEATURE is replaced with the feature name.

To disable the feature in a language test

// @dart=$VERSION

Include this comment near the top of the test (before the first directive), where $VERSION is the current stable release of Dart (and therefore is the largest version that is guaranteed not to contain the feature).

Google3 testing

New features should be tested in Google's internal code base before they are switched on.

Details of how to do this will be described in a separate (Google internal) document.

Implementation work

This is the bulk of creating a new language feature and this stage will take the most time.

Here are some tips for the implementation stage:

  • All implementation code should be under the experiment flag.
  • Use the language tests as a pseudo-checklist for what's left to implement.
  • Some teams may have their own checklist for what needs to be considered in a new language feature implementation. For example, this analyzer doc and this analysis server doc.
  • As we work through an implementation, we may encounter problems or holes in the spec. If so, create a new issue, add the feature label to it, and cc @dart-lang/language-team to discuss if we should make any changes in the specification.

Note

Remember that making a language feature is a two way street between the spec writers and the implementers. The implementation may change because the spec changed, or the spec might change after finding out the implementation is too complex.

Migrations

Once the implementation is finished, you should start a CL that enables the feature by default, if you haven't already. Use this CL to check what code your feature will break and determine if you need any other lints or quick-fixes to help these migrations.

See Google3 testing for more information on fixing breakages within Google3.

Shipping

This is a general checklist for shipping a feature:

  • Make sure all pre-migrations are complete.
  • Submit a CL that enables the feature by default in the upcoming version.
  • Follow up on documentation changes which should come out when the stable version with your feature comes out.
  • Communicate with the team that there's a new feature and invite everyone to test it out.

Congratulations! You've now shipped the feature.

Keep an eye out for breakages and any new QOL requests that surface from the usage of the feature. Sometimes people use features in ways we don't expect and we can learn a lot from seeing how the feature is used in the real world.

After shipping

After a feature has been shipped, the documents pertaining to the feature should be moved into subfolders carrying the name of the release in which they were shipped (e.g. 2.1).

For example, moving super-mixins to 2.1 after shipping:

/language

  /working
    super-mixins.md
    super-mixins-extra.md
    mikes-mixins.md
    spread-operator.md
    mega-constructors/
      proposal.md
      alternate.md
      illustration.png

  /accepted
    2.0/
    2.1/
      super-mixins/
        feature-specification.md
    future-releases/
      spread-operator/
        feature-specification.md
  /resources/
    [various supporting documents and resources]