読者です 読者をやめる 読者になる 読者になる

筋肉とエンジニアリングで すべてを解決するブログ

筋トレ、JavaScript、Ruby で世界を変えてやります。

React-Redux をわかりやすく解説しつつ実践的に一部実装してみる

全くわからない

こんにちは。

ここ1〜2週間くらい React と Redux 触ってるんですが、あまりにもまともなドキュメントがなく、どう動かして良いのかわからなかった状態でした。

しかし、色々仕組みを追っているうちに「こんな感じで書けばいいのでは」というのがわかってきたので僕の言葉&コードでまとめてみようと思います。

独自の解釈かも知れない部分があるので、変なところはコメントいただけると助かります。

まず React について

React についてはたくさん書かれてるのと、ふぅん〜くらいに流してもだいたいなんとかなるので端折ります。

qiita.com

上記の基本〜コンポーネントの使用くらいまで読んだらだいたいOKです。

重要なのは、

(MVCで言うところの)Viewのみを担当する。
JavaScriptのコード中に(PHPの様に)「HTMLタグ(っぽいもの)」を書ける。

ここらへん。

実践的に重要となるのは、render() 中の JSX の書き方くらいでしょうか。

結局僕は「Facebook製の優秀なテンプレートエンジン」くらいのレベルで解釈して後は調べるのをやめました。今度もうちょっと深追いします。

Redux について

React だけでも フロントエンド開発はできるっちゃできるんですが、フロントエンドでは結局状態管理が必要ですよね。

例えば、

  • ページングがある一覧に対して、現在のページ数を保持したり、「次へ」を押して読み込んでる最中は読み込んでいるという状態を管理したり
  • チェックボタンが3つあって、3つチェックされたら送信ボタンが ON になるための状態を管理したり

といった状態管理するためのフレームワークです。

もちろん、React と独自実装でも状態管理はできるけど、いい感じに状態管理周りをまとめてくれるフレームワークの一つが Redux です。

Redux のアーキテクチャ

Redux は 5つの要素からなります

  • State
    • 重要なやつ
    • 状態を保持してるところ
    • この State の状態を常に監視して、View 部分である React でレンダリングを行う
  • Action
    • type をキーとして、State を更新するための定義を書く
    • 更新する時は dispatch 関数を実行することで状態更新する
    • dispatch(definedFuncInActionCreator()) というような形
    • しかし!!!更新したい状態の定義はここではしない、それは ActionCreatorでやる
    • 関数のdispatchを行う場所、的なイメージ
    • その他、ajax 通信するならここ
  • ActionCreator
    • Action では書かなかった、更新したい状態(新しいState)の定義を書く
    • 直接 State をいじるのではなく、上書き更新したい部分だけ書く
    • ファイル的には Action と同じファイル上で書いてるようだし、ほぼほぼセット
    • テストしやすくしてるため分離してるみたい
  • Store
    • 一回書いたらほとんど変更しないところ
    • State を使うよーとか、redux のミドルウェア(Logger とか Thunk とか)を定義するみたいな部分
    • 状態管理部分の実装中はあんまり触らない
  • Reducer
    • state の状態を更新するためのロジックを書く部分
    • 基本的に Switch 文中に Action で定義した State の type で分岐しロジックを書く
    • return するものは必ず新しい Object というルールが有る(Object.assign({}, state, {変更したいプロパティ}) という関数をよく書く)

ばっと説明しましたが、たぶん上記を読んだだけではよくわからない

ので、いちから設計等を考慮して実装してみたいと思います

1. まず、作りたいものの検討

今回は以下の様なものにします

  • 最初の段階では div 要素に「入力してください」と表示される
  • input ボックスにデータを入力して submit ボタンを押したら、 input ボックスの値を取得し、特定の div 要素のテキストが更新される
  • input ボックスに入力した文字数が表示される
  • show ボタンを押すと div 要素の表示が表示される
  • hide ボタンを押すと div 要素の表示が消える

ものを作ってみたいと思います。

簡単すぎず若干複雑さがあるものにしてみました。

2. State の設計

State は以下のような Object で考えます

{
    text: "更新される内容",
    number: 0,
    flag: trueかfalse
}

状態管理したいのは div 要素のテキスト、文字数、表示するしないのフラグあたりですね。

この状態が変更されたときに「どう表示を変更するか」を別途実装します。

そして、状態が変更されたならば View 側に通知するために「store.subscribe() という関数を実行する」のですが、 React-Redux のライブラリの @connect 関数(後述)を使うと勝手に通知してくれるので、View への通知はあんまり気にしなくても大丈夫です。

3. Action の設計と実装

Action で State がどう変わるか設計します。

State が変更されるのはどういうときかを考えると、

  • submit が押されたとき
  • show が押されたとき
  • hide が押されたとき

今回はこの 3パターンですね。

submit が押された時

{
    type: "SUBMIT",
    text: "inputから取得した文字列",
    number: inputのvalueのlength
}

show が押された時

{
    type: "SHOW",
    flag: true
}

hide が押された時

{
    type: "HIDE",
    flag: false
}

上記のような更新を State にかけるといい感じに差分が変更されるでしょう。

更新したい部分のプロパティだけが入ったオブジェクトを定義します。

./frontend/javascripts/actions/Text.js

export function submitText(text) {
    return {
        type: "SUBMIT",
        text: text,
        number: text.length
    };
}

export function showText(text) {
    return {
        type: "SHOW"
        // flag は可変ではなく true 固定のため、 Reducer 側で書く
    };
}

export function hideText(text) {
    return {
        type: "HIDE"
        // flag は可変ではなく false 固定のため、 Reducer 側で書く
    };
}

4. Component (というか React 部分の HTML)

簡単にベースの HTML を考えます。以下のようなHTMLで表示するとします。

            <div>
                <div class="(hide)">
                    文章文章
                </div>
                <div>
                    <span>100</span> 文字
                </div>
                <input type="text" ref="inputText">
                <button>submit</button>
                <button>show</button>
                <button>hide</button>
            </div>

ただし、 HTML のようなもの ( jsx ) であるだけで、

  • jsx は HTML ではないため、class の設定が className になっていたりするので少し注意が必要なこと
  • 既存の HTML のタグやテキスト以外にも、{this.hogehoge()} とかもできちゃう
  • js のクラスも Render 内で解釈が可能 {HogeClass}
    • import したライブラリとか読み込みたい場合に使ったりする
    • 同一ファイル内でクラスを定義してあればそれでも良い
  • 属性の書き方が以下のように少し違う(単独の文字列の時はダブルクオーテーションで良く、それ以外の時は { } で囲む)
    • 文字列を設定する場合 class="moji"
    • 数字を設定する場合 class={123}
    • インスタンス等 class={Instance}
    • 要素の結合がある場合 class={"btn " + (flag ? "hide" : "" )}
  • <p 要素名=値 要素名=値>hoge</p> というようにイコールの前後はスペースを空けない
  • <input>等の単独の要素は /> で終わらせ、 <input type="input" /> といった形で閉じる

などなど、結構直感的にわかるかと思います。

5. Component のイベントの設計と実装

さらに Component でのイベントの登録(EventListener)も考えておきます。

DOM上に onClick={dispatch(hoge(flag))} みたいにも書けますが、見通しをよく・共通化するためにも function 化します

今回の関数は以下の通り

  • submitButtonClicked()
    • submit が押されたときの挙動を書く
  • showButtonClicked()
    • show が押されたときの挙動を書く
  • hideButtonClicked()
    • hide が押されたときの挙動を書く

僕の中でまだわかりきっていませんが、ActionCreator と Component の function での役割の差分は、

  • Component のみで dispatch できるなら dispatch する
  • Component では、dispatch 前にパラメータの取得、要素の設定など可変なものを準備する
  • ActionCreator では動的な取得は必要以上に行わず、引数で済ます

といったところを考えています。ココらへん詳しい人教えてください。

今回の Component を具体化すると

./frontend/javascripts/components/Text.js

import React, { Component } from "react"
import { connect } from 'react-redux'

// 使うアクションを import する
import { submitText, showText, hideText } from "../actions/Text"

class Text extends Component {
    render() {
        // mapStateToProps で紐付けしていることに注意
        const { flag, text, number } = this.props;
        // ココらへんは Redux じゃなくて React (JSX) の書き方
        return (
            <div>
                <div className={(flag ? "" : "hide")}>
                    {text}
                </div>
                <div>
                    <span>{number}</span> 文字
                </div>
                <input type="text" ref="inputText" />
                <button onClick={e => this.submitButtonClicked(e)}>submit</button>
                <button onClick={e => this.showButtonClicked(e)}>show</button>
                <button onClick={e => this.hideButtonClicked(e)}>hide</button>
            </div>
        )
    }

    submitButtonClicked(e) {
        // input の値を取得
        // action 内ではできない事をここで処理する
        const inputText = this.refs.inputText.getDOMNode().value;
        dispatch(submitText(inputText));
    }

    showButtonClicked(e) {
        dispatch(showText());
    }

    hideButtonClicked(e) {
        dispatch(hideText());
    }
}

function mapStateToProps(state) {
    const { flag, text, number } = state;
    return {
        flag,
        text,
        number
    }
}

// react-redux にある connect 関数を使うと state と Text の this.props をひも付けできる
// 前述したとおり、 store.subscribe() を呼ばなくても良くなる
export default connect(mapStateToProps)(Text)
    

上記のようになります。

6. Reducer の設計と実装

Reducer は先程出たように、State の更新処理を行う部分。

どういうパラメータの更新かは Action で定義されているが、具体的に State のどの部分の更新なのかをひも付けてあげる部分。

Index.js

まず、 ./frontend/javascripts/reducers/Index.js を作る

import {combineReducers} from "redux"
import text from "./Text"

const reducer = combineReducers({
    text
});

export default reducer;

これは Reducers が肥大化するため、 reducers/Index.js では複数の Reducer を結合できる仕組みを作っている。

他にも処理したい Reducer が増える場合、

  • import する
  • combineReducersのオブジェクトに追記してあげる
import {combineReducers} from "redux"
import text from "./Text"
import form from "./Form"

const reducer = combineReducers({
    text,
    form
});

export default reducer;

といったように。(今回は上記は必要ないですが)

Text.js

さらに、 ./frontend/javascripts/reducers/Text.js を作ります。

ここが実際に今回の状態変更の処理をする部分になっています。

// 初期値の設定をしてあげる
const initialState = {
    flag: true,
    text: "入力してください",
    number: 0
}

// action で受け取った値を state に適用して更新する
export default function text(state = initialState, action) {
    const { flag, text, number } = action;
    switch (action.type) {
        case "SUBMIT":
            // 今回ここでは状態の更新だけだが、action の値によってさらに別な値も変えたりするなど
            return Object.assign({}, state, {
                text: text,
                number: number
            });
        case "SHOW":
            return Object.assign({}, state, {
                flag: true
            });
        case "HIDE":
            return Object.assign({}, state, {
                flag: false
            });
        default: 
           return state;
    }
}

上記の状態の更新以外の部分では、例えば以下のような処理もできる

      case "SUBMIT2":
            let newFlag;
            // 一例ですが、文字数によって他のパラメータも更新する、などの場合
            if (number > 10) {
                newFlag = true;
            } else {
                newFlag = false;
            } 

            return Object.assign({}, state, {
                text: text,
                number: number,
                flag: newFlag
            });

7. Store の設定

つなぎこみの設定するだけです。

ここも色々な書き方ができるみたいですが、

をしてあげています。

./frontend/javascripts/store/ConfigureStore.js

import thunkMiddleware from 'redux-thunk';
import createLogger from 'redux-logger';
import { createStore, applyMiddleware } from 'redux';
import rootReducer from '../reducers/Index';

const loggerMiddleware = createLogger();

export default function createStoreWithMiddleware() {
    const store = applyMiddleware(
        thunkMiddleware, // lets us dispatch() functions
        loggerMiddleware // neat middleware that logs actions
    )(createStore);
    return store(rootReducer);
} 

一回書いたらそんなに変更することはないです。

redux-thunk というライブラリを使って複数の dispatch ができるようになる部分、 redux-logger というライブラリを使って開発中のデバッグができるようになるライブラリ(ミドルウェア)を組み込んで、 rootReducer である reducers/Index.js を読み込んでいる事が理解できるでしょうか。

上記の2つのミドルウェアは必須ではないので、自分の好みに合わせてつけてみるといいと思います。

8. エントリーポイントである index.js の作成

上記まででほぼほぼ完成です。

最後にエントリーポイントを作ります。

./frontend/javascripts/index.js

import React from "react"
import ReactDOM from "react-dom"
import {Provider} from "react-redux"
import createStoreWithMiddleware from "./store/ConfigureStore"
import Text from "./components/Text"

const store = createStoreWithMiddleware();

ReactDOM.render(
    <Provider store={store}>
        <Text />
    </Provider>,
    document.getElementById('content')
);

上記の import 文でわかるかと思いますが、 const store は 7. で前述した rootReducer の読み込みとミドルウェアの読み込み部分です。

で囲んであげると Store のデータがやり取りできるようになります。

9. トランスパイル

browserify 等を使って ./frontend/javascripts/index.js を元に、 ./index.js としてトランスパイルした結果を出力します。

ココらへんも書くと結構長くなるので今回は端折りますが、次回の記事で実例とともに書こうと思います。

ちなみに、この index.js には npm install した react や redux 等も含まれている状態とします。

10. index.html の作成

外部からアクセスできるディレクトリに

と書いたHTMLを準備すると、 React の DOM が描画されます。

./index.html

<html>
<body>
<div id="content"></div>
<script src="./index.js"></script>
</body>
</html>

もちろん上記の HTML の index.js は色々すっ飛ばして書いていますが、

これらについて今後別途サンプルのリポジトリを作成します。

11. 完成

内容としては以上です。

./index.js を読み込むと1〜7までに書いた react と redux の部分が処理されていることがわかるかと思います。

ブラウザのコンソール等を見て動きをチェックしてみてください。

終わりに

こんな形でだいたいの作り方は理解はできたでしょうか?

実際の完成形のコードや概念は理解できても、どこからどう作れば良いのかのノウハウが足りなかったので参考にしてもらえればと思います。

今後実際の動くコードや gulp を使ったトランスパイル例、また非同期通信等の実装などもかければと思っていますので応援よろしくお願いいたします!

2016年 新年の誓い

2016年 あけましておめでとうございます

ついこの前 2015年が始まって、やっと「あ、今年は 2014…じゃなくて 2015年の…」って言わなくなったなぁと思ったらもう 2016年です。

毎年この感覚がおかしくなってきて最後には、「平成何年だっけ?」「もう平成じゃないよ」とかって会話が毎年繰り広げられるのかもしれないと思うと意識し続けることは重要だなぁと沸々思うわけです。

思考停止しないようにこうやって振り返り、悪いところはマイナスから 0 に近づけられるように、 いいところは超伸ばしていけるように決意をしていきたいと思います。

さて、 2015年を振り返ってみて

大きく2つ。細かくいくつか。

2015年は「考えること」と「動くこと」がよかったこととして挙げられますが、一方で考えなかったことと動かなかったことが直すべき点でもあることを再実感しました。

「考えること」について

前の記事でも書きましたが、前半は環境が変わって右往左往しながらも、後半からはどう振る舞うべきなのか考えながら動いていくことができたと思います。

6〜8月くらいの CEDEC に登壇&準備するタイミングで「 QA エンジニアとゲーム開発エンジニアの違いはなんなのか」を長い時間かけて考えたことや、 同僚と議論することで自分にとってもチームにとっても考えが深まり、やるべきことを明確にすることができたと思います。

途中何をやるにしても、なぜそれをやるのか、なんの意味があるのか、どうプラスに働くのか、懸念点は何なのかということを考えながら進めてきました。

しかし。

まだまだ考えが浅く、なぜそれを始めたのか、なぜそうすべきだと思って動いたのか、何を優先したのか、… 無数に考え足りてない部分が多く、手を動かすだけ無駄みたいな時間が多かったことも正直認めます。考えてた気はするけど全然考えてない。考えられたものの上に乗っていただけだったのではないか。違うなぁって思ったけど別に関係ないからスルーしたのではないか。

そう、やってきたけどまだまだ足りない。たまに論理的だね、って言われるけどたぶんそれは結構都合いいように言い訳してることが多いんじゃないかと思います。

ちゃんと考えてる時は僕を毎回論破してくれる優秀な友人を思い浮かべます。「もし彼から質問来ても論破し返せるようしよう」と先読みして考えている時はうまくいくことが多いし、意見に誰もが納得してくれてる気がする。

常に考え続ける。簡単にできそうで簡単にできない僕の中の大きなテーマです。

今年は考えまくる。

「動くこと」について

2015年は少しずつ新しいことにチャレンジしていけたかなぁと思います。登壇系は少なくはないし、新しい環境でエンジニアの仕事もそうじゃない仕事も徐々にやってきたし、地味に習い事も1個始めて、(実は最初ノリ気ではなかった)会社の筋肉部にも入りました。

しかし。

でも、反省する視点が2つあって、まずそこまですごい大きく動いてない。それだけか、と言われればそれだけで、結果として何か世の中が大きく変わったかと言われれば大して変わってないし、成果として胸を張って誇れるものでもない。確かに年末に部内でプロジェクト MVP 貰えたけど、インパクトとしてまだまだ。大変でも誰もが驚く動きを今年はする。

次に、自分から動いていないことが多い。基本誰かに言われてじゃぁ僕がやろうってなったものが多くて、自分から超やりたいですって手を挙げたものが少ない。姿勢自体はあんまり悪くはないと思うけど、まだ弱すぎる。自分から手を挙げて動ききることができるようになるべき。

地味な仕事とかたくさんある。けど、自発的な動きで、かつ、インパクトを大きくしたい。

その他

細かいこと書かなくていいことは箇条書きで。(順不同)

  • ジム週3、平均12回/月行く
  • 貯金
  • 家計簿アプリで収支つける
  • 無駄遣いしない
  • 体脂肪率 12〜15%
  • 素直になる
  • 歌うのうまくなる
  • いまさら楽器始める
  • 週0.5くらいで走る
  • 考えてコード書く
  • アプリリリースしてみる
  • 要らないものを捨てる

まとめ

兎に角、大きく動く。動く前にちゃんと考え尽くす。議論し尽くす。

実際のところ、結果を残す事が重要だとは思いますが、僕は今年この「考える」「動く」の2つを重視することで変化をつけたいと思います。

シンプルですが、これを毎日考え続けて行動していきたいと思います。

2015年の振り返りと思い出まとめ

2015年が終わるので振り返ります

年が切り替わるいいタイミングなので今年を振り返ってみたいと思います。 エンジニアとして、プライベートとしての話を一ヶ月ごとに振り返り、最後にまとめます。

※目標は別記事で書きます

1月

この月に部署異動をして、新しいチームでスタートを切りました。
この月から QA エンジニアとしてのキャリアがスタートしました。どんな職種でどんなことが求められて何をしていいのかどう振る舞えるのか何もわからない状態でした。そんな中でまず最初にやったのはゲーム開発に慣れることとと QA について知ることでした。半ばにスタートしたので二週間くらいはこんな感じ。

プライベートはまず DQ5 を 3日くらいでクリアし、エスタークも次の日に倒すくらいの廃人生活で始まりました。
バドミントンやりに行ったり、大学のサークルのメンバーで湯沢にスノボーしに行ったり。めちゃんこ楽しかったですね。あ、バドミントンやった帰りに食べたラーメンが美味かったです。 去年からずっと一人カラオケにハマってたのでカラオケして、ジムに通い詰める日々でした。今も変わりませんが。 あ、初めてカラオケ 1位取ったのも 1月でしたね。

カラオケ: ?回(記録なし)
ジム: 10回

2月

2月もエンジニアらしいことはあんまりやってなくて、 いろんなチームの QA について勉強してました。
今どういうフローにいて、 QA のメンバーはどういうことをやっているのか。開発メンバーではないですが、エンジニアとして問題があるコードに PR を送ってみるなどしたりもして自分の立ち位置を探ったりしてました。
その他、部の懇親会で司会、台本、資料作成等を担当し、関係各位に対して満足してもらえる会作り等やってきました。エンジニアやりつつ、こういう会を運営してるのがすごい楽しかったりします。

プライベートは、レアジョブばっかり受けてました。数年くらいやめていましたが、復帰。英語で話すのは好きなので帰宅後の英会話はやはり楽しいと感じられた月でもありました。また時間作って英会話やりたいなぁ。
その他、雨降って寒い中、鎌倉行ったなぁ。めっちゃ生しらす食べたかったけどシーズンじゃないのでめかぶ食って我慢。うまかったなー。 友人の結婚式出て 10万円分くらいの飲食代がチームで当たったりで楽しかった日々でした。

カラオケ: ?回(記録なし)
ジム: 10回

3月

3月入ってからは、ゲームの管理ツール作成したりで PHP 中心にコード書いてました。 Cocos2d-xsilexMagicSpicecascadeMySQL あたり。 PHP のバージョンが新しかったり、フレームワークを違うもの覚えたりして楽しみながらお仕事してました。
前任者からのティーチングがないまま、ソースコードしかない状態で「これ作って」って状況があったりして、雰囲気で理解しそれをドキュメンテーションするといったこともしてました。

プライベートは家族でニューカレドニア島のヌメアに旅行しました。ちょうど台風が来てて行きたかったツアーも中止になりましたが、素敵な夕日、綺麗な海、港町を感じながらフランス感を楽しめる最高の旅行でした。物価は高かったですが、自然を感じられて治安も悪くないし素敵な場所でした。新婚旅行で行くというより、何かの記念でリゾートくらいの感じで行くのがいいかもしれないですね。
3月末にはスノボーに。雪質はそこまで悪くはなかった気がするけど全然楽しかったですね。夜中出発の日帰りはなかなか堪えるw

カラオケ: 3回以上(一部記録なし)
ジム: 4回 (←え、マジ??ww)

4月

この月も引き続き管理ツール作成。使用しているものは変わらずだけど、やらせてもらえる範囲が少し広がって新規実装も担当したり。
信頼がない場ではコツコツ信頼を積み重ねる必要が有ることを実感した月でした。ただし、この月になってもどんなことを QA エンジニアがやるべきなのかが見えてなかった。最初にもっと議論を重ねて何をどういう目的でやるべきなのかということを考える必要があった。考え足りてない。

4月は実家帰ったり、御殿場までドライブ行ったり、ハーフマラソンに出たりと結構大忙し。いやーそりゃ出費してるわ。
とはいっても、実家ですごい美味しいお店発見したり、御殿場アウトレットでお買い得に買い物したり、ハーフマラソンもいいペースで完走出来たし全然プラスに感じられた月でした。

カラオケ: 9回
ジム: 10回

5月

5月は管理ツール作成しながらも、社内のノウハウをまとめる仕事してみたり。ちょっと方向転換してみようと考えた月でした。 どういうふうにノウハウをまとめれば社内で役に立ってもらえるのかということを考えてやってたのですが、見せ方、情報量、わかりやすさなどのバランスを考えながら期日内でまとめきるというのが非常に難しい作業でした。 内容が決まっていても、どういう文章にすべきかとか、自分の言葉でまとめようとすると口語調になりすぎて一般化するにはどう変えていくべきなのか迷いました。

先月遊びまくった反動で5月は GW はそこまでお金をかけずに食事しにいったり。
チャリで海沿い散歩して春うららな気分で過ごせたいい月でした。

カラオケ: 10回
ジム: 10回

6月

管理ツールからは一旦離れて、この月も社内のノウハウやプロセスをまとめる仕事してました。仕事がごちゃごちゃしてしまうことがあったので、それを統一化することで抜け漏れをなくす、といったことを。 これまた人によっていろんな解釈があるので言葉の使い方を今まで以上に気をつけたり、情報の量を意図的に減らしたりページ構造変えたりしつつの try & error ずっと繰り返してた月だった気がします。

6月は実家に法事で帰ったついでに初めて野口英世記念館行きました。 あ、あとつくばにも行ったな。つくばで博士号に乗ったのが思い出です。ラーメンも美味しいの食べたりして良い旅行でした。 いや、その次の週も下田にあじさい見に行ったぞ。遊びすぎじゃないか。

カラオケ: 11回
ジム: 7回

7月

7月には OpenSTF を社内で導入してみるプロジェクトを始めました。
結構解決し無くてはならない課題だらけで大変でしたが、上長と協力してプロジェクトやり始めました。
ハード的にもソフト的にも大変でわからないことだらけで毎日ひたすらコードとエラーログ追う日々。

プライベートは、久々に浪人時代の友達と飲み会して楽しんでたり、バーベキューしてましたね。 ボルダリングもしました。ボルダリングって相当疲労感溜まるんだなぁ、って実感した気がします。 トレーニングしてるせいか、「ふくらはぎがいい」って褒められました。スクワットとランジしててよかったと思いました。

カラオケ: 10回
ジム: 8回

8月

この月も OpenSTF 導入しつつ、CEDEC 登壇したり、ノウハウまとめるお仕事したりと少し忙しかったです。 特に CEDEC での発表は初めての発表かつ外部での登壇だったので、結構時間使って準備してました。 このあたりに QA エンジニアとはなんなのか、ということを改めて考えさせられ、自分がどう振る舞うべきなのかわかってきた頃でした。
資料もあるのでどうぞ。

ちょうどお盆の時期だったので新潟までドライブ行ったり、福島観光したり、温泉入ったり。 ひまわり畑見に行ったりと遠出することが多かったですね。

カラオケ: 6回
ジム: 10回

9月

9月はもともとシルバーウィークに合わせて有給とってたのに合わせて、慶弔休暇でお休みとってたのでいまいち仕事した感がない月だった。
ゲームのフィードバックする仕事してたのだけれども、休んでる日数が多くてあまり仕事が捗ってなかったかもしれません。

実家に帰ったり、その次の日からセブ島に旅行したりと大忙しでした。
家族とは何なのかを考えさせられつつ、セブ島ではそんなことも半分忘れダイビングしたり、カジノ行ったりして素敵なリゾートを男5人で過ごしました。
男5人ではおすすめしませんが、ボホール島でのダイビングは最高なので是非チャレンジしてみるのおすすめします。

カラオケ: 6回
ジム: 10回

10月

10月に やっとのことで 社内で使われる STF をリリース。
過去にも書いたけど、ハード的にもソフト的にも大変だった問題をやっとクリアしてリリースしたサービスだったので個人的には辛かった。 実際構築してみないとわからない大変さが隠れてた。こういう知見重要だなと思ったし、もっと考えて事前にリスクを検知できる必要があったなと思った。 そのリスクを検知することで見積もりの精度をもっと高くしていかなきゃいけない。

10月は突発的に神津島行ってきました。シーズン的なものはもう終わってたので海は寒かったんだけど、浜辺や夕日は綺麗だし、海鮮は美味しかったし満足。
数日あれば全部見れるくらいの感じで週末旅行に向いてた。
その他、会社の筋肉部に入ったので本格的に毎日ジムに通い始めてトレーニングした。

カラオケ: 7回
ジム: 17回

11月

11月は QA チーム用のツールを作りはじめたり、STF を会社でもっと使ってもらうための布教活動をしていました。
ユーザテストも実施したりして、インタビュー担当としてエンジニア以外のこともバランスよくやっていました。

11月は28日もジム行った。腹筋周りは脂肪少なくなったけど、体重と体脂肪率はほとんど変化なくてつらい月でした。
旅行とかも全然行かずひたすらジム通ってました。たまに友達の家行ったりしたくらい。

カラオケ: 4回
ジム: 28回

12月

11月同様、 ツールづくりがメイン。 Golang + Redis でコード書いて、どう書けばどう動くのかというのをずっと調べながらコード書いてました。
最初は全然わからなかったけど、コンパイル早いし、コード書いてて変なストレスも少ないしもうちょっと調べて使い勝手を調べてみたいなーと思いました。 PHP とか Ruby のほうがさくっと書けるので個人開発の時には好きだけど、 チームで開発するなら Golang のほうが良さそう。

12月も全く外出しないでずっと鳥貴族で焼き鳥食べてた気がする。
安いし旨いし最高。
忘年会に何件か行ったのとゴールドジム行ったくらいであとはジム行くかコーディングしてた気がする。
11月の反動でカラオケに行き過ぎたけど、歌の歌い方がわかってきた、と思う。精進精進。

カラオケ: 11回
ジム: 14回

まとめ

2015年を振り返って、前半は環境が変わって右往左往してましたが、後半からはどう振る舞うべきなのか考えながら動いていくことができたと思います。

しかしながら、考えが甘かったり、プラスアルファの動きをしたり、見積もりの精度が甘かったり、結果として形にしていくことができていませんでした。

さて、それらについて次の記事で深掘りしてみることにして一旦 2015年を締めようと思います。

2015年はお世話になりました。非常に良い年でした。 2016年はもっといい年にしたいと思います!