flutterdartidiomsutility-method

How to write Dart idiomatic utility functions or classes?


I am pondering over a few different ways of writing utility classes/functions. By utility I mean a part of code being reused in many places in the project. For example a set of formatting functions for the date & time handling.

I've got Java background, where there was a tendency to write

class UtilsXyz {
  public static doSth(){...};
  public static doSthElse(){...};
}

which I find hard to unit test because of their static nature. The other way is to inject here and there utility classes without static members.

In Dart you can use both attitudes, but I find other techniques more idiomatic:

  1. mixins

Widely used and recommended in many articles for utility functions. But I find their nature to be a solution to infamous diamond problem rather than utility classes. And they're not very readable. Although I can imagine more focused utility functions, which pertain only Widgets, or only Presenters, only UseCases etc. They seem to be natural then.

  1. extension functions

It's somehow natural to write '2023-01-29'.formatNicely(), but I'd like to be able to mock utility function, and you cannot mock extension functions.

  1. global functions

Last not least, so far I find them the most natural (in terms of idiomatic Dart) way of providing utilities. I can unit test them, they're widely accessible, and doesn't look weird like mixins. I can also import them with as keyword to give some input for a reader where currently used function actually come from.

Does anybody have some experience with the best practices for utilities and is willing to share them? Am I missing something?


Solution

  • To write utility functions in an idiomatic way for Dart, your options are either extension methods or global functions.

    You can see that they have a linter rule quoting this problem:

    AVOID defining a class that contains only static members.

    Creating classes with the sole purpose of providing utility or otherwise static methods is discouraged. Dart allows functions to exist outside of classes for this very reason.

    https://dart-lang.github.io/linter/lints/avoid_classes_with_only_static_members.html.


    Extension methods.

    but I'd like to unit test some utility functions, and you cannot test extension functions, because they're static.

    I did not find any resource that points that the extension methods are static, neither in StackOverflow or the Dart extension documentation. Although extension can have static methods themselves. Also, there is an open issue about supporting static extension members.

    So, I think extensions are testable as well.

    To test extension methods you have 2 options:

    EDIT: as jamesdlin mentioned, the extension themselves can be tested but they cannot be mocked since they need to be resolved in compile time.


    Global functions.

    To test global functions, just import and test it.

    I think the global functions are pretty straightforward:

    That's why I prefer this approach for utility functions that are not attached to any other classes.

    And, if you are writing a library/package, the annotation @visibleForTesting may fall helpful for you (This annotation is from https://pub.dev/packages/meta).