| # Dart API Readability Rubric | 
 |  | 
 | [TOC] | 
 |  | 
 | ## Overview | 
 |  | 
 | This document describes heuristics and rules for writing Dart libraries that are | 
 | published in the Fuchsia SDK. | 
 |  | 
 | Unless otherwise specified, Fuchsia library authors should adhere to all the | 
 | heuristics and rules recommended by the Dart team itself under [Effective | 
 | Dart](https://www.dartlang.org/guides/language/effective-dart). Author’s should | 
 | familiarize themselves with all sections, | 
 | [Style](https://www.dartlang.org/guides/language/effective-dart/style), | 
 | [Documentation](https://www.dartlang.org/guides/language/effective-dart/documentation), | 
 | [Usage](https://www.dartlang.org/guides/language/effective-dart/usage) and | 
 | [Design](https://www.dartlang.org/guides/language/effective-dart/design) prior | 
 | to reading this rubric. | 
 |  | 
 | ### Terminology | 
 |  | 
 | There are some terms of art that Dart uses that conflict with Fuchsia’s | 
 | terminology. | 
 |  | 
 | - [Fuchsia | 
 |   package](/src/sys/pkg/bin/pm/README.md#structure-of-a-fuchsia-package): A | 
 |   Fuchsia package is one or more collections of files that provide one or more | 
 |   programs, components or services for a Fuchsia system. | 
 | - Fuchsia library: An informal definition for implementation code used by | 
 |   Fuchsia, usually found in lib or lib/src directories. Libraries are a | 
 |   convention, most policies for libraries are enforced socially or fallback to | 
 |   language specific approaches and tooling. | 
 | - [Dart package](https://dart.dev/guides/packages): The Dart package system is | 
 |   used to share software like libraries and tools within the Dart ecosystem, | 
 |   e.g. via Pub. Often a package is a collection of files with a minimum of a | 
 |   pubspec.yaml file and at least one Dart file, in-tree Dart packages will also | 
 |   have a `BUILD.gn` file. | 
 | - [Dart library](https://dart.dev/tools/pub/package-layout#public-libraries): A | 
 |   collection of Dart code (classes, constants, typedefs, etc.) isolated to a | 
 |   single namespace and corresponding to a single entry point, e.g. `import | 
 |   'package:enchilada/enchilada.dart';` imports the enchilada library. Note that | 
 |   Dart libraries have a privacy boundary, e.g. private implementation details | 
 |   are not visible or accessible outside of the library. A Dart package can | 
 |   contain multiple Dart Libraries. | 
 |  | 
 | When writing Dart code it is important to understand the distinction in | 
 | terminology in order to remain clear when communicating with team members whose | 
 | primary language might be one of the other supported languages (C++, Rust, | 
 | etc.). | 
 |  | 
 | - A Fuchsia package can contain components implemented as Dart binaries. | 
 | - A Dart binary is defined within a Dart package, and often has dependencies on | 
 |   other Dart packages. | 
 | - Code shared as a library in Fuchsia’s tree written in Dart is implemented as a | 
 |   Dart package. | 
 |  | 
 | ### Focus on the Interfaces | 
 |  | 
 | Public classes should expose a clean user interface that clearly describes the | 
 | API surface and is free from internal implementation details. Classes that | 
 | contain more than a minimal amount of functionality should expose their API in | 
 | an abstract class with the implementation inside a private implementation file. | 
 | Doing so allows for the users of the classes to focus on the public methods and | 
 | forces the implementer to think about the usage of the class before | 
 | implementation. | 
 |  | 
 | ### Consider Composability | 
 |  | 
 | When designing the API consider how it will fit into the larger Dart ecosystem | 
 | of libraries. For example, if writing an API that delivers events, consider | 
 | using Streams instead of callbacks because they compose better with libraries | 
 | like Flutter. | 
 |  | 
 | ## Lint Rules | 
 |  | 
 | Dart code written against the Fuchsia SDK should pass all the lint rules | 
 | specified by the | 
 | [analysis_options.yaml](https://fuchsia.googlesource.com/fuchsia/+/HEAD/analysis_options.yaml) | 
 | file, which lives in the topaz repository. These lint rules will help to automate | 
 | the review API review process. There are situations where a lint rule may be in | 
 | conflict with a specific API and may need to be explicitly ignored. If a file is | 
 | opting out of a lint rule the developer must provide a comment explaining the | 
 | reasoning for opting out of the lint rule. | 
 |  | 
 | ## Library Structure | 
 |  | 
 | When organizing the structure of a Dart package it is important to follow the | 
 | recommendations laid out by the [Effective | 
 | Dart](https://www.dartlang.org/guides/language/effective-dart) style guide. | 
 | Additionally, developers should consider how their code is exported. For a more | 
 | complicated package, developers should avoid a singular catch all top-level | 
 | export file and rather expose a top level file per logical grouping of classes | 
 | that make sense to be pulled under one import line. This allows users of the | 
 | library the ability to have finer grained control over which sections of the | 
 | library they import. | 
 |  | 
 | ## Comments/Documentation | 
 |  | 
 | All comments should adhere to [Effective Dart: | 
 | Documentation](https://www.dartlang.org/guides/language/effective-dart/documentation) | 
 | as well as the [Fuchsia Documentation](documentation.md) guide. | 
 |  | 
 | ## Dependencies | 
 |  | 
 | Packages written for the Dart Fuchsia SDK should not take on third party | 
 | dependencies that are not themselves also in the Fuchsia SDK. Exceptions will be | 
 | made for the following, well established, dependencies that are likely to be | 
 | present in all environments. Any packages that should be added to this list | 
 | must be approved by the [API | 
 | Council](/docs/contribute/governance/api_council.md). | 
 |  | 
 | - [logger](https://pub.dev/packages/logging) | 
 | - [meta](https://pub.dev/packages/meta) | 
 | - [intl](https://pub.dev/packages/intl) | 
 | - [flutter](https://flutter.dev/) | 
 |  | 
 |  | 
 | Packages that do take on external dependencies should consider whether they | 
 | want to reexport those symbols. If the dependency is reexported then the | 
 | generated documentation will generate documentation for the external dependency. | 
 | However, reexporting the dependency will create a tight coupling between package | 
 | versions. | 
 |  | 
 | ## Formatting | 
 |  | 
 | Code should be formatted using `dart format`. This is an opinionated tool that | 
 | cannot be configured. Formatting all of our code with this tool will ensure | 
 | consistency. In Fuchsia, you can use `fx format-code` will run `dart format` on | 
 | all staged dart files. | 
 |  | 
 | ## Files | 
 |  | 
 | - DO name files after their public class name | 
 | - PREFER placing each class into their own files, even if they’re private. It | 
 |   should be rare for multiple classes to live in the same file. Only private, | 
 |   small, simple and standalone classes can share a file with a public class. | 
 | - AVOID creating utility classes or libraries, these tend to turn into code | 
 |   dumping grounds. Instead, use precise naming that clearly communicates the | 
 |   purpose of the code being created. | 
 | - DON’T use the `part of` directive to avoid tight coupling of classes. | 
 |  | 
 | ### Methods | 
 |  | 
 | - PREFER using named parameters vs positional parameters for public methods on | 
 |   public classes that have greater than 2 parameters. This aids code refactor | 
 |   and allowed adding extra parameters without breaking the public API contract. | 
 | - AVOID using functions that can do more than one thing like `void | 
 |   updateAndCommit();` but prefer explicit naming. | 
 |  | 
 | ### Constructors | 
 |  | 
 | - PREFER using named parameters with Constructors that have more than two | 
 |   parameters. | 
 | - DO use the meta package to indicate which parameters are required. | 
 | - DO assert on required parameters. | 
 | - DO throw exceptions/errors for public APIs that will have detrimental side | 
 |   effects if invalid input is passed to constructors, since asserts do not run | 
 |   in release builds. | 
 |  | 
 | ``` | 
 | /// Constructs a [Car] object | 
 | /// | 
 | /// If [id] is not provided one will be | 
 | /// generated with a UUID4 format. | 
 | Car({ | 
 |   @required this.make, | 
 |   @required this.model, | 
 |   this.id, | 
 | }) : assert(make != null), | 
 |      assert(model != null); | 
 | ``` | 
 |  | 
 | ## Naming | 
 | If a method will use a cached object, or create it if it doesn’t exist, avoid | 
 | introducing or into the name. | 
 |  | 
 | ``` | 
 | class Node { | 
 |   //BAD | 
 |   Node getOrCreateChild(String name); | 
 |                | 
 |   //GOOD | 
 |   Node child(String name); | 
 | } | 
 | ``` | 
 |  | 
 | When adding a function or interface that will have methods invoked in response | 
 | to another action, name the methods add<NAME>Listener() and | 
 | remove<NAME>Listener(). The objects that implement the <NAME>Listener interface | 
 | should name the invoked methods on<EVENT>. | 
 |  | 
 | ``` | 
 | class MediaController { | 
 |   void addMediaListener(MediaListener listener) {} | 
 |   void removeMediaListener(MediaListener listener) {} | 
 | } | 
 |  | 
 | abstract class MediaListener { | 
 |   void onPause(); | 
 |   void onPlay(); | 
 | } | 
 | ``` | 
 |  | 
 | When appending an item to your object prefer the name add<Name> instead of | 
 | append to follow the dart list naming. | 
 |  | 
 | When deciding between using a single member abstract or a plain `Function` as a | 
 | `Listener` object consider how your API might evolve over time. If you expect | 
 | that you may add more methods to the listener use a single member abstract to | 
 | allow for the evolution but if the API is not likely to change use a plain | 
 | function. | 
 |  | 
 | ``` | 
 | // This could logically grow to include an onDoubleTap() | 
 | // method so it makes sense to use a single member abstract. | 
 | abstract class TapListener { | 
 |   void onTap(); | 
 | } | 
 | void addTapListener(TapListener listener) { ... }  | 
 |  | 
 | // This will likely never need more methods so it can  | 
 | // clearly take a function type. | 
 | void addOnCloseListener(void Function() listener) { ... } | 
 | ``` | 
 |  | 
 | ## Preferred Types | 
 | Concrete data types should be used instead of lower level primitives. The | 
 | following types should be used when possible: | 
 |  | 
 | - [Duration](https://api.dartlang.org/stable/2.4.0/dart-core/Duration-class.html) | 
 |   when working with a span of time. | 
 | - [DateTime](https://api.dartlang.org/stable/2.4.0/dart-core/DateTime-class.html) | 
 |   when working with dates. | 
 |  | 
 | If there is not a concrete type that can be used to represent your object at a | 
 | higher level your API should expose one. For example, if we had an API that | 
 | dealt with currency we would create a `Currency` data type instead of working | 
 | with `num` types. | 
 |  | 
 | ``` | 
 | // BAD | 
 | int getCash() { ... } | 
 |  | 
 | // GOOD | 
 | Currency getCash() { ... } | 
 | ``` | 
 |  | 
 | Your API should avoid returning unstructured JSON data but rather transform any | 
 | JSON into a typed value. | 
 |  | 
 | ``` | 
 | // BAD | 
 | Map<String, dynamic> getCar() => { | 
 |     'make': 'Toyota', | 
 |     'year': 2019,  | 
 | } | 
 |  | 
 | // Good | 
 | Car getCar() => Car(make: 'Toyota', year: 2019); | 
 | ``` | 
 |  | 
 | ## Internationalization | 
 | If a package exposes a user visible string the string should be | 
 | internationalized. In the absence of an ability to internationalize a user | 
 | visible string the API should return data in which a user of a library can | 
 | construct an internationalized string. | 
 |  | 
 | Exceptions and log messages do not need to be internationalized if they are not | 
 | intended to be user visible. | 
 |  | 
 | ## Error Handling | 
 | All error handling should adhere to [Effective Dart: Error | 
 | handling](https://www.dartlang.org/guides/language/effective-dart/usage#error-handling). | 
 |  | 
 |  | 
 | ## Error vs. Exception | 
 | Error and its subclasses are for programmatic errors that shouldn’t be | 
 | explicitly caught. An Error indicates a bug in your code, it should unwind the | 
 | entire call stack, halt the program, and print a stack trace so you can locate | 
 | and fix the bug. | 
 |  | 
 | Non-Error exception classes are for runtime errors. If your API implementation | 
 | throws an exception, it should be documented as part of the public API and it’s | 
 | expected behavior. This will facilitate programmatic handling of the exception | 
 | by API clients. | 
 |  | 
 | Except in a few special circumstances, idiomatic Dart should throw Errors, but | 
 | never catch them. They exist specifically to not be caught so that they take | 
 | down the app and alert the programmer to the location of the bug. | 
 |  | 
 | Note: often times people refer to Error when they mean Exception and vice versa. | 
 | Especially developers that are coming from a different language. Apply your | 
 | knowledge of their difference when developing your Dart API. | 
 |  | 
 | Your public API should throw well defined and typed exceptions so that users can | 
 | catch them and react appropriately. If you are not in control of all the code | 
 | that is being called by your package, maybe because you are using a third party | 
 | library, you may not be able to know exactly which exceptions may be thrown. If | 
 | this is the case, you can either attempt to catch the exception and wrap it in a | 
 | type that you create or clearly document that an exception of unknown type may | 
 | be thrown. | 
 |  | 
 | If your API can fail in more than one way the exception should clearly indicate | 
 | the failure method. Consider throwing different types of exceptions or adding a | 
 | code to the exception so the caller can respond appropriately. Also, don’t | 
 | forget to publicly document all the exceptions that are potentially thrown by a | 
 | given method. | 
 |  | 
 | ``` | 
 | enum ErrorCode { foo, bar } | 
 |  | 
 | class MyException implements Exception { | 
 |   final ErrorCode code; | 
 |   MyException(this.code); | 
 | } | 
 |  | 
 | /// Throws MyException(ErrorCode.foo) if condition is true or | 
 | /// throws MyException(ErrorCode.bar) if not  | 
 | void baz(bool condition) { | 
 |   If (condition) { | 
 |     throw MyException(ErrorCode.foo); | 
 |   } else { | 
 |     throw MyException(ErrorCode.bar); | 
 |   } | 
 | } | 
 | ``` | 
 |  | 
 | ### Assertions vs. Exceptions | 
 | Assertions should only be used to verify conditions that should be logically | 
 | impossible to be false due to programmer error, not user or data input. These | 
 | conditions should only be based on inputs generated by your own code. Any checks | 
 | based on external inputs should use exceptions. | 
 |  | 
 | Use asserts when you are in full control of the inputs. For example verify | 
 | private functions' arguments with asserts, and using exceptions for public | 
 | functions arguments. | 
 |  | 
 | In Dart all assertions are compiled out from the production/release builds. | 
 | Therefore, your program must work just as well when all assertions are removed. | 
 | Do not directly assert on a value returned directly from a function as this can | 
 | cause the code to not be included in release build since the entire body of the | 
 | assert is removed in release builds. | 
 |  | 
 | ``` | 
 | // BAD | 
 | assert(foo()); // foo is not executed | 
 |  | 
 | // GOOD | 
 | final success = foo(); | 
 | assert(success); | 
 | ``` | 
 |  | 
 | ### FIDL Exception Handling | 
 | In Fuchsia, the generated Dart FIDL bindings are always asynchronous, thus all | 
 | methods return a `Future` even if there is no return value (`Future<void>` is | 
 | used). Also, when connecting to a particular service the connection is assumed | 
 | to be successful even though it can fail to connect or disconnect in the future. | 
 | For these reasons, the caller of any FIDL api should always assume that a | 
 | specific call can fail and handle that appropriately when needed. | 
 |  | 
 | ``` | 
 | final _proxy = fidl_myService.MyServiceProxy(); | 
 | connectToService('fuchsia-pkg://fuchsia.com/my_service#meta/my_service.cm', _proxy); | 
 |  | 
 | _proxy | 
 |   .doSomething() | 
 |   .catchError((e, s) { | 
 |     // handle the error if needed | 
 |   }); | 
 | ``` | 
 |  | 
 | ## Testing | 
 | Please review [Dart](https://www.dartlang.org/guides/testing) and | 
 | [Flutter](https://flutter.dev/docs/testing) testing guides. | 
 |  | 
 | - DO test for `Future<T>` when disambiguating a `FutureOr<T>` whose type | 
 |   argument could be Object. | 
 | - DON’T use `@visibleForTesting` on public API. | 
 |  | 
 | The API surface of your package should be well tested. However, the public API | 
 | should not need to leak internal details for the class to be testable. Consider | 
 | the following example: | 
 |  | 
 | ``` | 
 | class Foo { | 
 |   // services is exposed for testing | 
 |   Foo({GlobalServices services = GlobalServices()}) { … } | 
 |  | 
 |   // Connects to the global service with the given name. | 
 |   Connection connectToGlobalService(String name) { | 
 |      return services.connect(name); | 
 |   } | 
 | } | 
 | ``` | 
 |  | 
 | Rather, consider writing your class as an abstract class so the user does not | 
 | need to know about the injection of global services but tests can directly | 
 | inject the global services into the implementation. These avoids leaking | 
 | implementation details to the user and provides an API that the user cannot | 
 | abuse or mess up. This has the added advantage of allowing the API to evolve if | 
 | the GlobalServices class evolves without having to change the callers of the | 
 | method. | 
 |  | 
 | ``` | 
 | // foo.dart | 
 | abstract class Foo { | 
 |   factory Foo() => FooImpl(services: GlobalServices); | 
 |   connectToGlobalService(String name); | 
 | } | 
 |  | 
 | // internal/foo_impl.dart | 
 | class FooImpl implements Foo { | 
 |   FooImpl({GlobalServices services}) { … } | 
 |  | 
 |   // Connects to the global service with the given name. | 
 |   Connection connectToGlobalService(String name) { | 
 |      return services.connect(name); | 
 |   } | 
 | } | 
 | ``` | 
 |  | 
 | Dart does not allow a private class/function to be accessed from within a test. | 
 | This has the effect that any private classes cannot be tested. This may be ok if | 
 | there is a corresponding public class/function that can exercise the private | 
 | members but this may not always be the case. In these situations it is best to | 
 | move the private class into its own file, which does not get exported by the | 
 | top-level export, and make it public. The tests can now access your private | 
 | members. | 
 |  | 
 | ``` | 
 | /// BAD - this code does not make _Taco directly testable | 
 |  | 
 | // dinner.dart | 
 | class Dinner { | 
 |   final _taco = _Taco(); | 
 |    | 
 |   void eat() => _taco.consume(); | 
 | } | 
 |  | 
 | // We have no way to directly test this class | 
 | class _Taco { | 
 |   void consume() {} | 
 | } | 
 |  | 
 | /// GOOD - this code makes Taco directly testable by moving it to its own private file | 
 |  | 
 | // dinner.dart | 
 | import '_taco.dart'; | 
 |  | 
 | class Dinner { | 
 |   final _taco = Taco(); | 
 |   void eat() => _taco.consume(); | 
 | } | 
 |  | 
 | // _taco.dart  | 
 | class Taco { | 
 |   void consume() {} | 
 | } | 
 |  | 
 | // _taco_test.dart | 
 | import 'package:dinner/src/_taco.dart' // ignore: implementation_imports | 
 |  | 
 | void main() { | 
 |   test('taco consumption', () { | 
 |     expect(_Taco().consume(), runsNormally); | 
 |   }); | 
 | } | 
 | ``` | 
 |  | 
 | ## Design Patterns | 
 | ### Disallowing Subclassing | 
 | It can be useful for a library to declare a common base class without allowing | 
 | developers to extend the common base class. The common pattern for supporting | 
 | this is to declare a private constructor on your public base class. This has the | 
 | effect of allowing subclasses within the same file to extend the base class | 
 | while not allowing users of your library to subclass the base class. | 
 |  | 
 | ``` | 
 | /// Base class | 
 | abstract class A { | 
 |   // private constructor disallows instantiation outside of this file | 
 |   ._(); | 
 |   /// Concrete implementation of foo | 
 |   void foo() {} | 
 | } | 
 |  | 
 | /// A concrete implementation of [A] | 
 | class B extends A { | 
 |   () : super._(); | 
 |  | 
 |   @override | 
 |   void foo() { | 
 |     // B implementation | 
 |     super.foo(); | 
 |   } | 
 | } | 
 | ``` | 
 |  | 
 | It is important to note that this pattern does not restrict users from | 
 | subclassing the child class since it has a public constructor. If this | 
 | restriction is required see the factory constructors pattern below. | 
 |  | 
 | This pattern is useful if the implementation surface is small since the pattern | 
 | requires all of the subclasses to live in the same file as the base class or to | 
 | use the part of directive, which is discouraged. If the surface area is too large | 
 | for a single file consider an alternate pattern. | 
 |  | 
 |  | 
 | ### Factory Constructors | 
 |  | 
 | There are times when a user only needs to interact with a single interface but | 
 | which may have a different implementation depending on how the object was | 
 | constructed. Requiring the user to know about the different implementations can | 
 | add unnecessary APIs, and only serves to confuse the user. In this | 
 | situation you can define an abstract base class that defines the API surface | 
 | and create factory constructors that vend the appropriate private class. | 
 |  | 
 | ``` | 
 | // Publicly exported class | 
 | abstract class Foo { | 
 |    | 
 |   factory Foo() => FooImpl(); | 
 |  | 
 |   factory Foo.withNamespace(String namespace) => NamespacedFoo(namespace); | 
 |  | 
 |   void update(String value); | 
 |   void revert(); | 
 | } | 
 |  | 
 | // Private implementations not exported in public API | 
 | class FooImpl implements Foo { | 
 |   final _values = <String>[]; | 
 |  | 
 |   @override | 
 |   void update(String name) => _values.add(name); | 
 |  | 
 |   @override | 
 |   void revert() => _values.removeLast(); | 
 | } | 
 |  | 
 | class NamespacedFoo extends FooImpl { | 
 |   final String namespace; | 
 |   NamespacedFoo(this.namespace); | 
 |  | 
 |   @override | 
 |   void update(String name) => super.update('$namespace/$name'); | 
 | } | 
 | ``` | 
 |  | 
 | Note: If you need to add the restriction that the base class cannot be extended | 
 | you can implement the pattern defined in Disallowing Subclassing that adds a | 
 | private constructor to the public base class | 
 |  | 
 | ### Working with FIDLs | 
 |  | 
 | Try to make a clear distinction between regular object types and FIDL types. | 
 | This makes it easier for the maintainers of the code to identify FIDL types from | 
 | other types and take the necessary precautions when needed. Consider using the | 
 | as when importing a FIDL service and prefixing it with “fidl_”, this makes it | 
 | very to identify FIDL types across the entire file. | 
 |  | 
 | ``` | 
 | import 'package:fidl_fuchsia_foo/fidl_async.dart' as fidl_foo; | 
 |  | 
 | // now it is clear that the return type bar comes from fidl_foo | 
 | fidl_foo.Bar myMethod(String baz) {...}  | 
 | ``` | 
 |  | 
 | When subclassing FIDL types extend them so they can be interchanged with the | 
 | generated FIDL files. Usually, wrappers decorate the existing type with | 
 | additional functionality that compliments the original object. However, by | 
 | extending it from the original FIDL it allows the existing and new API to work | 
 | with original FIDL types instead of the more concrete types, which is useful when | 
 | interacting with other FIDLs or when developers are not using your wrapper. | 
 |  | 
 | ### Decoupling implementation concerns | 
 |  | 
 | Try to avoid interfaces that cover multiple areas of concerns. By breaking down | 
 | the concerns users can have more flexibility with how they choose to combine the | 
 | interfaces and allows composed objects to be passed to methods with specific | 
 | concerns. | 
 |  | 
 | ``` | 
 | void main() { | 
 |   final restaurant = lookupRestaurant(); | 
 |   map.display(restaurant); | 
 |   phone.call(restaurant); | 
 | } | 
 |  | 
 | abstract class Callable { | 
 |   String get phoneNumber; | 
 | } | 
 |  | 
 | abstract class Location { | 
 |   String get address; | 
 |   String get displayName; | 
 | } | 
 |  | 
 | class Restaurant implements Callable, Location { | 
 |   final String name; | 
 |   final String phoneNumber; | 
 |   final String address; | 
 |   String get displayName => name; | 
 |  | 
 |   Restaurant(this.name, this.phoneNumber, this.address); | 
 | } | 
 |  | 
 | class Map { | 
 |   void display(Location descriptor) {} | 
 | } | 
 |  | 
 | class Phone { | 
 |   void call(Callable callable) {} | 
 | } | 
 | ``` | 
 |  | 
 | ### Iteration of Modifiable Collections | 
 | When exposing an API that can modify some sort of collection it is important to | 
 | protect against modifying the collection during iteration. When iterating over | 
 | an internal collection consider making a copy of the backing collection to | 
 | iterate. This will protect from exceptions being thrown for concurrent | 
 | modification of the underlying collection. | 
 |  | 
 | ``` | 
 | class Controller { | 
 |   final _listeners = <void Function()>[]; | 
 |   void addListener(void Function() f) => _listeners.add(f); | 
 |   bool removeListener(void Function() f) => _listeners.remove(f); | 
 |  | 
 |   void notify() { | 
 |     // Make a copy to avoid modification of _listeners during iteration. | 
 |     for (final f in List.of(_listeners)) { | 
 |       // This method can safely call add/remove listeners | 
 |       f(); | 
 |     } | 
 |   }     | 
 | } | 
 | ``` | 
 |  | 
 | ## Anti Patterns | 
 |  | 
 | The following patterns should be avoided when writing Dart libraries for the | 
 | Fuchsia Dart SDK. Exposing Internal Details for Testing It may be tempting to | 
 | expose certain aspects of your API for testing concerns. However, doing so can | 
 | clutter your public interface and leak implementation details that the user | 
 | does not need to know about or may come to rely on. See the [Testing](#Testing) | 
 | section for more details | 
 |  | 
 | ### Accepting/Returning dynamic Types | 
 |  | 
 | Dart provides a dynamic type for which the compiler will allow any type to be | 
 | passed to a function and returned from a function. This can be useful in some | 
 | situations like json encoding/decoding but in the general case it should be | 
 | avoided. Using dynamic types prevents the compiler from performing static type | 
 | checking at compile time and introduces hard to debug run-time errors. | 
 |  | 
 | In situations where an API might need to accept/return multiple input types | 
 | consider using generics or defining an interface that the object implements | 
 | instead. In situations where this will not work, consider defining multiple | 
 | methods that call through to the private dynamic accepting function. | 
 |  | 
 | ### Using Private Methods Across Files | 
 |  | 
 | Dart distinguishes private members from public members by prefixing them with | 
 | the underscore. This creates isolation between files reduces coupling. This can | 
 | be overridden by using the `part of` directive at the top of a file. This | 
 | directive has the effect of combining multiple files and allowing them to access | 
 | each others private members. Doing this makes it hard to rationalize about what | 
 | is public and what is private and creates tight coupling between classes. Rather | 
 | than using this directive, it is recommended to only interact with another | 
 | object via its public interfaces. If classes must interact via private | 
 | interfaces it is recommended to keep them in the same file to clearly indicate | 
 | their relationship. | 
 |  | 
 | ### Global Static Variables | 
 |  | 
 | Global static variables can be useful in sharing state across a library but they | 
 | can easily introduce race conditions and hard to debug code. Global variables | 
 | can also be accessed by users of your library, which may introduce unexpected | 
 | side effects. It is strongly recommended that you avoid global static variables | 
 | in public libraries. | 
 |  | 
 | If there is a reason that your package does need to use a global static variable | 
 | it is recommended to use zone-local static variables instead to isolate the | 
 | variable from users of your library. | 
 |  | 
 | ``` | 
 | void startComputation() { | 
 |   runZoned(() async { | 
 |     await collectScores(getValues()); | 
 |     print('Scores: ${Zone.current[#scores]}'); | 
 |   }, zoneValues: {#scores: <int>[]}); | 
 | } | 
 |  | 
 | Future<void> collectScores(Stream<int> scores) async { | 
 |   await for (int value in scores) { | 
 |     Zone.current[#scores].add(value); | 
 |   } | 
 | } | 
 |  | 
 | // scores will not be affected by the call to startComputation. | 
 | final scores = <int>[1, 2, 3]; | 
 |  | 
 | void main() { | 
 |   startComputation(); | 
 | } | 
 | ``` |