App Engineでマルチテナントなアプリを作る

Google App Engine上でマルチテナントなアプリを作る方法について調査したのでブログにまとめてみます。

マルチテナントとは?

IT用語辞典には以下のように記載されています。

マルチテナントとは、SaaSクラウドコンピューティングなどで、機材やソフトウェア、データベースなどを複数の顧客企業で共有する事業モデル。

マルチテナントとは1つのアプリケーションを複数のクライアントで共有することを意味します。

App Engineにおけるマルチテナント

App Engineは Namespace API を使ったマルチテナントの実装がサポートされています。 具体的には 公式ドキュメント に以下のように記載されています。

複数のクライアント組織に対応する個別のデータ パーティション(テナント)を提供することで、「マルチテナンシー」をサポートできます。これにより、すべてのテナントで同じデータスキーマを保持しながら、各テナントのデータ値をカスタマイズできます。マルチテナンシーではテナントを追加するときにデータ構造を変更する必要がないため、新しいテナントのプロビジョニングが効率的になります。

これにより、1つのアプリケーションをNamespaceで区切られた複数の環境で同じように動作させることが可能で、さらにこのNamespaceで区切られた環境は互いに干渉することはありません。

Namespace API

マルチテナントアプリケーションを実現するために App Engineでは Namespace API が用意されています。

cloud.google.com

ドキュメントに記載されていますが、現在サポートされてる言語は javapython、goに3言語で、Namespace API名前空間を使用するApp Engine(※1)のサービスは以下です。

  • Datastore
  • MemCache
  • Task Queue
  • Search

※1. google.golang.org/appengine のappengine package。cloud.google.comの方ではない。

このAPIを使ってマルチテナントアプリケーションを構築することで、例えば以下のようなことが可能になります。

  • Namspaceで区切られた環境は互いに干渉することがないのでそれぞれ独立したアプリケーションとして動かすこと。
  • ある名前空間を持つ環境で操作したデータが別の名前空間に影響するようなことがない状態を作ること。
  • これにより 1つのコードベースで様々な用途の環境を同時に複数用意する こと。(ex. 検証環境 etc...)

実装方法

具体的な実装方法については 公式のドキュメントを参照してください。ここでは名前空間を指定してDatastoreの新しいデータを追加する方法について記載します。

// 登録する名前空間をcontextに入れる
ctx, err := appengine.Namespace(appengine.NewContext(req), "emahiro")
if err != nil {
   panic(err)
}

key := datastore.NewKey(ctx, "SampleKind", "prop", 0, nil)
// datastoreのput処理

これだけで名前空間で区切られた環境にデータが登録されます。consoleでは以下のようにKindを選ぶ前に名前空間を選ぶUIが表示されるようになります。
ここではAppEngineのデフォルトの名前空間の他に新しく登録した emahiro という名前空間が作られていることがわかります。

※ 繰り返しになりますが、詳細な実装方法、およびDatastore以外の実装については公式ドキュメントを参考にしてください。

contextのなかに Namespaceの文字列を入れるだけという非常にシンプルな方法で名前空間を分けてデータを入れることができました。
ここでは Datastoreでの実装方法を記載しましたが、Namespace APIは DatastoreとMemCacheの両方で使われるので https://github.com/mjibson/goon を使っていてもマルチテナントアプリケーションに対応できます。(Goonも中ではdatastoreのAPIを使っているで。)

まとめ

  • App Engineにはマルチテナントアプリケーションを構築できる機能が備わっている。
  • Namespace APIを使うと簡単に名前空間を設定可能。
  • 分けられた名前空間は互いに干渉しないので、検証や配布など様々な用途で使うことができる。

参考資料

初めて技術発表をした話

社内向けではありましたが、エンジニアキャリアの中で初めて大勢の前で技術発表をするという機会を貰い、本日発表をしてきたので、そこで感じた内容をまとめます。

発表する前の自分

  • キャリアの中で規模の大小に関わらず発表経験なし。もっぱら聞く専。
  • 自分のやってきたことが発表に値するものではないと感じていたので、技術的な発表に対して後ろ向きな姿勢。
  • 発表に対して間違いを指摘されたり、Feedbackで辛辣なことがくるのではないかとビビってた。

発表した後の自分

  • 案外喋れた。(ビビってたので結構準備したのは事実)
  • 内容だけでなくプレゼンの仕方そのものも結構難しい。
  • 思ってたほど怖くなかった。
  • そこまで辛辣なFeedbackは来ない。

発表を通して勉強になったこと

  • Google スライドの使い方
    • 特にプレゼン時にトークノートと一緒にスライドを表示させる方法に手間取ったりしました。
    • PDFの出力方法が最初わからなかったりしました。
  • 時間計測の重要性
  • スライドの作り方
    • スライドで伝えたいこととスライドの説明の補足(プレゼンそのもの)のバランスを取るのが難しかったです。どうしてもスライドに全て載せたくなってしまう。1スライド1センテンス(だったかな?)とか言いますけど、知ってるのとやるのとでは大違いでした。

今回は技術についての発表それ自体よりもプレゼンについて勉強したことが多かったです。

まとめ

案外自分のやってきたことは知らない誰かのためになることがあるんだなぁと実感しました。 自分でハードルを勝手に高くしてた節があるので、少し気が楽になったかなと思います。 (とはいえ、まだちょっと苦手です。)

あと発表後にいくつか質問受けて、うまく答えられなかったり、深く検討してなかったこともあるなーと思ってあとから調べようかなと思ったので、インプットとアウトプットのサイクルってこういうことか!って腹落ちしました。

まぁなんにしても無事に終わってよかったです。

Intellij IDEA をCLIから起動する

Intellij IDEAをコマンドラインから起動する設定について記載します。

手順

  1. メニューバーのTools > Create Command-line Launcher ... を選択

image_create_cl_launcher

  1. コマンドの作成先を指定する(必要に応じてpathを通す。)

set_idea_cmd_path

  1. コマンド確認
$ which idea
/usr/local/bin/idea

使い方

コマンド単体で叩いて Intellij IDEA を起動することもできますが、プロジェクト指定すればプロジェクトまで一気に開いてくれます。

# 単体起動
$ idea

# プロジェクト起動
$ idea ./PROJECT_PATH

IDEを使ってるとDockから起動するか、spotlightやalfredから起動することが多いですが、やはりterminalから起動したくなることが多いので、設定方法をまとめてみました。

『静的解析をはじめよう - Gopherをさがせ!』をやった

golang.tokyoが公開しているCodeLabをやってみました。

golangtokyo.github.io

普段からあまりコードの静的解析をやっているわけではありませんが、Goで静的解析をする場合にはどうするのか、というのを学ぶにはとてもいい教材でした。

特に「構文解析」の章が勉強になって、以下の部分

   // ファイルごとのトークンの位置を記録するFileSetを作成する
    fset := token.NewFileSet()

    // ファイル単位で構文解析を行う
    f, err := parser.ParseFile(fset, "_gopher.go", nil, 0)
    if err != nil {
        log.Fatal("Error:", err)
    }

これだけで構文解析が完了して、あとはトークンの位置情報を記録した fset 変数を ast.Inspect メソッドに渡してガリガリ構文チェックする。
Goだと結構簡単にファイルの構文解析ができるんですね。

普段web開発にしか触れてないですけど、たまにこういったことに触れておきたいなと思いました。

Intellij で goappコマンドを動かす

※ 作業ログです。自分の環境で動作させたので再現性があるかは不明です。

事前準備

使用しているshell(bash, zsh, fish..etc)でgoappコマンドにpathが通ってる状態であること。

Intellij上の設定

$ which goapp
# ここでpathが通っていれば問題ない。

pathが通っていない時...
Intellij上でterminalを開き echo $PATH する。

この時何も設定していないと /usr/sbin /sbin /usr/local/sbin のみpathが通っている....はず。 なので自分の使ってるshellの設定ファイルで 上記の3つにもpathを通す。

Intellijを再起動する。

$ which goapp
/HOME_PATH/google-cloud-sdk/platform/google_appengine/goapp

通っているっぽかった。

おしまい...(これであってるのか....)

TypeScript の Optional Property

TypeScriptにはObjectのもつpropertyに Optional Property という機能があります。

propertyに ? をつけることでそのpropertyがない場合もあるよということを表現することができます。

公式のドキュメントには以下のように記載されています。

  • Not all properties of an interface may be required. Some exist under certain conditions or may not be there at all.

ref. https://www.typescriptlang.org/docs/handbook/interfaces.html

あってもなくてもどちらの場合も許容する、propertyを宣言するときに使います。

それだけだと「じゃあそんなpropertyを明示的に宣言する必要があるのか?」とか「正規でpropertyを定義しておけばいいじゃん」となりますが(僕もそう思いました)、例えば以下のような必須でない補足情報を追記したり(case1)、propertyが入ってるケースにおいて型を制限したり(case2)するときに使います。

case1: 何か付加情報を追記したいが、それはoptionalな値であること

interface Person {
  name: string // 必須
  age: number // 必須
  extra?: object // optional
}

case2: propertyが入ってるケースに置いて型を制限する

interface UserAgent {
  os?: 'mac' | 'win'
}

このケースでは os propertyは 存在しないかもしれないが、存在する場合は mac or win という文字列のみ許容する という表現になります。

どちらのケースにおいても別に ? をつけなくてもいいと思いますし、つけない方がinterfaceの構造を厳密に定義することができます。

しかし、propertyがないcaseにinterfaceの構造レベルでコンパイルエラーが検出されますし、それだけのためにいらないproperty込でインスタンス化するようなことにもなると思います。

// case1
const person: Person = {name: 'bob', age: 20} //OK

// case1': extra propertyをrequiredにする
const person: Person = {name: 'bob', age: 20} //Error
const person: Person = {name: 'bob', age: 20, extra: {}} //OK

Optional Propertyを使わないケースでのPersonオブジェクトのインスタンス化は冗長です。

また、可読性の観点からも 存在しないかもしれない値だとinterfaceを見ればわかります。

Optional Propertyは Typescriptの表現力の高さを感じさせるものでした。

『ファクトフルネス』を読んだ

『ファクトフルネス』を読んでとても面白い書籍だったので、学んだことの整理もかねて備忘録として書録を記載します。

ファクトフルネスに世界を捉えること

本書の中に書かれたことを自分なりに整理すると「事実に基づいて世界を見ることを阻害する人間の持つ10の本能」を コントロールすること だと思います。
コントロールとしたのは、ファクトフルネスを阻害する本能は、文字通り本能なので、全くなくすことはできません。しかし、何か本能を刺激する事象に触れた時に、出てこようとする本能をコントロールすることはできます。
本能が前に出てきたなと感じたら、一呼吸置いて、俯瞰して目の前の事象に対して客観的に事実に基づいて見ることを意識すること、それが無意識でできるようになることなのかなと本書を読んで感じました。

以下は「事実に基づいて世界を見ることを阻害する人間の持つ10の本能」とそれにどう対処するかについて、本書に記載されてる内容をまとめました。

分断本能

世界は分断されているという思い込み。

ex.

  • 先進国/後進国
  • 西欧諸国/それ以外

ファクトフルネスに考える

大半の人間がどこにいるのかを探す。

  • 話の中の「分断」を表す言葉 に気づくこと。
    • 多くの場合は、分断はなく、誰もいないと思われていた中間層に大半の人がいる。
    • 大半の人がどこにいるのか? を探すこと。
  • 「平均の比較」 に注意する。
  • 「極端な数字の比較」 に注意する。
  • 上からの景色 であることに注意する。
    • 上から観ると同じ「低い」でも下から見ると一段階違うと全く違う。

ネガティブ本能

「世界はどんどん悪くなっている」という思い込み。

ファクトフルネスに考える

悪いニュースの方が広まりやすいと覚えておく。

  • ネガティブなニュースに気づく。
    • ネガティブなニュースは耳に入りやすい。
  • 「悪い」と「良くなっている」は両立する。
  • 良い出来事はニュースになりにくい。
  • ゆっくりとした進捗はニュースになりにくい。
  • 悪いニュースが増えても、悪い出来事が増えたとは限らない。
  • 美化された過去に気をつける。

直線本能

「ひたすら〇〇し続ける」という思い込み。

ファクトフルネスに考える

直線もいつかは曲がることを覚えておく。

  • 「グラフはまっすぐになるだろう(線形に進む)」という思い込みに気づくこと
    • 線形に進み続ける方が珍しい
  • 直線のグラフばかりを当てはめないようにする。
    • S字、滑り台、コブ、倍増、いろんなグラフの形がある。

恐怖本能

危険でないことを「恐ろしいこと」と考えてしまう。

ファクトフルネスに考える

リスクを計算する。

  • 恐ろしい物事には自然と目がいってしまうことに気づくこと。
    • 恐怖と危険は異なる。
  • 世界は恐ろしいと思う前に、現実を見ること。
    • メディアや自分自身の関心フィルターのせいで世界は実際より恐ろしく見えてしまう。
  • リスク = 危険度×頻度質×量
    • 恐ろしさはリスクとは違う
  • 行動する前に落ち着くこと。

過大視本能

目の前の数字が一番重要だという思い込み。

ファクトフルネスに考える

出てきた数字を比較する。

  • ただ1つの数字が、とても重要であるかのように勘違いしてしまうことに気づくこと。
    • 比較、割り算など他の指標を駆使して別の意味を見いだせる。
  • 比較すること。
  • 80:20ルールを使うこと。
  • 割り算をすること。
    • 量それ自体よりも大抵は「割合」の方が役に立つ。

パターン化本能

1つの例が全てに当てはまるだろうという思い込み。

ファクトフルネスに考える

分類を疑う。

  • 1つの集団のパターンを根拠に物事が説明されていたら、それ自体に気づくこと。
    • パターン化は間違いを産みやすい。
    • パターン化本能をコントロールするには、分類を疑うこと
  • 同じ集団の中にある違いを探すこと。
  • 違う集団の中の共通項を見つけること。
    • ex.) 女性一人当たりの子供の持つ人数は地域が違えど関係する指標は所得である。
  • 違う集団の間の違いも探そう。
    • ex.) 意識のない兵士(成人)と眠っている赤ちゃんへの対応。
  • 過半数」に気をつけること。
  • 強烈なイメージに注意すること。
  • 自分以外アホだと決めつけないこと。

宿命本能

全てはあらかじめ決まっているという思い込み。

ファクトフルネスに考える

ゆっくりした変化でも、変化していることを心に留めておく。

  • 色々な物事(ヒト、国、宗教、文化)が変わらなく見えるのは、日々の変化がゆっくり少しずつ起きているからだと気づくこと。
  • 小さな進捗を追いかけること。
  • 知識をアップデートすること
  • おじいさんやおばあさんにも話を聞くこと。
  • 文化が変わった例を集めること。

純化本能

世界は1つの切り口で理解できる、という思い込み。

ファクトフルネスに考える

1つの知識が全てに応用することはできない。

  • 1つの視点だけでは世界は理解できないことを知ること。
    • なんでもトンカチで叩くのではなく、様々な道具の入った工具箱を準備した方が良い。
  • 自分の考え方を検証すること。
  • 知ったかぶりはやめること。
  • やたらめったらトンカチを振り回すことをやること。
  • 数字は大切だが、数字だけに頼らないこと。
  • 単純なものの見方と、単純な答えには注意すること。
    • シンプルであることと、簡単であることは違う。

犯人探し本能

誰かを責めればはものごとは解決する、という思い込み。

ファクトフルネスに考える

誰かを責めたところで、問題は解決しない。

  • 誰かが見せしめとばかりに責められていたら、それに気づくこと。
    • 誰かを責めると他の原因に目がいかなくなり、将来起こるであろう同じ間違いを防げなくなる。
  • 犯人ではなく、原因を探すこと。
  • ヒーローでなく、社会を機能させている仕組みに目を向けること。

焦り本能

今すぐ手を打たないと大変なことになる、という思い込み。

ファクトフルネスに考える

小さな一歩を重ねる。

  • 「今すぐ決めないいけない」と感じたら、自分の焦りに気づくこと。
    • そもそも、今(その時)決めないといけないことは滅多にない。
  • 落ち着くこと
    • 深呼吸、深呼吸。
  • データにこだわること。
  • 占い師に気をつけること。
  • 過激な対策に注意すること。

まとめ

紹介されていた本能は自分も働いてることが今まで多々ありました。特に、

  • 極端な2つの集合に分けるのではなく、レベル1~4の段階でそれぞれ集合があること。そして、中間があることを念頭に置くこと。
  • ある1時点の数字や現実の結果だけに目を向けず、過去からの進捗をみること。
  • 今時点で「悪い」ことと現在進行形で「良くなっている」は両立すること。

この3つはこの本を読んで「確かに!」と気付かされたことでした。どうしても、広告やテレビを始めたとしてマスメディアの持ち出すドラマティックなメッセージやストーリー性に引きづられてしまって、思考停止して事実を正確に捉えられないことがあります。
正直これ自体はこのエントリの冒頭でも記載した通り、本能なのでなくすことはできませんが、本能の活動を意識的にコントロールするための材料を手に入れることができたと思います。

身の回りに溢れている、極端な分断的表現、ドラマティックなストーリーや単一の数字には注意深くなるきっかけを与えてくれるいい書籍でした。

Intellijでlspを使う

lsp(Language Server Protocol) とは?

The Language Server protocol is used between a tool (the client) and a language smartness provider (the server) to integrate features like auto complete, go to definition, find all references and alike into the tool

cf. Langserver.org

自動補完、定義ジャンプ、参照の検索などの機能を各ツール(editor or IDE and so on...)に統合するために、ツール(クライアント)と言語機能プロバイダ(サーバー)間でおしゃべりできるようにする共通仕様です。
共通仕様になってるから今までは自動補完始め開発支援系のライブラリが色んな言語、IDE独自で開発しなくて良くなるのだと思います。

cf. Big Sky :: gocode やめます(そして Language Server へ)

Intellijにlspを導入してみた

公式でプラグインが出てるので入れてみました。
ほとんどGitHubに記載されてる内容ですが、Goで実際に試してみます。

github.com

手順

Preference > Pluginでlsp関連のプラグインを検索してインストール、再起動をします。

f:id:ema_hiro:20190111025121p:plain

以下の項目があればOKです。

f:id:ema_hiro:20190111025141p:plain

ドキュメンテーション

これ思いの外便利です。まず定義にhoverするとhoverした定義のドキュメントが表示されます。ショートカットはデフォルトでは ^ + J です。 さらにhoverした状態で '^ + J' を押すと右側に詳細なドキュメントが表示されます。

ドキュメントの表示設定は Preference > Editor > Generalの下記の場所にチェックマークを入れます。

f:id:ema_hiro:20190111025806p:plain

実際に表示してみた結果が以下(net/httpパッケージで試してます。)

f:id:ema_hiro:20190111024809p:plain

f:id:ema_hiro:20190111024826p:plain

f:id:ema_hiro:20190111024907p:plain

コードジャンプ(定義ジャンプ)

別ウィンドウが開くようになりました。今まではコードの定義に対して Ctrl or Command + Click/ Ctrl or Command + N をすると定義の下部にずらっと一覧が出ましたが、別ウィンドウになったので検索性が向上したように思います。
ただ、その他は特にLSPを入れてIntellijがLanguage Server Clientになったからといって特段変わったことがあるようには感じませんでした。ショートカットも同じですし。

コード検査

Analyze -> Inspect CodeでLSPを使ってるかどうか確認できます。 検査すると検査結果一覧が下部に出ます。この辺もLSP使う前とあんまり挙動自体は変わっていないと思います。

f:id:ema_hiro:20190111025854p:plain

まとめ

試しに使ってみましたが、あんまり導入前と変更点はなさそうでした。まだlsp自体も発展途上っぽいので今後に期待。

intellijのgoのプラグインではそもそも今現在LSPをサポートしていないので、この辺はクライアント(IDE)自体がLSP対応するプラグインを用意していても、言語側のプラグインが対応するのを待つことになると思います。

plugins.jetbrains.com

しかし、現時点でまだまだ機能が不十分とはいえ、ドキュメントをそのまま参照できるようになる機能だけでも良さそうでした。
IntelligのLSPの設定にはLanguage Serverの参照先追加設定とかもありましたが、この辺まだよく使い方わかってないので追々わかったら追記していこうと思います。

NuxtでTodoアプリを作成する

はじめに

気になっていたNuxtを触ってみました。
軽く触れて、ドキュメントを読んだだけでしたが今回は簡単なtodoアプリの作成をしてみます。

Nuxtは日本語のドキュメントがとても充実していて インストール - Nuxt.js を見ればほぼ誰でもNuxtを簡単に始めることができます(すごい)

SetUp

install

npx create-nuxt-app myNuxtTodos
# 略
Use a custom server framework (Use arrow keys) # Nuxt試すだけが目的なのでサーバーサイドFWは使わずにいきます。
❯ none
  express
  ...
Use a custom UI framework (Use arrow keys) # UI FWも特に使わずにいきます。
❯ none
  bootstrap
  vuetify
  ...
Choose rendering mode (Use arrow keys) # 今回はUniversalではなくSPAにします。
  Universal
❯ Single Page App
# その他は以下のような設定で行いました。
Use axios module yes
Use eslint yes
Use prettier yes
# あとは勝手にNuxtのプロジェクトが作成されます

起動方法

インストールシーケンスに書いてる通りです。devしか触るときは使ってません。

To get started:

  cd myNuxtTodos
  npm run dev

To build & start for production:

  cd myNuxtTodos
  npm run build
  npm start

ちょっとハマった

eslintをONにした状態でデフォルトでNuxtのアプリケーションを起動すると

/path/to/myNuxtTodos/pages/index.vue
  36:1  error  Delete `⏎`  prettier/prettier

✖ 1 problem (1 error, 0 warnings)
  1 error and 0 warnings potentially fixable with the `--fix` option.

というエラーにもしかしたら当たるかもしれませんが、これは書いてる通りに pages/index.vue ファイルで style 属性に改行が入ってることが問題なので該当行の改行を削除すれば問題なく起動します。

Vuexのモードを指定する

NuxtでVuexを使う場合、クラシックモードモジュールモード があります。

クラシックモードとは?

Vuex インスタンスを返すメソッドをエクスポートする store/index.js ファイルを作成します。ファイルとしては stores/index.js のみがあってこの中で Vuex をインスタンス化し、actions, mutations, getters が全て一箇所にまとまってる状態のファイルがあることを指します。

モジュールモードとは?

store ディレクトリ内にモジュールと対応するファイルを持つようにjsファイルを分割することです。 jsのファイル的には stores の中に分割するStateごとのjsファイルを作成します。

TODOアプリを作ってみる。

ドキュメントに沿って簡単なTodoアプリを作ってみます。ちなみに内容はVuexの章にあるTodoのほぼコピペです。Vuexはモジュールモードを使いました。

コードはこちらに上げてます。
il/myNuxtTodos at master · emahiro/il · GitHub

まとめ

ほぼドキュメントのコピペでしたが、Vue/Vuexの基本的なところがわかってる方にがサクッとvueのアプリを作ることができるなと感じました。 NuxtってVueでSSRを簡単にできるライブラリ?くらいの理解でしたがVueのアプリケーションを簡単に作成できるFWという説明がなんとなく理解できました。
今回は素のjsで書いたのですが、いつも業務で扱ってる技術スタックは Typescriptなので Nuxt/Typescriptを使う方 (公式ではすでに typescript-template/template at master · nuxt-community/typescript-template · GitHub があるけれど)を試してみたいと思います。

VuexにおけるGettersのメソッドスタイルアクセス

gettersでstateから任意の値を取り出すときにVuexではGettersのプロパティの返り値にfunctionを指定することで、Gettersのプロパティに関数の引数という形で直接値を渡す(アクセスできる)手法があります。これを メソッドスタイルアクセス と言います。

メソッドアクセススタイルについてはVuexの公式のGettersのドキュメントでも記載があります。

ref. ゲッター #メソッドスタイルアクセス | Vuex

サンプルコードは以下のようになります。

Gettersでのプロパティの定義

getters: {
  hogeById: (state) => (id) => {
    // 外部から直に私た変数をidに入れて使うことができる。
  }
}

呼び出す側

store.getters.hogeById(2) or this.hogeById(2) // getters.hogeById 内で使われる id には 2が入る。

typescriptで書き直すと...

定義元

const hogeGetters: GetterTree<HogeState, RootState> = {
    hogeById(state){
        return (id: number) => {
        // id: numberを使った何かしらの処理
    }
}

呼び出す側

this.hogeById(123) // hogeById内でのstateを何らかの条件を元にGetするPropertyで id=123 として直に値を扱うことができる。

VueのGettersそれ自体はオブジェクトを作成しています。

const hogeGetters: GetterTree<HogeState, RootState> = {
    hogeById(state) {
        return (id: number) => {
            // idを使った何らかの処理
        }
    }
}

typescriptの例で見るとわかりやすいですが、hogeGettersは {} なのでそれ自体はオブジェクトであり、そのオブジェクトが hogeById という関数(hogeGettersオブジェクトからみたらプロパティ)を持っています。
hogeByIdをはじめとしてgettersの関数には引数としてstate(他にもgettersやrootStateなどVuexの作法に則ったstateやgetters)を渡していますが、呼び出し元では通常stateを明示的に指定しません。これはVuexのGettersではstateを渡さずともどのstateに対して呼ばれたものなのか呼び出したコンテキストから自動的に解釈してくれているからだと思います。

例) HogeというStateをもつ画面においてにthis or store.getters でHoge StateのGettersが呼ばれた場合には必ずHogeをゴニョった結果(state)が得られます。

あるStateのもつGetterの関数が呼ばれた時に、その関数の返り値が関数(function)であると、その関数の引数を呼び出し側から指定した特定の値にstateの引数を通り越して、直でアクセスできるように解釈してくれるみたいです。
この辺、何でそうなるのか時間のある時にもう少し調べてみようと思います。(僕のフロントエンド力で調べられるかわかりませんが...)

このメソッドスタイルアクセス、非常に便利だし、ちょっと見慣れない形でありますが、慣れるととても綺麗にGettersで特定の値を扱えるなと思いました。
ただ、参考文献はVuexの公式ドキュメントくらいしかなく、ググってもあまりヒットしないのでメジャーではないのかもしれません。。。ただ知ってるといいなと思う記法だったの備忘録として記載しました。

Updated at 20190109

上記でメソッドスタイルアクセスがどうして動作するのかの仮説をややこしく記載しましたが、この記法はJSのクロージャーだと捉えると腹落ちしました。

developer.mozilla.org

getters: {
  hogeById: (state) => (id) => {
    // 外部から直に私た変数をidに入れて使うことができる。
  }
}

というgettersのメソッドに対してメソッドスタイルアクセス記法を使ったとすると、hogeByIdメソッドを実行するときは必ず、stateが暗黙的に渡されて、さらにその関数内で作成されたローカル変数 state を保持する 'scope' オブジェクトが作成されます。それは関数の引数として渡された変数とともに初期化されます。
このgettersメソッドにおいては hogeById メソッドが呼ばれる段階で state変数とid変数が初期化されてメソッド内で使えるようになります。

refった JavaScript「再」入門のクロージャーの章にて例に出されている以下のサンプル

function makeAdder(a) {
  return function(b) {
    return a + b;
  };
}

var x = makeAdder(5);
x(6) //11が出力される

これをgettersのhogeByIdと合わせてみると以下のような構造と捉えることができます。 ※ 擬似コードです。

var hogeById = getters(state)  
hogeById(1) // id: 1 で操作されたstateが返ってくる。

厳密な理解としてはまだ正しくないのかもしれませんが、クロージャーの構造としてみるとメソッドスタイルアクセスで指定した引数をstateを通り越してgettersのメソッドに伝播させることができるのか少しだけ理解に近づいた気がしました。

fishで &&、||、! がようやく使えるようになった

やっとか!という思いが強くてエントリを書いてしまいました。

表題の通りですが fishが2018年末に3.0.0にメジャーバージョンアップされていました。

github.com

その中で特に嬉しかったのがこれ

fish now supports && (like and), || (like or), and ! (like not), for better migration from POSIX-compliant shells (#4620).

fishユーザー今まで &&|| が使えずに、そういう手順を見かける度にand|or に書き直すが、しぶしぶzshを使うことで耐え忍んできたけど、ようやくその無駄なコストから少し解放されそうです。

fishがようやくまともなshellに少し近づいてくれました。感謝🙏🙏🙏

2019年 ~抱負~

エンジニアとして

あれこれ目標立てても達成できなくて振り返りで凹むので最低限これは続けたいことをピックアップしました。

現在使ってる技術のベースの知識を深化

今の自分のベースとなる技術スタックが

なので今年一年は新しいことを覚えるのを一旦ストップしてこの領域の知見を深めることを頑張りたいと思っています。

書を読む

迷ったんですけどこれを入れました。
インプットしたことがそのまま業務に生きるわけではないですが、これを目標に入れないとやらなくなりそうなので最低月1冊は技術書を読破したいと思っています。

読書録は emahiroの本棚 (emahiro) - ブクログ にて公開してます。

技術書だけでなく、インターネットの技術仕様やホワイトペーパーも読んでいきたいと思っています。

アウトプットを継続する

アウトプットがあってこそのインプットなので、このブログは引き続き書き続けたいと思っています。

その他

エンジニアとして以外の部分で。

料理のレパートリーを増やす

本当に頑張りたい。むしろ一番頑張りたいのはこれかもしれない...。

物を捨てる

自宅にある使わなくなったものをガンガン捨てて、身の回りを身軽にしていきたいです。

いいものに投資する

捨てる一方で、QOLを上げてくれるものへは惜しまず投資していきます。とりあえず初売りでスニーカーに投資してきました。

やらないこと

あえてこの項目を用意してみました。個人的には以下のことはやらないことを目指したいと思います。

0 -> 1 の開発

これ決めておかないとどうしても心が揺れてしまうタイプなので、新規とか0->1領域の世界は昨年に続いて一旦封印し、愚直に作ったもの、及び既に作られたシステムを安全に運用する力をつけていきたいと思っています。

新しい言語の習得(※ 仕事以外)

業務で必要になるケースを除いて新しい言語を覚えることに時間を使うより、今持っている技術スタックへの理解を深化させることに時間をかけたいと思っています。

2018年振り返り

今年の振り返りです。

新年に立てた目標はこちら。

ema-hiro.hatenablog.com

エンジニアとしてコミットしたと言えるプロダクトをつくる

評価: 🙆‍♂️

普段で業務で開発しているプロダクトは AndApp | スマホアプリがPCで遊べる | アンドアップ と言いますが、今年の後半はこの リニューアルプロジェクトでUI周りをゴリゴリ触る機会があり、かなりコミットできたと言えるんじゃないかなと思います。

引き続きGoをゴリゴリ書いてましたが、個人的には古き良きjQueryで止まっていた自分のフロントエンド力を今時のスキルセット(SPA + Typescript) にアップデートできたいい機会になりました。

月2冊以上の技術書を読む

評価: 🤔

最初の半年はできていましたが、後半失速しました。
書籍である程度インプットしてもあんまり実務に活きないなーって思い始めたのがきっかけなのと、買った本でも興味のある章だけ読んでサクッと次に行くとかしてたので、実際読んでいたけど、読了した!と思えるものは後半あまりなかったのもあります。

このエントリを目にしてから少しずつ読み方が変わりました。

qiita.com

とはいえ、この読み方は嫌いじゃないので今後も続けていこうかなと思いますし、読了数を追わないようにしたいなと思いました。

そんな中でも『エンジニアリング組織論への招待 ~不確実性に向き合う思考と組織のリファクタリング』は別格に面白かったです。

使ってる技術であれば『Goならわかるシステムプログラミング』はかなり仕事に活きました。

githubへの1commit/weekをしていくこと

評価: 🙅‍♂️

全くできませんでした。個人の勉強記録はもう少し定期的にあげてもよかったような気もしてますが、やはり作りたいものがないとモチベーションが継続しません。。。
草ばっか生えてても中身なければ意味がないし、何か作りたいモチベーションが今の所ないのでここは来年はあまり意識しないようにしようと思います。

新しいサービスは積極的に使っていく

評価: 🙆‍♂️

もう癖ですね。今年も色々使ってみてそのほとんどはその場で消しました(笑)
そして使い続けてるサービスも特に残りませんでした。これほど無収穫な年も珍しいです。毎年何かしら「これはいい!」って思ってずっと使い続けてるサービスがあったので。

新しい言語を一つ仕事レベルで習得すること

評価: 🙆‍♂️

Typescriptを仕事レベルで習得することに挑戦し、実際プロダクション投入できたことはよかったです。
来年も引き続き新技術や新しい言語へのチャレンジはしていきたいことですが、浅く広くても仕方ないので当分は

  • サーバーサイド: Go/GCP(GAE)
  • フロントエンド: Vue/Typescript

をベースにしていきたいかなと思っています。
どれもIDEの恩恵を受けることができてとてもDXが高く書き心地がいいと感じています(※ 個人の主観です)

そのほか

  • 自炊のレパートリーを増やすこと
    • できませんでした...
  • ブログを引き続き継続して書くこと
    • できました。ただ、社内で捕捉され、見られてることが多いらしいので迂闊なことは書けなくなって辛いです。
  • 資産運用や税制といったファイナンシャルの教養を身につけること
    • うーん...道半ばです....。

2018まとめ

新しいサービスとか0->1が好きな人間でしたけど、そこをまずは封印してベタな ものづくり力をつけること にフォーカスすることで、気づきの多かった一年でした。
小さなサービスしか経験したことのなかった自分にとって これまでのエンジニアキャリアの中で一番障害を出しましたし、その度に色々助けてもらいながら学びがありました。
(できることなら来年は障害起こすようなことを減らしたい....)

今年の反省を踏まえつつ、来年はどんなことを頑張ろうか年末年始に考えようと思います。

それではみなさん良いお年を〜

社内isuconに参加して惨敗した話

先日(12/10)社内でisucon8の問題を解くイベントが開催されたので参加してきました。

詳しい内容は

を参照してください。
今回は僕の振り返りをまとめてみます。

結果

惨敗でした。予選通過スコアが3万弱くらいだったので遠く及ばないスコアしか出すことができず、文字通り「なんの成果もあげられませんでした」状態で無事終了しました。

敗因

こんな感じかなと(若干言い訳じみた内容も含みます)

isucon慣れしてない

しょっぱなから言い訳です(笑

こういった競技プログラミング的なことを経験したことがなかったので、まずレギュレーションを確認したり、何から取り掛かるべきかってところであたふたしてしまいました。ダッシュボードの使い方とか最初よく分かってませんでしたし初動のここで時間がかかってしまいました。

また、チームとしての作業分担をあらかじめ決めておけませんでした。慣れてるチームはある程度役割分担を先に決めてしまってサクサク作業を進めていた印象でした。

Linux忘れてる問題 and インフラの知識不足

Linuxの使い方とリソース監視のところが丸っと忘れててなんの力にもなれませんでした。
普段の業務はほぼPaaSの運用作業なのでVMSSHするなんてめちゃくちゃ久しぶりでしたし、sysctl系のLinuxコマンドもほぼ忘れてたり、知らないもの多くてこの辺知ってる知らないで確実に差が出てしまったところだなと思いました。
特にサーバーのリソース監視のところさっぱり忘れてて、サーバーのリソース監視ってどうするんだっけ?とか初歩の初歩でどつまづいてました。 dstat コマンドとかそういえばありましたね。

計測方法の未整備

憶測するな、計測せよ という当たり前のことができてませんでした。
まずボトルネックになってるEPがどこでそこを高速化するって言う当たり前のことなんですけど、参加したチームでこの辺の計測の手法とかツールを先決め事としてやっておけなかったのがあとあとになって響きました。
パラレルで作業するに当たって誰がどこをするのか、なんでそれをするのか?をちゃんと根拠立てて進めるために、計測する仕組みを先に整えておけばよかったと思います。
高得点を出したチームはここが出来ていたように思います。
この辺もプロファイルするコマンド知っていたり、計測するプラクティスを知ってる知らないで差が出たなと思いました。

実装力不足

GetEvents地獄をさっさと取り除ければもっと色々出来たのかなと感じました。
ボトルネックを見つけた後、素早く修正する単純な実装力もないなと実感しました。後述する理由もあってオンタイムで参加できなかったので、解決にかける時間がそもそも少なかったというのはありますが、それでももっとサクサク実装できればよかったなと思いました。
使い慣れてないライブラリやツールであっても使えるように日頃から素振りとかしているとこういう時に役に立つんだなと思います。

そのほか

差し込み業務があって参加が遅れてしまいました...(これは仕事なので仕方なし)

まとめ

基本的なところでつまづいてしまった ってところが大きいです。
実力不足を痛感しました。

それに気づけたいい機会でした。
どうしても普段仕事をしていると、自分がどれくらいの実力なのかわからなくなる時があるのでこういった競技に参加してみるのも自分を客観視できるいい機会だなと思いました。

今回予選問題を作成した karupanerura sanが「isuconはweb開発の総合格闘技」と言う言葉を使ってますが、その意味が少しわかりました。

アプリケーションレイヤーだけでなく、インフラや、ボトルネックを見つける力、それに対して最短でアプローチし、かつ最速で実装するスキルを求められましたし、どれを取っても全く不足してました。。。
(もちろん業務で書かないようなコードの書き方もしたので、仕事においてはこれができればいい、ってわけでもないんですが...)

反省ばかり並べても悲しくなるのでよかったところを最後にまとめます。

よかったこと

  • isuconと言うイベントを体験することが出来たこと。
    • 知ってはいましたが参加するのにおよび腰だったのでこういった社内で開催される機会があってよかったです。イベントへの心理的なハードルを下げることが出来ました。
  • 速度アップという目的に特化したことで普段業務で意識しないところまで意識せざる得ず、よく言われる問題(N+1問題とか)を実際に体験出来たこと。
    • ベタなIaaSの構成だったのがとてもよかったです。リソースが限られている中で高速化について考える機会がクラウドを使っているとそんなに訪れるわけではないですが、無駄な実装をしているとそもそもいくらお金かけても意味がないので。
    • 無駄な実装を取り除くとスコアが上がる、単純なことですが定量的に評価されるとなぜやるのか?ということの意味がわかります。

余談

今回はGoで参戦しましたがこういったイベント(予選ではなく社内開催ではありましたが)に参加したことで、言語ごとに多少に有利不利はあれど、言語で差が出る以前の基本的なweb開発のスキルが大事であることを実感しました。
実際、講評にもある通り、Goは言語的には有利だったにも関わらず全くその良さを出すことは出来ませんでした。そのレベルに行く以前のところでつまづいたので全くスコアを出すことは出来ませんした。
問題解決に最適なツールを選択すること、そしてそれを使う自分の基本的なスキル上げる方が大事だなと思いました。

精進しよ....