dart-code-metrics icon indicating copy to clipboard operation
dart-code-metrics copied to clipboard

[New rule] Build method metrics

Open Pomis opened this issue 3 years ago • 2 comments

Would be nice to have separate metrics for build method, since some developers tend to bloat them.

I would propose having two metrics,

build-method-max-length: 30
build-method-max-nesting: 5

One, that would basically count lines of code. I assume, build method could be allowed to be a bit longer that regular methods, so in some project this separation could be useful. Another one to count, how many widgets are nested to each other

What category of rule is this? (place an "X" next to just one item)

[X] Warns about a potential error (problem) [ ] Suggests an alternate way of doing something (suggestion) [ ] Other (please specify:)

BAD:

@override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: hideKeyboard,
      child: Column(
        children: [
          const SimpleAppBar(
            showMenu: true,
          ),
          Expanded(
            child: Observer(
              builder: (_) {
                return SmartRefresher(
                  onRefresh: _onRefresh,
                  dragStartBehavior: DragStartBehavior.down,
                  controller: _refreshController,
                  header: ClassicHeader(
                    refreshingText: 'keywords_ss.refreshing'.tr(),
                    releaseText: 'keywords_ss.releaseToRefresh'.tr(),
                    idleText: 'keywords_ss.pullDownToRefresh'.tr(),
                    failedText: 'keywords_ss.refreshFailed'.tr(),
                    completeText: 'keywords_ss.refreshCompleted'.tr(),
                  ),
                  scrollController: scrollController,
                  child: SingleChildScrollView(
                    controller: scrollController,
                    child: Column(
                      mainAxisSize: MainAxisSize.min,
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        _welcomeCard(),
                        if (_showEmployeePackageBanner)
                          Padding(
                            padding: const EdgeInsets.only(top: 40),
                            child: EmployeePackageWidget(
                              onHide: () async {
                                promoCodeState.hasIntroDone = true;
                                await StorageHelper.setSimpleIntroSkippedUsers(
                                    authState.currentUser!.id);
                              },
                            ),
                          ),
                        if (homeState.events.isNotEmpty &&
                            (authState.hasMarketplaceVisible ||
                                _user.company != null)) ...[
                          ContentTitle(
                            title: 'ss_upcomingConsultations'.tr(),
                          ),
                          EventsList(
                            events: homeState.events,
                            onBookAnAppointmentTap: _bookAnAppointment,
                          ),
                        ],
                        ..._shortcuts(),
                        SizedBox(
                          height: DisplaySizeHelper.screenPadding.bottom + 16,
                        ),
                      ],
                    ),
                  ),
                );
              },
            ),
          ),
        ],
      ),
    );
  }

GOOD:

@override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(
          'ss_turnOnLocationSettings'.tr(),
          style: context.h4,
        ),
        const SizedBox(height: 24),
        LoadingButton(
          text: 'ss_goToSettings'.tr(),
          onPressed: () async {
            await openAppSettings();
            Navigator.pop(context, true);
          },
        ),
        const SizedBox(height: 8),
        LoadingButton.link(
          text: 'ss_noThanks'.tr(),
          onPressed: () {
            Navigator.pop(context, false);
          },
        )
      ],
    );
  }

Are you willing to submit a pull request to implement this rule? Not sure

Pomis avatar Dec 09 '21 17:12 Pomis

Probably, it could be useful to have a suggestion for extracting the widget, if:

  • it's complex enough (has more than N subwidgets);
  • has no dependency on the current widget.

ookami-kb avatar Dec 09 '21 17:12 ookami-kb

I think it could be a useful change for Flutter developers

Cilestal avatar Dec 10 '21 09:12 Cilestal

Available in Teams 1.3.0, https://dcm.dev/docs/metrics/number-of-used-widgets/ and https://dcm.dev/docs/metrics/widgets-nesting-level/

incendial avatar Apr 06 '23 18:04 incendial