kakakakakku blog

Weekly Tech Blog: Keep on Learning!

Vuex でショッピングカートを実装できる無料コース「Vuex for Everyone」を受講した

Vue School の無料コース「Vuex for Everyone」を受講した.Vue.js 初心者でも受講できるレベルになっているし,今まで Vue.js を書いたことはあるけど,Vuex はまだ使ったことがないという人にもオススメできる.進め方にもよるけど,写経するとしても2,3時間あれば終わる.

Vuex for Everyone

今回受講した「Vuex for Everyone」の題材は「shopping-cart」で,ステップバイステップに実装を進めていく.動作確認をしながら,機能を追加したり,リファクタリングをしたりする.

vueschool.io

動画を見るとわかるけど,とにかく実装スピードが早いので,写経する場合は何度も戻して見直す必要がある.ただ困ったときは Vue School の GitHub にセッションごとにコミットされているので,それを活用すればオッケー.

github.com

セッション一覧

  • Introduction
    • Meet Vuex ⏲ 2:46
    • Create a new project with vue-cli ⏲ 3:45
    • Install and use Vuex ⏲ 1:57
  • Vuex Options
    • Vuex Mutations ⏲ 3:22
    • Vuex Getters ⏲ 1:57
    • Vuex Actions ⏲ 4:25
    • Store Access from all Components ⏲ 0:53
  • Shopping Cart Features
    • Add products to the cart ⏲ 5:08
    • Vuex Mutation History and Vue Devtools ⏲ 2:46
    • Cart items and total ⏲ 4:32
    • Checkout ⏲ 3:49
  • Advanced Vuex Options
    • Dynamic Vuex Getters ⏲ 2:31
    • Vuex Map Helpers ⏲ 8:04
    • Split Vuex Store in Multiple Files ⏲ 1:11
    • Vuex Modules ⏲ 7:23
    • Namespaced Vuex Modules ⏲ 6:27

f:id:kakku22:20180915094327p:plain

(受講画面例)

Meet Vuex

  • Vuex とは何か?
  • なぜ Vuex が必要なのか?

Create a new project with vue-cli

Vue School のボイラープレートから「shopping-cart」プロジェクトを作成する.

$ npm install -g vue-cli
$ npm install -g yarn

$ vue init vueschool/webpack-template shopping-cart

? Project name shopping-cart
? Project description A Vue.js project
? Author kakakakakku <y.yoshida22@gmail.com>
? Vue build runtime
? Install vue-router? No
? Use ESLint to lint your code? No
? Setup unit tests with Karma + Mocha? No
? Setup e2e tests with Nightwatch? No

   vue-cli · Generated "shopping-cart".

   To get started:

     cd shopping-cart
     npm install
     npm run dev

   Documentation can be found at https://vuejs-templates.github.io/webpack

$ cd shopping-cart
$ yarn
$ yarn dev

次に Vuex の GitHub にあるサンプルを参考に,ProductList コンポーネントを実装する.API 部分はモックになっている.

const _products = [
    {"id": 1, "title": "iPad 4 Mini", "price": 500.01, "inventory": 2},
    {"id": 2, "title": "H&M T-Shirt White", "price": 10.99, "inventory": 10},
    {"id": 3, "title": "Charli XCX - Sucker CD", "price": 19.99, "inventory": 5}
  ]

この時点で,3商品を表示することができる.

f:id:kakku22:20180915093954p:plain

(実装画面)

Install and use Vuex

ここで Vuex をインストールする.

$ yarn add vuex

そして,新しく store/index.js を作成する.ここで,さっそく Vuex で重要なコンセプトが出てくる.

  • state
  • getters
  • actions
  • mutations

Vuex Mutations

ここでは,実際に mutations を実装する.ハンドラ関数の第一引数として state を指定し,追加でペイロードとして products を指定している.

// shopping-cart/src/store/index.js
mutations: {
  setProducts (state, products) {
    // update products
    state.products = products
  }
}

Vuex Getters

getters の実装はシンプルで,ストアからフィルタして取得できる.実際にモックの1商品の在庫を0にして,動作確認をした.

// shopping-cart/src/store/index.js
getters: { // = computed properties
  availableProducts (state, getters) {
    return state.products.filter(product => product.inventory > 0)
  }
}

f:id:kakku22:20180915094003p:plain

(実装画面)

Vuex Actions

この時点だと,まだコンポーネントから直接 Ajax で API を呼び出しているので,ベストプラクティスではなく,actions を使って解決するとのことだった.最初は,そのまま mutations をコミットすれば良いのではないかと思っていたけど,mutations は同期,actions は非同期なので,ここでは actions を使って,mutations をコミットする必要性を学べた.そして,API を呼び出しているときのローディング画像もここで実装した.

// shopping-cart/src/store/index.js
actions: { // = methods
  fetchProducts ({commit}) {
    return new Promise((resolve, reject) => {
      // make the call
      // call setProducts mutation
      shop.getProducts(products => {
        commit('setProducts', products)
        resolve()
      })
    })
  }
},

actions を呼び出すときは .dispatch を使う.そして actions の中で Promise を実装しているので,ここでは .then で受けて,ローディング画像を消している.

// shopping-cart/src/components/ProductList.vue
created () {
  this.loading = true
  store.dispatch('fetchProducts')
    .then(() => this.loading = false)
}

f:id:kakku22:20180915094012p:plain

(実装画面)

Store Access from all Components

全てのコンポーネントで store を import しなくても良いように,ルートコンポーネントに注入し,各コンポーネントでは this.$store で参照できるようにした.

// shopping-cart/src/main.js
new Vue({
  el: '#app',
  store,
  render: h => h(App)
})

Add products to the cart

次に商品をカートに入れられるようにストアにカートを実装した.ここまでの理解もあったので actions と mutations の実装も問題なかった.

f:id:kakku22:20180915094021p:plain

(実装画面)

Vuex Mutation History and Vue Devtools

Chrome 拡張を使って Vuex の状態を確認した.状態を Time Travel して戻すことができるのは,デバッグするときに便利そうだった.

f:id:kakku22:20180915094029p:plain

(実装画面)

Cart items and total

Vuex の GitHub から Filters 用の currency.js をコピーして,カートの実装を追加した.これで,カートの中に何が何個入っていて,総額も確認できるようになった.

f:id:kakku22:20180915094037p:plain

(実装画面)

Checkout

次は,購入できるようにチェックアウトボタンを実装した.実際にチェックアウトはできないので,ボイラープレートに入っている実装で,ランダムで成功したり,失敗したりするようになっている.

buyProducts (products, cb, errorCb) {
  setTimeout(() => {
    // simulate random checkout failure.
    (Math.random() > 0.5 || navigator.userAgent.indexOf('PhantomJS') > -1)
      ? cb()
      : errorCb()
  }, 100)
}

actions から,成功時の mutations と 失敗時の mutations を送っている.

// shopping-cart/src/store/index.js
checkout ({state, commit}) {
  shop.buyProducts(
    state.cart,
    () => {
      commit('emptyCart')
      commit('setCheckoutStatus', 'success')
    },
    () => {
      commit('setCheckoutStatus', 'fail')
    }
  )
}

Dynamic Vuex Getters

在庫がないときに商品名が消えてしまうのは微妙なので,Add to cart ボタンを disable にする実装をした.

f:id:kakku22:20180915094046p:plain

(実装画面)

Vuex Map Helpers

ここからは,Vuex のお作法でリファクタリングをしていく.まずは Map Helpers で state / getters / actions の宣言をシンプルにするために mapState / mapGetters / mapActions を宣言し,スプレッド演算子とともに,その中に呼び出し名を宣言できる.

// shopping-cart/src/components/ProductList.vue
computed: {
  ...mapState({
    products: state => state.products
  }),
  ...mapGetters({
    productIsInStock: 'productIsInStock'
  })
}

Split Vuex Store in Multiple Files

次は store/index.js の肥大化を防ぐために,actions だけを store/actions.js に切り出した.ただし,ここでは切り出せることを学ぶだけで,実際には次に出てくる Vuex Modules で書き直すことになる.

Vuex Modules

モジュールも Vuex のコンポーネントで,ストアごとに切り出していくようなイメージになる.今回は store/modules/cart.jsstore/modules/products.js に切り出した.モジュールごとに state / getters / mutations / actions を持っているので,わかりやすいし,テストコードも書きやすそう.結果的に store/index.js に実装はなくなり,とにかく薄くなった.

// store/index.js
import Vuex from 'vuex'
import Vue from 'vue'
import actions from './actions'
import cart from './modules/cart'
import products from './modules/products'

Vue.use(Vuex)

export default new Vuex.Store({
  modules: {
    cart,
    products
  },

  state: { // = data
  },

  getters: { // = computed properties
  },

  actions,

  mutations: {
  }
})

Namespaced Vuex Modules

最後は namespaced で,モジュールで namespaced: true を指定することにより,コンポーネント側で mapActions に名前空間を指定できるようになる.メソッド名にストア名を含めて冗長になっている場合など,シンプルに書けるようになる.

まとめ

  • Vue School の無料コース「Vuex for Everyone」を受講した
  • ショッピングカートを実装しながら,Vuex の基礎を学べた
  • 動画だと理解できなかった部分などは公式ドキュメント(日本語)を参考にした

vuex.vuejs.org

写経した GitHub リポジトリ

github.com

他にもある Vue School の無料コース

過去に受講した Firebase Realtime Database の無料コースも,Firebase Authentication の無料コースも良かった.

kakakakakku.hatenablog.com

kakakakakku.hatenablog.com

コピペのためのコマンドラインツール clipboard を試した

Mac / Windows / Linux など,クロスプラットフォームで,コピペができるツールを探していて,Go で書かれた clipboard を試した.clipboard をインストールすると gocopy コマンドと gopaste コマンドが使えるようになる.

github.com

Mac / Linux

サンプルファイルを用意して,簡単に動いた.

$ cat sample.txt | gocopy
$ gopaste
1
12
123
1234
12345

ただし,Linux の場合は以下のエラーが出るため,事前にパッケージをインストールしておく必要がある.README にも Requirements として書いてあった.

panic: No clipboard utilities available. Please install xsel or xclip.

ディストリビューションによって違うと思うけど,今回は Amazon Linux で試した.

$ sudo yum install xsel --enablerepo epel
$ sudo yum install xclip --enablerepo epel

Windows

あまり Windows に慣れていないけど,手元にある Windows 10 環境でも動かすことができた.

$ type .\sample.txt | .\gocopy.exe
$ .\gopaste.exe
1
12
123
1234
12345

コピペ対象

README にも書いてある通り,コピペ対象はテキストのみだった.png / gif など,画像もコピペできると良いんだけど,画像にも対応したライブラリはあるのだろうか?

まとめ

  • クロスプラットフォームで,コピペができる clipboard を試した
  • 実装を読むと,例えば Mac だと pbcopypbpaste を実行していた

ドットインストールで「textlint 入門」を受講した

textlint はドキュメント用の Lint ツールで,日本語にも対応しているので,簡単に文法や typo などを検出できる.

textlint.github.io

ドットインストールのレッスン一覧を眺めていたら textlint のレッスンがあり,気になったので,受講してみた.

Lesson 1

Node.js をインストールした(というか既に入っていた).今回試した Mac の環境は以下の通り.

$ node -v
v10.8.0
$ npm -v
6.2.0

Lesson 2

npm で新規プロジェクトを作成し,textlint を実行できるようにした.今回は v11.0.0 になった.

$ npm init -y
$ npm install --save-dev textlint
$ ./node_modules/.bin/textlint -v
v11.0.0

Lesson 3

の個数をチェックできる textlint-rule-max-ten をインストールした.

$ npm install --save-dev textlint-rule-max-ten

次に設定ファイルとなる .textlintrc を作成し,textlint-rule-max-ten を有効にしている.

{
  "rules": {
    "max-ten": true
  }
}

github.com

Lesson 4

実際に textlint を実行し,エラーが出ることを確認した.

$ ./node_modules/.bin/textlint docs/sample.md

/Users/kakakakakku/github/sandbox-dotinstall-textlint/docs/sample.md
  1:11  error  一つの文で""3つ以上使用しています  max-ten

✖ 1 problem (1 error, 0 warnings)

Lesson 5

次に .textlintrc を変更し,デフォルトの閾値「3個」を「2個」に変更した.

{
  "rules": {
    "max-ten": {
      "max": 2
    }
  }
}

実際にエラーの閾値を変更できた.

$ ./node_modules/.bin/textlint docs/sample.md

/Users/kakakakakku/github/sandbox-dotinstall-textlint/docs/sample.md
  1:8  error  一つの文で""2つ以上使用しています  max-ten

✖ 1 problem (1 error, 0 warnings)

Lesson 6

実際に日本語の文章をチェックするときは複数のルールを組み合わせたプリセットを使うと良い.今回は textlint-rule-preset-japanese をインストールし,「助詞の個数」や「ら抜き言葉」などをチェックできるようにした.

$ npm i -D textlint-rule-preset-japanese

$ ./node_modules/.bin/textlint docs/sample.md

/Users/kakakakakku/github/sandbox-dotinstall-textlint/docs/sample.md
  1:11  error  一文に二回以上利用されている助詞 "" がみつかりました。  preset-japanese/no-doubled-joshi
  1:20  error  ら抜き言葉を使用しています。                              preset-japanese/no-dropping-the-ra

✖ 2 problems (2 errors, 0 warnings)

また,以下のようにプリセットの中で一部のルールを無効化することもできる.

{
  "rules": {
    "preset-japanese": {
      "no-dropping-the-ra": false
    }
  }
}

github.com

Lesson 7

次に文章中の表記揺れをチェックする textlint-rule-prh をインストールした.

$ npm i -D textlint-rule-prh

.textlintrc は以下のように書く.

{
  "rules": {
    "preset-japanese": {
      "no-dropping-the-ra": false
    },
    "prh": {
      "rulePaths": [
        "rules/dotinstall.yml"
      ]
    }
  }
}

Lesson 8

rules/dotinstall.yml を以下のように書くと javascript という小文字の表記揺れをチェックすることができる.

version: 1

rules:
  - pattern: javascript
    expected: JavaScript

実際に表記揺れのエラーが出た.

$ ./node_modules/.bin/textlint docs/sample.md

/Users/kakakakakku/github/sandbox-dotinstall-textlint/docs/sample.md
  1:1  ✓ error  javascript => JavaScript  prh

✖ 1 problem (1 error, 0 warnings)1 fixable problem.
Try to run: $ textlint --fix [file]

github.com

Lesson 9

さらに rules/dotinstall.yml を拡張し,複数の表記揺れを定義した.

version: 1

rules:
  - pattern:
      - javascript
      - java script
    expected: JavaScript

正規表現で書くこともできるので,表記揺れのパターンが多いときは助かる.

version: 1

rules:
  - pattern: /java\s*script/i
    expected: JavaScript

また --fix オプションを使うと自動的に文章を修正することもできる.

Lesson 10

次は複数ファイルに対して textlint を実行するコマンドを試した.

$ ./node_modules/.bin/textlint docs/*.md

/Users/kakakakakku/github/sandbox-dotinstall-textlint/docs/sample.md
  1:13  ✓ error  Javascript => JavaScript  prh
  1:27  ✓ error  JAVAScript => JavaScript  prh

✖ 2 problems (2 errors, 0 warnings)2 fixable problems.
Try to run: $ textlint --fix [file]

Lesson 11

Atom + textlint を試すレッスンだったけど,僕は Atom を使っていないので,スキップした.実はブログ記事を書くときに VS Code で textlint を使っているので,vscode-textlint で textlint を動かしたキャプチャを貼っておこうと思う.

f:id:kakku22:20180828180506p:plain

marketplace.visualstudio.com

まとめ

  • ドットインストールに textlint のレッスンが追加されていて素晴らしい
  • textlint-rule-preset-japanesetextlint-rule-prh など,よく使うルールが紹介されていて良かった

試した内容は Lesson ごとに commit している.

github.com

CircleCI の Auto-cancel redundant builds が Workflows にも対応した

CircleCI には便利な Auto-cancel redundant builds があり,有効にしておくと,同じブランチに対して複数回ビルドがトリガーされた場合に,自動的に過去のビルドがキャンセルされる.繰り返し git push をして,さらに CI 時間が長いような場合には,無駄な待ち時間を減らせたり,ジョブの詰まりを減らせたりする.この機能は CircleCI 1.0 時代からあったけど,もしかしたらあまり知られていないかも?

Auto-cancel redundant builds with Workflows

最近のリリースで Auto-cancel redundant builds を Workflows でも使えるようになった(とのこと).一部注意点はあるものの,公式ドキュメントにも手順が載っていた.

  • Auto Cancelling a Redundant Build
    • Steps to Enable Auto-Cancel for New Builds Triggered by Pushes to GitHub without Worklfows
    • Steps to Enable Auto-Cancel for Workflows Triggered by Pushes to GitHub or the API

circleci.com

試してみた

まず Auto-cancel redundant builds を無効にした状態で,単純に sleep するだけの CI ジョブを作成し,複数回ビルドをトリガーしてみた.すると,以下のように RUNNING が多く並んだ.こうなってしまうと,ジョブが詰まってしまうので,開発効率も下がってしまう.

f:id:kakku22:20180822214033p:plain

次にプロジェクト設定を変更する.Auto-cancel redundant buildsEnable build processing (preview) を有効にした.

  • Advanced Settings
    • Auto-cancel redundant builds
      • OffOn
    • Enable build processing (preview)
      • OffOn

f:id:kakku22:20180822214042p:plain

この状態で,複数回ビルドをトリガーしてみた.すると,詰まっているビルドが自動的に CANCELED になった.便利!

f:id:kakku22:20180822214051p:plain

注意点 : デフォルトブランチは対象外になる

公式ドキュメントに書いてある通り,デフォルトブランチは対象外になる.これは適切な挙動だと思っていて,特に master などは,リリースプロセスに使うため,必ずビルドをしてあげる必要がある.

Projects for which auto-cancel is enabled in the Advanced Settings will have workflows on non-default branches cancelled when a newer build is triggered on that same branch.

注意点 : キャンセルされて良いかを考える

公式ドキュメントに書いてある通り,Auto-cancel redundant builds を有効にする前にビルドのユースケースを考える必要がある.例えば lint 系だけではなく,デプロイもビルドで行っている場合など,自動キャンセルによって不整合などが起きないようになっている必要がありそう.

Notes: It is important to carefully consider the impact of enabling the auto-cancel feature, for example, if you have configured automated deployment jobs on non-default branches. Auto-cancelling workflows requires enabling the preview build processing feature.

まとめ

  • CircleCI の Auto-cancel redundant builds は便利
  • 最近のリリースで Workflows でも使えるようになった(とのこと)
  • 実際に試してみた

小さすぎて失敗すらできないステップを毎日繰り返そう /「小さな習慣」を読んだ

「アウトプットを習慣化する」というスローガンを掲げて,これまで5年間以上,継続をしてきた.自分のノウハウを共有するために,イベントで「アウトプット」をテーマに登壇したこともある.

kakakakakku.hatenablog.com

kakakakakku.hatenablog.com

また,去年末から取り組んでいる「ブログメンター(アウトプットメンター)」という活動も,根源的なモチベーションは「習慣化に困っている人をサポートしたい」と言える.一部の人は「習慣化」を「気合で乗り切る」といった感覚で理解しているが,実際は「うまく目標設定をすること」が重要で,その「うまく」という表現は「小さく,定量的に,達成可能なレベルに」とも言い換えられる.目標設定の文脈でよく出てくる「SMART Goals (Specific / Measurable / Achievable / Relevant / Time bound)」に似ている.

小さな習慣

そんな「習慣化」をテーマにした書籍「小さな習慣」を読んだ.もともとは洋書で「Mini Habits: Smaller Habits, Bigger Results」というタイトルで2013年に発売されている.内容は比較的シンプルながら,習慣化を実現するためのノウハウが詰まっている.また,個人的に刺さるキーフレーズも出ていたので,紹介したいと思う.習慣化をしようとしても三日坊主になってしまう人などにオススメできる.

小さな習慣

小さな習慣

小さな習慣とは?

まずタイトルにある「小さな習慣」って「どこまで小さいの?」という疑問が出ると思う.本書には,最初に以下のような具体例があり,驚くほどに小さかった.確かに続けられそう.

  • 毎日,本書を「2ページ」読む
  • 毎日,腕立て伏せを「1回」やる
  • 毎日,記事を「50文字」書く

本書で繰り返し出てくるキーフレーズの中で,個人的に刺さったものを紹介する.本当に「小さい」からこそ,失敗しないというロジックはその通りで,確かに腕立て伏せ「1回」なら10秒あればできる.

  • 小さすぎて失敗すらできない
  • 失敗する方が難しい
  • (ジムに行くのではなく)トレーニングウェアをクローゼットから出す

Mini Habit Ideas

Hini Habits 公式サイトに,具体的な「小さな習慣」のサンプルが公開されている.

  • Mental Fitness, Knowledge, & Intelligence
  • Physical Fitness
  • Health, Diet, & Well-Being
  • Happiness
  • Business
  • Productivity

例えば「Drink 1 glass of water(水をコップ1杯飲む)」「Laugh once(1度笑う)」など,小ささの粒度として参考になる.「Write 50 words (for blog)(ブログ用に50文字書く)」などもあり,最初から「1記事」書こうとするから大きく感じるのであって,まずは「50文字」から書き始めるというのは,素晴らしい取り組みだと思う.

1歩を踏み出すこと

本書を読んでいて「1歩を踏み出すこと」の難しさが,習慣化できない理由に繋がっていると感じた.言い換えると「腰が重い」とも言える.本書にも「最初のアクションが1番難しい」という話があり「ニュートンの運動の法則」に例えられていた.ダラダラと1日を過ごしてしまうと,区切りがなくなってしまうので,うまく区切りを作って,1歩を踏み出せば,あとは「なるようになる」ことは改めて意識したいと思う.前にツイートした内容も本書の内容と似ている.

ツール

本書では,目標を管理するツールとして,大きなカレンダーを部屋に貼る方法だけではなく,スマホアプリ,デスクトップアプリなども紹介されていた.詳しくは Hini Habits 公式サイトに載っている.

現在,僕は「ループ習慣トラッカー (Loop - Habit Tracker)」「習慣の目標 (Habit Tracker)」の2アプリをインストールして,試用している.1ヶ月ほど使ってみて,好きなアプリに決めたいと思う.

play.google.com

play.google.com

個人スプリントと組み合わせる

「アウトプット駆動学習を習慣化する」という登壇資料にも書いている通り,僕はタイムボックスを1週間に設定した「個人スプリント」を数年間ずっと回している.タスク管理に使っているツールは Trello で,毎週タスクを Done にするために頑張っている.ただし,これはあくまでタイムボックスが1週間なので,1週間で終わらせる(帳尻を合わせる)ようなルールになっている.そこで,今回から「毎日の小さな習慣」も組み合わせることにした.組み合わせる負荷は気にする必要はなく,理由は「小さすぎて失敗すらできない」からと言える.中長期的に運用してみて,どこかで結果をまとめたいと思う.

f:id:kakku22:20180819133149j:plain

まとめ

  • 「小さな習慣」は習慣化に悩んでいる人にオススメできる
  • 「小ささ」の粒度は本当に小さく,失敗すらできない
  • Hini Habits 公式サイトを参考に,自分の「小さな習慣」を決めて,まずは1歩を踏み出そう!

小さな習慣

小さな習慣