Skip to content

proposal: avoid_library_cycles #57141

@jakemac53

Description

@jakemac53

avoid_library_cycles

Description

Library cycles should be avoided, because they can negatively affect hot reload and other tooling.

Details

It is challenging for tools to deal efficiently with large library cycles, and in many cases it means that any change to any library in the cycle will have to recompile (or re-link at least) every single library in the cycle.

Breaking up your libraries into smaller parts, or sometimes separating interfaces from implementations, can enable you to break these library cycles, leading to a better development experience.

Kind

Encourages good organization and loose coupling between libraries.

Bad Examples

a.dart:

import 'b.dart' as b;  // lint, avoid_library_cycles

final variableThatUsesB = '${b.variableInB}'; 

final someOtherVariable = 'hello';

b.dart:

import 'a.dart' as a; // lint, avoid_library_cycles

final String variableInB = '${a.someOtherVariable}';

Good Examples

We can break the cycle, by moving someOtherVariable into a new library, c.dart:

a.dart:

import 'b.dart' as b;

final variableThatUsesB = '${b.variableInB}'; 

b.dart:

import 'c.dart' as c;

final String variableInB = '${c.someOtherVariable}';

c.dart:

final someOtherVariable = 'hello';

Discussion

I analyzed several apps from itsallwidgets.com, under the suspicion that many apps devolved into a state where they would have a single large library cycle. The result is here https://gist.github.com/jakemac53/6ca8d58723f243926c1494323c91e664 (keys are cycle size, values are the number of library cycles of that size).

You can see that for these example apps, while some are well structured, it was indeed common to have at least one large library cycle, mixed with a bunch of single library cycles. In the worst case, the large cycle was 268 libraries, over 80% of the app.

For the macros feature in particular, we are struggling with a way to deal efficiently with these large library cycles, and currently must re-run all macros across the entire cycle whenever any edit is made.

Discussion checklist

  • List any existing rules this proposal modifies, complements, overlaps or conflicts with.
  • List any relevant issues (reported here, the SDK Tracker, or elsewhere).
  • If there's any prior art (e.g., in other linters), please add references here.
  • If this proposal corresponds to Effective Dart or Flutter Style Guide advice, please call it out. (If there isn't any corresponding advice, should there be?)
  • If this proposal is motivated by real-world examples, please provide as many details as you can. Demonstrating potential impact is especially valuable.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3A lower priority bug or feature requestarea-devexpFor issues related to the analysis server, IDE support, linter, `dart fix`, and diagnostic messages.devexp-linterIssues with the analyzer's support for the linter packagelinter-lint-proposallinter-status-pendingtype-enhancementA request for a change that isn't a bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions