スケーラブルなフラッタアプリの構築(アーキテクチャ,スタイリング,コンベンション,状態管理)


フラッピングの2年後、私はこの記事では、スケーラブルなアプリケーションを構築する方法を学んだベストプラクティスを共有したいと思います.
私はあなたがすべきことを言うつもりはない.このガイドラインは、あなたと、他の誰もがアプリケーションを維持することを確認し、簡単かつ直感的に探しているものを見つけることができます.
それは、あなたがそれを達成する方法を議論しましょう.

1 )アーキテクチャ:特徴ベース


機能は、任意のソフトウェア設計を理解するために不可欠な概念です.また、ソフトウェア開発のためのユーザー要件を記述するために使用されます.したがって、我々がプロジェクトによってプロジェクトを構成するならば、より大きな単位でシステムを構築するとき、それがプロジェクトを管理するのはより簡単です.

機能によるプロジェクトの整理


複雑なアプリケーションでは、どのように異なるモジュールのコラボレーションを理解するのは難しいです.機能指向のアーキテクチャは、関連するロジックをグループ化したので、これに役立ちます(widgets|utils|pages|stores|models|..etc) 機能に.私たちは小さな部品がどのように一緒に働くが、どのように機能を一緒にアプリケーションを構築する作業を考える必要はありません.機能の間の依存関係を分析することによって、アプリは自動的に開発者のための理解できるダイアグラムを生成したり、プロジェクトを確認することができます.

機能タイプ


どんな特徴も汚染されるのを防ぐために、その特徴のビジネスロジックをそのプレゼンテーションから切り離すことは重要です.だからこそ、我々は2つの異なる層にアプリケーションを分割する必要があります:
  • インフラストラクチャの機能:アプリケーションのビジネスロジックを実装するための責任を負っているすべての機能が含まれています
  • アプリの特徴:アプリケーションのプレゼンテーションを実装するための責任があるすべての機能が含まれています
  • Notice that auth, user, events, articles, …etc. features can be both infrastructure and app features, so what is the difference? that’s what we will discuss in the next section (Features anatomy).



    機能解剖


  • インフラストラクチャの特徴:サービス、リポジトリ、モデル、DTOS、utils、インターセプター、バリデータ、インターフェイス、など

  • アプリケーション機能:ページ、ウィジェット、スタイル、フォント、色などを維持します.
  • Note: An app feature may consume multiple Infrastructure features



    2 )命名規則:命名ファイル


    ヘビケース


    SnakeRankケースは、名前のすべての文字が小文字であり、名前の単語を分離するためにアンダースコアを使用する命名スタイルです.また、角度では、ドット名を使用して、ファイル名の名前、種類、および拡張を分離します.file_name.type.dartファイル名の型を含めて、テキストエディタまたはIDEを使用して特定のファイルタイプを見つけることが容易になります.
    最も一般的なファイルタイプは以下の通りです.ウィジェット、.スタイルサービス.モデル.util ,店

    Create additional type names if you must but take care not to create too many.


  • file_name.widget.dart
  • file_name.style.dart
  • file_name.model.dart
  • file_name.util.dart
  • 3 )状態管理:プロバイダ+ mvvm


    状態管理はフラッターの複雑な話題です.各状態管理アプローチは、その特性を持って、それぞれの人が異なる設定を持っています.私にはProvider それは理解しやすいですので、それは多くのコードを使用していない最高の選択です.
    つまり、プロバイダー自体はスケーラブルアプリを構築するのに十分ではないので、プロバイダとMVVMの両方の機能を組み合わせた状態管理のためのパッケージを構築してPMVVM .

    MVVM


    PMVVMでは3つの主要な作品が必要です、他のすべてはあなた次第です.これらは以下の通りです.

  • ビュー:それはアプリケーションのロジックを欠いてのUIを表します.The ViewModel 通知を送信しますview 状態変更時にUIを更新するには

  • ViewModel :それはModelView . これは、データからの変換に責任がありますModel , また、このイベントの開催View

  • モデル:アプリケーションのデータとビジネスロジックを保持します.ビジネスロジック-ローカルおよびリモートデータソース、モデルクラス、リポジトリから成ります.通常は単純なクラスです.

  • 利点✔️
  • あなたのコードはさらに簡単にテスト可能です.
  • あなたのコードはさらに切り離されます(最大の利点)
  • パッケージ構造はさらに簡単にナビゲートします.
  • プロジェクトはさらに簡単に維持することです.
  • あなたのチームは、さらに迅速に新機能を追加することができます.
  • 使用するとき👌
    シンプルに保つには、MVVM あなたのウィジェットが直接状態を突然変異させることができる独自のイベントがあるときはいつでも、ページ:ポスト、..など
    いくつかの注意
  • View アクセスできませんModel 直接
  • View 任意のアプリケーションロジックが欠けている
  • ViewModel を超えるView .
  • 用途


    ビルドViewModel .
        class MyViewModel extends ViewModel {
          int counter = 0;
    
          // Optional
          @override
          void init() {
            // It's called after the ViewModel is constructed
          }
    
          // Optional
          @override
          void onBuild() {
            // It's called everytime the view is rebuilt
          }
    
          void increase() {
            counter++;
            notifyListeners();
          }
        }
    
    また、context インサイドViewModel 直接
        class MyViewModel extends ViewModel {
          @override
          void init() {
            var height = MediaQuery.of(context).size.height;
          }
        }
    
    2 .宣言MVVM ウィジェットの内部.
        class MyWidget extends StatelessWidget {
          const MyWidget({Key key}) : super(key: key);
    
          @override
          Widget build(BuildContext context) {
            return MVVM<MyViewModel>(
              view: (context, vmodel) => _MyView(),
              viewModel: MyViewModel(),
            );
          }
        }
    
    ビルドView .
        class _MyView extends StatelessView<MyViewModel> {
          /// Set [reactive] to [false] if you don't want the view to listen to the ViewModel.
          /// It's [true] by default.
          const _MyView({Key key}) : super(key: key, reactive: true); 
    
          @override
          Widget render(context, vmodel) {
            return Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: <Widget>[
                Text(vmodel.counter.toString()),
                SizedBox(height: 24),
                RaisedButton(onPressed: vmodel.increase, child: Text('Increase')),
              ],
            );
          }
    

    For more details, head to the package documentation


    ウェブ,モバイル,デスクトップ用P . MVVM

    pmvvm あなたのアプリケーションが複数のプラットフォーム上で動作する場合は特に完全に動作します.必要なのは、これらのビューをすべて表示する単一のビューモデルを作成することです.

    スタイリング


    フラッターでは、しばしば色、文字列、テキストのスタイル、テーマのファイルを作成します.これらの値のすべてのこの方法は、簡単にアプリを維持すると立ち往生する人のための生活を容易にする必要があります場所を見つけるために保持されます.

    機能としてのスタイリング


    グループすべきapp-wide 色、フォント、テーマ、およびアニメーションと呼ばれるアプリの機能としてstyles . このアプローチは、アプリケーション内のすべてのウィジェットが単一のソースからスタイルを消費するようになります.
    例:colors.style.dart
        abstract class CColors {
          static const white0 = Color(0xffffffff);
          static const black100 = Color(0xff000000);
          static const blue10 = Color(0xffedf5ff);
          static const blue20 = Color(0xffd0e2ff);
          static const blue30 = Color(0xffa6c8ff);
        }
    
    text.style.dart
        abstract class CFonts {
          static const primaryRegular = 'IBMPlexSans-Regular';
          static const primaryLight = 'IBMPlexSans-Light';
          static const primaryMedium = 'IBMPlexSans-Medium';
          static const primarySemibold = 'IBMPlexSans-SemiBold';
          static const primaryBold = 'IBMPlexSans-Bold';
        }
    

    More examples can be found Here


    ウィジェットスタイリング


    あなたのウィジェットが複雑で、特定の行動(例えば、ボタンがタップされるとき、背景色変化)に基づく何らかの反応的なふるまいを持つならば、あなたはおそらくウィジェット・コードからあなたのウィジェット・カラーとレイアウト変数を切り離す必要があるでしょう.
    例:tile.style.dart
        abstract class TileStyle {
          static const Map<String, dynamic> layouts = {
            'tile-padding': const EdgeInsets.all(16),
          };
          static const Map<String, Color> colors = {
            'tile-enabled-background-color': CColors.gray90,
            'tile-enabled-label-color': CColors.gray30,
            'tile-enabled-title-color': CColors.gray10,
            'tile-enabled-description-color': CColors.gray30,
            //
            'tile-disabled-background-color': CColors.gray90,
            'tile-disabled-label-color': CColors.gray70,
            'tile-disabled-title-color': CColors.gray70,
            'tile-disabled-description-color': CColors.gray70,
          };
        }
    
    tile.widget.dart
     class CTile extends StatelessWidget {
      const CTile({
        Key? key,
        this.enable = true,
        ...
      }) : super(key: key);
    
      final bool enable;
    
      final _colors = CTileStyle.colors;
      final _layouts = CTileStyle.layouts;
    
      @override
      Widget build(BuildContext context) {
        /// styles helpers
        String cwidget = 'tile';
        String state = enable ? 'enabled' : 'disabled';
    
        return IgnorePointer(
          ignoring: !enable,
          child: Container(
            color: _colors['$cwidget-$state-background-color'],
            padding: _layouts['$cwidget-padding'],
            child: ....,
          ),
        );
      }
    }
    
    

    More examples can be found Here


    結論


    この記事では、大きなアプリケーション開発に必要な4つの主要な事柄をカバーしました.
    ここではその概要を示します.
  • 一緒に動作する機能のセットとしてアプリケーションを構築します.
  • ファイル名を使用して各DARTファイルの種類を定義します.種類ダート.
  • MVVMを使用してあなたの状態を管理するブロックなどの他の選択肢よりも簡単です.
  • あなたのウィジェットスタイルをプレゼンテーションコードから切り離してください.
  • ソースコード


    この記事の完全な例を見つけることができますhere