フロントに処理を書くとき、フレームワーク内で処理は書かない方がいい気がする

2020/06/17 2020/06/17 #Vue #フロント

フロントに処理を書くとき、フレームワーク内で処理は書かない方がいい気がする

こんにちはNonです。
今回はこれまでと変わってフロントに着目したいと思います。

前提

  • (laravel-mixでの)Vue

フレームワーク内で処理を書くとこうなる

export default {
  name: 'ApplicationComponent',
  data() {
    return {
      food: {
        name: '',
        price: 0,
        num: 0,
      },
      drink: {
        name: '',
        price: 0,
        num: 0,
      },
      sum: {
        price: 0,
        num: 0,
      },
      tax: 0.08,
    };
  },
  created() {
    this.food.name = 'おにぎり';
    this.food.price = 100;
    this.food.num = 3;
    this.drink.name = 'お茶';
    this.drink.price = 150;
    this.drink.num = 1;
  },
  computed: {
    sum() {
      return {
        price: this.calcTax(this.food.price, this.food.num) + this.calcTax(this.drink.price * this.drink.num),
        num: this.food.num + this.drink.num,
      };
    }
  },
  methods: {
    calcTax(price, num) {
      return price * (1 + this.tax) * num;
    },
  }
};

コンポーネント単位でこのような処理を書くと、違うコンポーネントのロジックを書くときに、計算方法を間違えそうになるかもしれません。

そこで、計算処理、つまりビジネスロジックを持つモデルを外部のjsで持つことでロジックの重複を防ぎます。

フレームワーク内はレンダリングに注力し、処理は他のパッケージで持つ

フレームワーク内はレンダリング、つまり値の監視や、コンポーネントの管理などはフレームワーク(ここではVue)で行い、フロントで行うべき処理であるビジネスロジックはモデルとして外部に持つようにします。すると下記のようになります。

export default {
  name: 'ApplicationComponent',
  data() {
    return {
      food: {
        name: '',
        price: 0,
        num: 0,
      },
      drink: {
        name: '',
        price: 0,
        num: 0,
      },
      sum: {
        price: 0,
        num: 0,
      },
      tax: 0.08,
    };
  },
  created() {
    this.food.name = 'おにぎり';
    this.food.price = 100;
    this.food.num = 3;
    this.drink.name = 'お茶';
    this.drink.price = 150;
    this.drink.num = 1;
  },
  computed: {
    sum() {
      const productCollection = new ProductCollection([
        new Product(this.food.name, this.food.price, this.food.num),
        new Product(this.drink.name, this.drink.price, this.drink.num),
      ]);
      return {
        price: productCollection.sumPrice(),
        num: productCollection.sumNum(),
      };
    }
  }
};
export class ProductCollection
{
  constructor(items = []) {
    this.items = items;
  }

  sumPrice() {
    return this.items.reduce((previous, current) => {
      return previous.sumPrice() + current.sumPrice();
    });
  }

  sumNum() {
    return this.items.reduce((previous, current) => {
      return previous.num + current.num;
    });
  }
}
export class Product
{
  static get TAX() {
    return 0.08;
  }

  constructor(name, price, num) {
    this.name = name;
    this.price = price;
    this.num = num;
  }

  calcTax() {
    return this.price * (1 + this.TAX);
  }

  sumPrice() {
    return this.calcTax() * this.num;
  }
}

このように、商品のビジネスロジックをクラスの中に封じ込め、更にフレームワーク依存しない箇所に集めることで、使い回すことを可能にしています。

さらに、フレームワーク依存しないので、他のフレームワークに移行するときにも重宝します。

Vueの場合、mixinに書けばいいじゃん?

もちろん、Vueに依存することを前提にしている場合はそれでもいいですが、HelperやUtilのような役回りが多いmixinにビジネスロジックを書くのはいかがなものでしょうか?

〇〇mixinが多くなってしまうのが、目に見えます。

クラス(オブジェクト)のパワーを借りることができる。

例えば、バリデーターを自作したとして、このようなクラス作成します。

export class StringValidator
{
  constructor(value) {
    this.value = value;
    this.result = [];
    this.messages = [];
  }

  max(length) {
    this.result.push(this.value.length > length);
    this.messages.push(length + '文字以下で入力してください。');
    return this;
  }

  min(length) {
    this.result = this.value.length < length;
    this.messages.push(length + '文字以上で入力してください。');
    return this;
  }

  number() {
    this.result = Number.isInteger(this.value);
    this.messages.push('半角数字のみで入力してください。');
    return this;
  }

  invalid() {
    return this.result.filter((item) => {
      return item === true;
    }).length > 0;
  }
}

このようにすれば、jQueryだろうがReactだろうが使用できるようになるでしょう。
今回の場合はVueで書いてみます。

export default {
  name: 'ApplicationComponent',
  data() {
    return {
      name: '',
      errors: [],
    };
  },
  methods: {
    submit() {
      const validator = new StringValidator(this.name);
      const invalid = validator
        .max(10)
        .min(1)
        .invalid();
      if (invalid) {
        this.errors = validator.messages;
        return false;
      }

      // 処理

    }
  }
};

これならバリデーションの内容を外部に任せることができます。
もちろん、入力中のバリデーションやVueで行いたい基本的なバリデーションをmixinなどに書いてリアルタイムにエラーを出力することなどもできますので、そちらはVue側に記述して、ビジネスロジックに関するバリデーションは外部に持つというのが、いい気がします。

最後に

今回はフロントにロジックを記載するときについて書いてみました。

PHPでWebアプリを作成するときは少し前まではフロントを書くときjQueryを採用することが多かったです。

こうなるとどうしてもロジックをスクリプトにチョチョイと書いてしまう実装は多いのではないでしょうか?

フロント言語がしっかりとしてきた今、フロントのコードもしっかりと設計していきたいものです。

今は社内でスクラムの勉強会をしているので、その記事も書くかもしれません。

そのときはよしなに。

.

Non

所属 : 株式会社スマレジ 開発部

Twitter : @nonz250

Github : nonz250

Qiita : @nonz250

My Qiita posts My Qiita contributions My Qiita followers

主にPHPを使用し、サーバーサイドを担当。最近はフロントにも興味津々。

なにかを作ったりいじったりするのが好きで、個人開発なども行っている。

趣味はバイクアイコン画像は大抵愛車の「Z250」である。友達にアイコン描いてもらえて嬉しい。

PHP / Laravel / CakePHP2 / CakePHP3 / Vue / Nuxt / C# / etc...

Tags

#non's Labo #Laravel #Vue #個人開発 #ブログ #プログラミング #javascript #Html5 #WEBサービス #Twitter #今年の抱負メーカー #勉強方法 #PWA #モバイルアプリ #Android #ツーリング #バイクに乗るエンジニア #Z250 #秋吉台 #能登半島 #バイク #冒険 #東尋坊 #Squid #リバースプロキシ #hosts #axios #cropper #AdSense #Bootstrap #MySQL #高速化 #トドTask #Telescope #デバッグ #composer #テスト #セキュリティ #POSレジ #スマレジ #本部機能 #バリデーション #入力チェック #Mac #Chrome #テスト駆動開発 #開発手法 #UI #デザイン #WEBサイト #機能美 #PHP #Laravel 6 #コメント #バージョンアップ #vue-cli #localhost #BIツール #売上分析 #TANAX #MFK250 #ツアーシェルケース2 #RESTful #API #REST API #実務的 #PHP Tech Tutor #Smaregi Tech Talk #勉強会 # ブログ #CakePHP3 #CSRF #VSCode #開発環境 #CakePHP3.0 #さくらのレンタルサーバー #モジュールモード #シェル #メール #Gmail #relay #OGP #エラーページ #抱負 #家庭教師 #ドメイン駆動設計 #DDD #読書会 #那智の滝 #伊勢志摩 #伊勢志摩スカイライン #フロント #三方五湖 #レインボーライン #ボーイスカウト・ルール #プログラマが知るべき97のこと #リファクタリング #ユビキタス言語 #車輪の再発明 #マイクロサービス #デプロイ #QA #laravel-mix #Tips #storybook #@storybook/addon-actions #昇降デスク #コードレス #書斎 #オフィス #リモートワーク #働き方 #エラーハンドリング #スマレジ4