「ゼロから作るDeep Learning」を読みました

諸事情により機械学習エンジニアを志したのでやっていきます

TOC

まえがき

この本の対象者について

自然言語処理をやりたいんだけど、それは2巻の自然言語処理編でやります。

ゼロから作るDeep Learning ? ―自然言語処理編

ゼロから作るDeep Learning ? ―自然言語処理編

第1章 Python入門

このへんはいつの間にかインストールされていたpyenvでAnacondaをインストールしてやっていきます

$ pyenv install anaconda3-5.1.0
$ pyenv global anaconda3-5.1.0
import numpy as np
import matplotlib.pyplot as plt

x = np.arange(0, 6, 0.1)
y = np.sin(x)

plt.plot(x, y)
plt.show()

f:id:Cormorant:20190330160959p:plain

第2章 パーセプトロン

  • パーセプトロンとは、複数の信号を入力として受け取り、ひとつの信号を出力するアルゴリズム
  • 信号は0または1を出力し、それぞれに固有の重みが乗算されて入力される
  • 入力の総和が閾値を超えた場合、1を出力する

数式は略。

単純な論理回路

パーセプトロンでAND,OR,NANDで実装すると、構造は同じままパラメータの値の調整だけでそれぞれ実現できる。すごい。(ただし、パラメータの調整は人力)

パーセプトロンの限界

パーセプトロンではXORは実装できない。えー。

ちゃんと書くと、パーセプトロンでは直線による領域(線形な領域)を分けることはできるが、曲線による領域(非線形な領域)を分けることはできない。

多層パーセプトロン

しかしパーセプトロンの層を重ねればXORを実現できる。

def XOR(x1, x2):
    s1 = NAND(x1, x2)
    s2 = OR(x1, x2)
    y = AND(s1, s2)
    return y

ANDやORが単層のパーセプトロンだったことに対し、XORは2層のパーセプトロン(多層パーセプトロン)になっている。 XOR関数内のx1, x2を第0層、s1, s2を第1層、yを第2層とすると、0->1層と1->2層の2層のパーセプトロン

このように層を重ねることでパーセプトロンはより柔軟な表現が可能になり、足し算や2進数を10進数に変換するエンコーダも作ることができる。さらにはNANDだけで理論上コンピューターを表現することも可能であることから、パーセプトロンでコンピュータが行う処理も表現できる。

第3章 ニューラルネットワーク

パーセプトロンは理論上コンピュータが行う処理も表現できるが、そのパラメータの調整は人力だった。それを解決するのがニューラルネットワーク

活性化関数

この活性化関数を別の関数にしたらどうなるか。これをやってるのがニューラルネットワーク

シグモイド関数

ステップ関数はこうだった。

f:id:Cormorant:20190330174738p:plain

シグモイド関数はこう。

f:id:Cormorant:20190330174925p:plain

ReLU関数

最近は ReLU (Rectified Linear Unit) 関数を使う。詳しくは多分後述。

f:id:Cormorant:20190330180604p:plain

3層ニューラルネットワークの実装

import numpy as np

def sigmoid(x):
    return 1 / (1 + np.exp(-x))

def identity_function(x):
    return x

def init_network():
    network = {}
    network['W1'] = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
    network['b1'] = np.array([0.1, 0.2, 0.3])
    network['W2'] = np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]])
    network['b2'] = np.array([0.1, 0.2])
    network['W3'] = np.array([[0.1, 0.3], [0.2, 0.4]])
    network['b3'] = np.array([0.1, 0.2])
    return network

def forward(network, x):
    W1, W2, W3 = network['W1'], network['W2'], network['W3']
    b1, b2, b3 = network['b1'], network['b2'], network['b3']
    a1 = np.dot(x, W1) + b1
    z1 = sigmoid(a1)
    a2 = np.dot(z1, W2) + b2
    z2 = sigmoid(a2)
    a3 = np.dot(z2, W3) + b3
    y = identity_function(a3)
    return y

network = init_network()
x = np.array([1.0, 5.0])
y = forward(network, x)
print(y) # [0.33098211 0.72778046]

出力層の設計

  • 上記で出てくる identity_function のように、入力をそのまま返す関数を恒等関数
  • 入力信号akの指数関数 / すべての信号の指数関数の和 を返す関数をソフトマックス関数
  • 回帰問題では恒等関数を、分類問題ではソフトマックス関数を使う
  • 回帰問題はあるデータから数値の予測をする問題、分類問題はあるデータのクラス分けをする問題

ソフトマックス関数の特徴

ソフトマックス関数は出力の総和が1になるので確率として扱える。 ソフトマックス関数の出力の大小は入力前と変わらないので、推論フェーズでは省略されることが多い

出力層のニューロンの数

出力層のニューロンの数は、解くべき問題に応じて、適宜決める必要がある。例えば、0から9の数字を画像認識する10クラス分類問題では、出力層のニューロンは10個に設定する。

手書き文字認識

第4章 ニューラルネットワークの学習

ニューラルネットワークの特徴は、データから学習できる→重みのパラメータをデータから自動で決定できること。

データから学習する

機械学習を使った画像認識では、画像から特徴量を抽出してそのパターンを機械学習の技術で学習する。(画像認識の特徴量として、SIFT,SURG,HUGなど)特徴量を使って画像をベクトルに変換し、機械学習で使われる識別器(SVMやKNNなど)で学習させる。機械が規則性を見つけ出すので人がゼロからアルゴリズムを見つけ出すより効率的。

対してニューラルネットワークでは画像に含まれる特徴量も機械が学習する。

損失関数

基準となる指標をもとに、最適な重みパラメータの探索を行う。この指標は損失関数と呼ばれ、一般には2乗和誤差や交差エントロピー誤差が用いられる。

2乗和誤差

def mean_squared_error(y, t):
    return 0.5 * np.sum((y-t)**2)

# 2 を正解とする one-hot表現
t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]

# 例1: 2の確率が最も高い場合(0.6)
y = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0 0.1, 0.0, 0.0]
mean_squared_error(np.array(y), np.array(t)) # 0.0975 (教師データとの誤差が小さい)

# 例2: 7の確率が最も高い場合(0.6)
y = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0 0.6, 0.0, 0.0]
mean_squared_error(np.array(y), np.array(t)) # 0.5975 (教師データとの誤差が大きい)

上記だと、例1のほうが教師データにより適合していることを示している。

交差エントロピー誤差

def cross_entropy_error(y, t):
    delta = 1e-7
    return -np.sum(t * np.log(y + delta)) # 微小数deltaを足すことでlogeが無限になるのを防ぐ

# 2 を正解とする one-hot表現
t = [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]

# 例1: 2の確率が最も高い場合(0.6)
y = [0.1, 0.05, 0.6, 0.0, 0.05, 0.1, 0.0 0.1, 0.0, 0.0]
cross_entropy_error(np.array(y), np.array(t)) # 0.5108 (教師データとの誤差が小さい)

# 例2: 7の確率が最も高い場合(0.6)
y = [0.1, 0.05, 0.1, 0.0, 0.05, 0.1, 0.0 0.6, 0.0, 0.0]
cross_entropy_error(np.array(y), np.array(t)) # 2.3025 (教師データとの誤差が大きい)

tがone-hot表現のとき、正解ラベルが1の出力のみ計算すればいい。(その他の出力は0乗算)

ミニバッチ学習

例えば6000枚の訓練データから、ランダムに100枚選んで、その値で学習を行う学習手法。

なぜ損失関数を設定するのか?

精度を指標にすると、例えば正解率32/100になるようなパラメータのとり方は幅があり、パラメータの変化があっても傾きが生まれないため、そこで学習がストップしてしまう。連続的に変化する損失関数を指標にすれば、少しのパラメータの変化に反応して関数の出力も変化する、つまり殆どの場所で傾きが0にならないため、正しい学習が行われる。

数値微分

数学の話なので略。

勾配

数学の話なので略。

勾配法

勾配を使って損失関数が最も小さくなる場所を探そう、というのが勾配法。ただし、勾配は各地点で値が小さくなる方向でしかないので、そこが関数の最小値である保証はない。勾配の方向にどの程度更新するのか、という学習率の設定が重要になる。一般に、学習率は高くても低くても「良い場所」にはたどり着かない。ニューラルネットワークの学習に置いては、学習率を変更しながら正しく学習できているか確認作業を行うのが一般的。学習率のように自動で獲得されず、人の手によって設定されるパラメータをハイパーパラメータという。

ニューラルネットワークの学習

  • ステップ1: ミニバッチ
  • ステップ2: 勾配の算出
  • ステップ3: パラメータの変更
  • ステップ4: 繰り返す

この4つの手順で行う。これはミニバッチを使用していることから、確率的勾配降下法(stochastic gradient descent)と呼ばれている。ディープラーニングフレームワークではSDGという関数名で実装されていることが多い。

2層ニューラルネットワークのクラス、ミニバッチ学習の実装

テストデータで評価

過学習をしていないか、訓練データ以外のテストデータで確認する。ここでは、1エポック(10000個のデータに対し100個のミニバッチで100回学習した場合、100回で1エポック)ごとにテストする。

テスト自体は略。

まとめ

数値微分による計算には時間がかかるが、その実装は簡単である。一方、次章で実装するやや複雑な誤差逆伝播法は、高速に勾配を求めることができる。

第5章 誤差逆伝播

計算グラフで誤差逆伝搬法を理解する。

計算グラフ

計算グラフ自体については略。

計算グラフを使って問題を解くには、

  1. 計算グラフを構築する
  2. 計算グラフ上で計算を左から右へ進める

という流れで行う。2番目のステップは、順方向の伝播、順伝播(forward propagation)という。逆方向は逆伝播(backward propagation)といい、このさき微分を計算するにあたって重要な働きをする。

局所的な計算

計算グラフでは、各ノードで行うべきことは自分に関係する計算だけであり、全体のことについては何も考えなくてよい。全体がどんなに複雑な計算でも、各ステップでやることは、対象とするノードの局所的な計算になる。局所的な計算は単純だが、その結果を伝搬することで、全体を構成する複雑な計算の結果が得られる。

なぜ計算グラフで解くのか?

  1. 局所的な計算
  2. 途中の計算の結果をすべて保持することができる
  3. 逆方向の伝播によって「微分」を効率良く計算できる(最大の理由)

連鎖律・逆伝播

数学の話なので略。

単純なレイヤの実装

実装を見て計算グラフを感じてほしい。

乗算レイヤ

class MulLayer:
  def __init__(self):
    self.x = None
    self.y = None

  def forward(self, x, y):
    self.x = x
    self.y = y
    out = x * y
    return out
  
  def backward(self, dout):
    dx = dout * self.y # x と y をひっくり返す
    dy = dout * self.x
    return dx, dy

加算レイヤ

class AddLayer:
  def __init__(self):
    pass

  def forward(self, x, y):
    out = x + y
    return out

  def backward(self, dout):
    dx = dout * 1
    dy = dout * 1
    return dx, dy

逆数レイヤ(予想して書いたので間違ってるかも)

class RevLayer:
  def __init__(self):
    self.out = None

  def forward(self, x):
    out = 1 / x
    self.out = out
    return out

  def backward(self, dout):
    dx = dout * (0 - self.out ** 2)
    return dx

活性化関数レイヤの実装

ReLUレイヤ

class Relu:
  def __init__(self):
    self.mask = None
  
  def forward(self, x, y):
    self.mask = (x <= 0)
    out = x.copy()
    out[self.mask] = 0
    return out

  def backward(self, dout):
    dout[self.mask] = 0
    dx = dout
    return dx

Sigmoidレイヤ

class Sigmoid:
  def __init__(self):
    self.out = None
  
  def forward(self, x):
    out = 1 / (1 + np.exp(-x))
    self.out = out
    return out

  def backward(self, dout):
    dx = dout * (1.0 - self.out) * self.out
    return dx

Affineレイヤ

ニューラルネットワークの順伝播で行う行列の積は、幾何学の分野では「アフィン変換」と呼ばれる。そのため、ここでは、アフィン変換を行う処理をAffineレイヤという名前で実装していく。

バッチ版Affineレイヤ

class Affine:
  def __init__(self, W, b):
    self.W = W
    self.b = b
    self.x = None
    self.dW = None
    self.db = None

  def forward(self, x):
    self.x = x
    out = np.dot(x, self.W) + self.b
    return out

  def backward(self, dout):
    dx = np.dot(dout, self.W.T)
    self.dW = np.dot(self.x.T, dout)
    self.db = np.sum(dout, axis=0)
    return dx

Softmax-with-Lossレイヤ

ソフトマックス関数に損失関数である交差エントロピー誤差(cross entropy error)を含めて、Softmax-with-Lossという名前のレイヤを作成する。

Softmax-with-Loss

class SoftmaxWithLoss:
  def __init__(self):
    self.loss = None  # 損失
    self.y = None     # softmaxの出力
    self.t = None     # 教師データ(one-hot vector)

  def forward(self, x, t):
    self.t = t
    self.y = softmax(x)
    self.loss = cross_entropy_error(self.y, self.t)
    return self.loss

  def backward(self, dout=1):
    batch_size = self.t.shape[0]
    dx = (self.y - self.t) / batch_size
    return dx

ソフトマックス関数の損失関数として交差エントロピー誤差を用いると、逆伝播が y - t というきれいな形になる。これはそうなるように交差エントロピー誤差という関数が設計されているから。また、回帰問題では高等関数を用いるが、そちらは2乗和誤差を用いると逆伝播が y - t になる。

誤差逆伝播法の実装

OrderdDict を用いてレイヤの追加順を記録し、追加した順に forward (または逆順に backward)するだけ。

誤差逆伝播法の勾配確認

実装が難しいので、数値微分の結果と比較して勾配確認(gradient check)する。

第6章 学習に関するテクニック

第7章 畳み込みニューラルネットワーク

第8章 ディープラーニング

面白いので買って読んで。

感想

機械学習の本は何冊か読んだんだけど、実際どうやって作っていけばいいのかさっぱりわからない状態だったのでかなり助けになりました。

数学が弱々なので、数式で説明されるよりもコードで実装してくれる方が理解しやすかったようです。

私がやりたいのは8章で紹介されていた画像キャプション生成やDeep Q-Network(強化学習)が近いと思うので、この辺を実際に作ってみたいですね。自然言語処理について取り上げている2巻にも期待。

2018年10月末~12月の振り返り

普段WikiHubで日報を書いているのですが(c18t's articles - 日報)、去年の10月末から更新が滞っていたので、その期間の振り返りをやっていきたいと思います。

2018年10月

  • 基本的に何もしてなかったようだ
  • Twitterのいいね廃止するかもしれんという話題でこんなこと言ってた
  • VRChat用のボディを作ろうとしてリアル写真をもとに3Dモデリングをしていたんだけど挫折

2018年11月

  • 貯金が底をつく
  • 通帳残高ゼロを名乗り始める
  • おじいちゃんの7回忌
  • マルチプラットフォームアプリケーション開発をやりはじめる
  • スプラトゥーン2で全然勝てなくてつらい
  • よくわからない
  • 末頃から転職活動をしはじめる
    • スカウトメールが山程来て何もわからなくなってくる

2018年12月

  • 無な日々
  • なんもわからんを名乗り始める
  • 転職活動はぼんやりと継続中
  • スプラトゥーン2で全然勝てなくてつらい
  • 金沢に帰省

所感

ぼんやりしていたら年の瀬って感じで、あんまり記憶がはっきりしていない…

あとスプラトゥーン2で全然勝てなくてつらい

「Kotlin Development for Android (Create Your Own App)」を読みました

KotlinでAndroidアプリを作る練習をします。

TOC

  • Chapter1 Intro to Kotlin
  • Chapter2 Android Studio 3.0 Set-Up
  • Chapter3 Hello World! (Your First App)
  • Chapter4 Higher or Lower (Your Second App)
  • Chapter5 BMI Calculator (Your Third App)
  • Chapter6 Extras
  • Chapter7 Conclusion

英語が貧弱なのでだいぶ意訳でまとめていきます。要旨なのでエッセンスが入ってればいいんだよの精神です。

Chapter1 Intro to Kotlin

Kotlinについて、Javaと100%互換性がありコード記述行数が40%削減できる学習コストの低いすごい言語だよ、KotlinをはじめるためにこれからAndroid Studioをダウンロードしてセットアップしよう、そうすればアプリの開発が始められるよ、とのことでチャプター2へ

Chapter2 Android Studio 3.0 Set-Up

Android StudioのインストールとAndroidバイスのUSBデバッグ方法について。割愛。

Chapter3 Hello World! (Your First App)

Android Studioで新規プロジェクトを作成する方法と、デザイナーでボタンとテキストを配置する方法、ボタンにクリックイベントを設定する方法について。

Chapter4 Higher or Lower (Your Second App)

ユーザーの入力に応じて結果を変える処理、トースト、追加のアクティビティ(画面)を使用する方法について。

lblFeedback.getText()

とあるけど、Kotlinではgetter/setterでアクセスできる。

lblFeedback.text

それから、トーストの表示にtoast()だけ記述しているけど、実際にはこう書かないと動かなかった。

Toast.makeText(applicationContext, "Please enter a number", Toast.LENGTH_LONG).show()

Chapter5 BMI Calculator (Your Third App)

  • BMI = (weight(kg) / height(m)) / height(m)

アクティビティにデータを渡す方法について。

Chapter6 Extras

Kotlinからは微妙に離れるけど、その他のアプリケーション開発のスキルについて。

別方向(横向き)のスクリーンデザインと、アプリアイコンの設定方法。

Chapter7 Conclusion

ここまでにできるようになったことの振り返り

  • Build an app from scratch
  • Create diffrent activities for your apps
  • Link those activities together
  • Send data between activities
  • Understand and utilise constraints with different elements
  • Use images in your apps
  • Write your own Kotlin functions
  • Develop apps for different screen orientations
  • Create and change app icons

感想

ざっくりAndroidアプリを作れるようになりました。 しかし、要素の配置がいまいち思い通りに出来ない(相対位置を指定しないとぐちゃぐちゃになるのなんでかわかってない)ので、もうちょっとちゃんと勉強しないといけなさそうです。XAMLのときは実地でなんとかしたので手を動かすしかないか。

英語を読む気力がなかなか湧かなくて、短いテキストにもかかわらず読み終わるのに時間がかかってしまいました。英語もスラスラ読めるようになりたいなぁ。

「速習Kotlin〜Javaより簡単!新Android開発言語を今すぐマスター」を読みました

マルチプラットフォームアプリケーション開発の勉強中で、各プラットフォームの開発の学習をしているので、Androidアプリ開発で使う言語としてKotlin触ってみようと思います。

TOC

Part1 イントロダクション

Kotlinとは何ぞや?ということで、Kotlinの特徴と開発環境の準備について記載されている。

  1. 簡潔
    • Javaと比較して短く書ける
  2. 安全
    • Null安全とスマートキャスト
  3. 相互運用性に優れる
    • altJSやKotlinNativeがあり、様々な開発に使用できる
  4. ツールとの親和性に優れる
    • IDEやツールがKotlinをサポートしている

Part2 基本構文

  • 変数宣言は var, val
    • varが再代入可能、valが不可(定数)
    • コンパイル時定数の const キーワード
  • 8進数リテラルがない
  • 文字列リテラルは Escaped String, Raw String
    • Raw Stringはいわゆるヒアドキュメント。trimMarginという行頭余白を落とすメソッドがある
  • 文字列テンプレートあり
  • Null許容型、ボクシングは他言語とだいたい一緒
    • if式でNullチェックをすればブロック内でNull許容型をそのまま使用可能(スマートキャスト)
  • 型変換は明示的に行う必要あり
  • ラムダ式で i -> i を省略できる it 変数
  • コレクションを生成する xxxOf, mutabuleXxxOf

Part3 演算子/制御構文

  • 同値性 == (.equals相当), 同一性 === (==相当)
  • 三項演算子なし。if式で行う
  • if (i in 1..20) { println("iは1〜20の範囲") }
  • ビット演算子は(演算子ではなく)関数として提供
    • and, or, xorなど
  • if, whenは式なので値を返せる
    • val a = if (b == 1) { "1" } else { "not 1" }
  • for inが基本。mapに対しては for (key, val) in
  • for i in 1..10 step 3 で増分変更
    • for i in 10 downTo 1 でデクリメント方向
  • ラベルは末尾 @
    • label@, break@label

Part4 関数

  • 関数の宣言はfun
  • 引数、戻り値の型指定必須
    • 何も返さない戻り値 Unit については省略可
  • 可変長引数 vararg, 可変長引数に配列を渡す *list
  • 複数の戻り値型は Pair, Triple で表現
  • 高階関数として引数に関数を渡す ::func
  • ラムダ式内でのreturnは呼び出し元での return になること注意
    • ラムダ式の終了は return@label または return@forEach (関数名)でラベルで指定
  • 関数内で関数を定義するとローカル関数になる

Part5 オブジェクト指向構文

  • デフォルト public
  • class name()の部分でコンストラクタ生成できる
  • プロパティのgetter, setterでバッキングフィールド field を使用できる
  • パッケージはフォルダ構成一致させる必要なし
  • インポートは as で別名でインポートできる

Part6 継承とインターフェイス

  • デフォルト final のため、継承可能なクラスは open 修飾子で明示する
    • 抽象クラスには abstract
  • インターフェイスの定義は class の代わりに interface

Part7 特殊なクラス

  • データクラス
  • オブジェクト宣言
  • オブジェクト式
  • コンパニオンオブジェクト
  • enumクラス
  • ジェネリック

データクラスべんりそう。

Part8 もっとオブジェクト指向

委譲プロパティ、委譲クラスが言語仕様でできるの良いですね。

感想

Javaの知識を活かして差分の知識を素早く習得」とあるように、あっさりとKotlinの言語仕様を学習できました。 Swift, TypeScriptのような新しい言語のいいとこ取りって感じでいいですね。Kotlin覚えれば主要モバイルプラットフォームで使う言語だいたい使えるようになるので頑張るぞ。 ただ、この本ではKotlinの活用先であろうAndroidアプリ開発については全く触れていないので、そちらは別の場所で学習が必要でしょう。

そういえばエラー処理について書かれていなかったけど、そこはJavaと同じなのかな…めんどい。

「Unity5ゲーム開発はじめの一歩」を読みました

読んで作ってみたので書きます。

Unity 5 ゲーム開発はじめの一歩 ThinkIT Books

Unity 5 ゲーム開発はじめの一歩 ThinkIT Books

TOC

  • はじめに
  • 第1章 新しくなったUnity
  • 第2章 Unity5でコインプッシャーゲームを作ろう(前編)
  • 第3章 コインプッシャーゲームを作ろう(中編)
  • 第4章 Unity5でコインプッシャーゲームを作ろう(後編)
  • 第5章 uGUIの簡単な使い方
  • 第6章 複数人で1つのUnityプロジェクトを管理するには
  • 第7章 全国各地で盛り上がりを見せるゲーム開発イベント
  • 著者紹介

はじめに

本書では、Unity 5 Personal Editionを利用して、実際にコイン落としゲームを制作しながらUnityの様々な機能を体験する。

第1章 新しくなったUnity

略。

第2章 Unity5でコインプッシャーゲームを作ろう(前編)

  1. 新規プロジェクトを作成して
  2. Unityの画面の見方、操作方法を学んで
  3. コインプッシャーの土台を作って
  4. コインに物理演算を加えて
  5. ゲームの視点を調整して
  6. コインに色を付けて
  7. 作成したシーンを保存

第3章 コインプッシャーゲームを作ろう(中編)

こんな感じになった。(クソというのは筆者の題材が悪いという意味ではなく私が作ると虚無のゲームになるという意味です)

第4章 Unity5でコインプッシャーゲームを作ろう(後編)

  1. コインの枚数を表示してみる
  2. コインの枚数を増減させる
  3. コインが土台から堕ちたときの処理
  4. コインが土台から落ちて加点したときに効果音を鳴らす
  5. Assetを利用して、ステージを飾ってみる

できた。

第5章 uGUIの簡単な使い方

ボタンが必要なソフトを作ったときにやってみます。

第6章 複数人で1つのUnityプロジェクトを管理するには

GitHubがあるから大丈夫。

第7章 全国各地で盛り上がりを見せるゲーム開発イベント

割愛。

感想

github.com

本日の成果物です。

楽しげなものができました。素敵な本をありがとうございました。

「後悔しないためのVueコンポーネント設計」を読みました

技術書典5で、悩める私を救ってくれると信じて購入した本です。

ponyhead.booth.pm

TOC

はじめに

本書は、筆者が業務および個人プロジェクトで得たVue.jsの知見を文書化したもの。

第1章 なぜテストを書くのか

「他人に迷惑をかけるコードを書きたくない」わかりが過ぎる…

第2章 テストしやすいコンポーネントと、テストしづらいコンポーネント

後悔しないためにはテストを書く、テストを書くためにテストしやすいコンポーネントを作る、そのためには下記を押さえようという話。

  • テストしやすいコンポーネント
    • 機能が少ない(メソッド数ではなく、担う役割)
    • 依存がない/少ない
    • 状態をもたない

依存は少なく

値を取り出すコンポーネントと値を表示するコンポーネントに分けることで、Storeに依存する場所をなるべく少なくする。

dataを使うパターン

コンポーネントに閉じた状態を表現するとき。トグルとか。

propsの型指定で避けたほうがいい型

  • Number
  • String
  • Array
  • Object
  • Boolean

上記はJSONで表現可能。それ以外の型(Dateなど)を使うと通信やデータストアで型変換が必要になりテストが複雑になるため、避けたほうがいい。

props down event up

  • 親から子へは props でデータを渡し、子から親へは this.$emit でイベントを返す。
  • 子からのイベントを購読するやり方か、propsでFunctionを渡すやり方かは、プロジェクトで統一されていればいい。

ライフサイクルフックに直接処理を書かない

  • vue-test-utilsではフックをmockできないのでテストできなくなる。

第3章 コンポーネントを分類する

コンポーネントを Presentational Component と Container Component に分類する。

  • Presentational
    • 主にpropsで渡されたデータを表示する
    • これ以外の機能を持たないようにいろいろ制約をつける(割愛)
  • Container

第4章 ディレクトリ構成とコンポーネントの分類

こんな風にディレクトリ切ると良いよという話。

  • basics
  • components
  • containers
  • pages

私は普段こんな感じ。

  • atoms
  • molecules
  • organisms
  • pages

どちらも小さい順に上から下へフォルダが並びますね。役割も一致してる。

第5章 なにをテストするか

  • templateで次の項目が正しく動作するか
  • propsが正しく受け取れるか
  • methodsが正しく動作するか
  • $emitでイベントが正しく発火するか
  • slotが正しく動作するか
  • コンポーネント同士が正しく協調しているか

最後のはざっくりした結合テストだけど業務ではここでやってしまったほうが良い箇所のような気がする。

第6章 テスト実行環境の構築

割愛。

第7章 テストを書く

ここではコンポーネントごとのテスト方法をJest,vue-test-utilsの使い方も含め、具体例を挙げて紹介している。実際にテストを書くときに参考にします。

あとがき

書きたいことが多くてそこそこのボリュームになったということ。確かに同人誌としては想像以上のボリュームだった。

感想

恥ずかしながら知らないことが結構あって非常に参考になりました。なにかに特化したソフトウェアエンジニアではないのもあり、どの分野も知識が浅いんだよなあと反省しました。フロントエンドのデザインパターンてどこで勉強してるんだろう。何をテストしたら良いのか、というのはしょっちゅう悩んでしまうので、実践する際に繰り返し読み返そうと思います。あと表紙がかわいい。

素晴らしい本をありがとうございました。

「GOで全ウェブサイトCLI化計画」を読みました

技術書典5で見かけてビビッときたので買った本です。

booth.pm

読みながら試したリポジトリc18t/hello-cobra

TOC

  • はじめに
  • 第1章 cobraによるCLI開発の基礎
  • 第2章 Chrome DevTools Protocolとchromedp
  • 第3章 技術書典サークル検索CLI
  • おわりに
  • 著者紹介

はじめに

  • SPAの台頭によりスクレイピング界は未曾有の危機に陥っていた。
  • その救世主となったのがChrome DevTools Protocol。そうですね!

第1章 cobraによるCLI開発の基礎

  • cobragolangのためのCLI開発支援ツール/ライブラリ。
  • go get github.com/spf13/cobra/cobraでインストールできる。
  • cobra init github.com/c18t/hello-cobra~/.go/src/github.com/c18t/hello-cobra プロジェクトフォルダができた。
  • cd して go install でもう hello-cobra が動く。とっても簡単。
  • cobra add goobyehello-cobra goodbye サブコマンドを追加できる。これも簡単。
    • ここでひとつfishシェルだと問題があった。私の環境だと ~/.go/src~/Project にリンクしてるんだけど、$GOPATH以下に居ないとcobra addは動かせないらしく、fishがシンボリックリンクのパスを実パスに直す仕様のために動かなかった。仕方がないので bash で $GOPATH 以下に移動して実行した。
  • オプションハンドリングの方法も解説あり。あとでviper試そう。

第2章 Chrome DevTools Protocolとchromedp

使い方については割愛。

第3章 技術書典サークル検索CLI

実践編。サークル情報を取得する機能と、取得した情報をfzfで検索できるよう出力する機能、ブラウザで開くためのURLを取得する機能の3つを実装する。(その他の機能はfzf, openなどコマンドを組み合わせる)

おわりに

CLI化できればcronなどと組み合わせることで作業時間をゼロにすることも可能!自動化しよう!

感想

GoでCLIツールを作っている最中だったのでまさにこれが欲しかったんだよという感じの本。goについてはとにかくどのライブラリを使って良いのかさっぱりわからないので、cobraの選定理由もちゃんと書いてあってありがたかったです。あと表紙がかわいい。

素晴らしい本をありがとうございました。