OmniAICreator/Qiita-1.07M huggingface dataset:
Rails5のwebpacker環境でwebpack-bundle-analyzerをdocker-composeで使えるようにする

Rails5環境の`webpacker`でコンパイルされるJavaScriptの容量がやけに多くてそれを調べるために`docker-compose`で動かしているRails環境で[webpack-bundle-analyzer](https://www.npmjs.com/package/webpack-bundle-analyzer)を動かせるようにしたのでその方法を記載します。


`docker-compose.yml`でポートが通るようにします。

```docker-compose.yml
version: '3'
services:
  web:
    build: .
    command: bin/rails s -p 4000 -b '0.0.0.0'
    volumes:
      - .:/app
    environment:
      - DOCKER_DB_HOST=db

    ports:
      - "3000:3000"
      - "8888:8888" ＃ 追加
    depends_on:
      - db
〜(略)〜
```

`package.json`の`dependencies`に`webpack-bundle-analyzer`を追加します。

```package.json
{
  "name": "lamipass-rails",
  "private": true,
  "dependencies": {
    "@rails/webpacker": "3.5",
    "rails-erb-loader": "^5.5.0",
    "rails-ujs": "^5.2.2",
    "webpack-bundle-analyzer": "^3.1.0" <-追加
  },
  "devDependencies": {
    "webpack-dev-server": "2.11.2"
  }
}
```

`webpacker`の設定ファイル(JavaScriptの方)を変更します。

```config/webpack/development.js
process.env.NODE_ENV = process.env.NODE_ENV || 'development'

const environment = require('./environment')
// webpack-bundle-analyzerの読み込み 
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
const config = environment.toWebpackConfig()

// pluginsに追加する
// analyzerHostにはdocker-compose.ymlのservicesのRailsのservice名を指定する
config.plugins.push(new BundleAnalyzerPlugin({ analyzerHost: 'web' }))
module.exports = config
```

`docker-compose`が止まってたら起動する。

```bash
$ docker-compose up -d
```

Railsが動いているコンテナに入る

```bash
$ docker-compose exec web bash(imageでalpine使ってたらash)
```

以降Railsが動いているコンテナ内でのコマンド実行。
`yarn install`を実行する

```bash
＃ yarn install
```

`webpacker`を実行する

```bash
＃ yarn run webpack --config config/webpack/development.js
```

```bash
Webpack Bundle Analyzer is started at http://web:8888
Use Ctrl+C to close it
```

と表示されたら、`webpack-bundle-analyzer`が起動しています。
`http://localhost:8888/`へアクセスしたら、JavaScriptのファイルごとに元ファイルの容量が大きさに比例して表示サイズの大きさが確認できるページが表示されます。

[Foreman](https://github.com/ddollar/foreman)とか使って、`webpack-dev-server`を`Rails`コンテナ内で起動するようにしていたら、普通に`docker-compose`起動すれば、`http://localhost:8888/`にアクセスできるようになります。
MacでのPython環境構築

真面目に開発環境を用意する場合はdockerを使うべきだけど、
手元でサクッと色々試すための環境も作りたい。
その上でも
・python自体のバージョンを切り替えて使いたい。(主にv3.6を使いたい)
・ライブラリを切り替えて使いたい。
という２つの目的を満たす形で環境を作りたい、という場合の手順メモです。

##今回利用するツールの説明
**homebrew**
言わずと知れたmacのパッケージマネージャ
(ほぼデファクトスタンダードなものにもかかわらず、個人？が運用しているというのが、自分的には微妙、、なんだけど、他に良いものも見つからないので仕方ない。)

**pyenv**
python自体のバージョンを切り替えるためのツール
>似た名前のものにpyvenvとは別物。pyvenvはdeprecatedで後述のvenvを使うように書かれている。


**venv**
python自体に組み込まれている仮想環境作成ツール
もともとvirtualenvという独立したツールだったが、python3.3から組み込まれた


#まずはhomebrewを入れる
macにhomebrewがまだ入っていない場合、インストールする
https://brew.sh/index_ja にあるインストール方法でインストールします。

```
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
```

#pyenvをインストールする
python自体のバージョンを切り替えることができるツールであるpyenvをインストールする

```
brew install pyenv
```

インストールしたらパスを設定しておきます

```:bash_profileへの設定。初回は直接実行もしておく。
echo 'export PATH="$HOME/.pyenv/shims:$PATH"' >> ~/.bash_profile
export PATH="$HOME/.pyenv/shims:$PATH"
```

インストール後
`pyenv install --list`
で利用可能なpythonの一覧が表示されます。




#macとpyenvでのzlibエラー対応
pyenvを利用しようとすると、zlibに関するエラーが発生するのでhttps://qiita.com/zreactor/items/c3fd04417e0d61af0afe
にかかれているように以下のコマンドで対応する

```
sudo installer -pkg /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg -target /
```

#利用したいpythonバージョンをインストール&切り替える(3.6.8を利用する場合)
```
pyenv install 3.6.8
pyenv global 3.6.8
```

#venvでの環境切り替え
```
python -m venv [環境名]
```
で[環境名]に以下のようにディレクトリが作成されます

```:[環境名]ディレクトリ以下の構成(抜粋)
bin/
  activate :この環境を利用するためのスクリプト
  pip :この環境用のpip
  python :pythonの実態へのリンク
include/
lib/ :この環境のpipでインストールしたライブラリはこの下に置かれます。
pyenv.cfg
```

ライブラリもこの下にインストールされるので、他の環境を汚さずに操作できるようになります。

```
source [環境名]/bin/activate
```
でこの環境の利用モードになります。

ここで

```
python --version
```

とすると、venvで環境作成したときのバージョンになります。

なお、上記環境利用状態から出る場合は以下のコマンドです。

```
deactivate
```



ガッツリ環境を用意する場合はdockerを使いましょう。
PHPでmySQLへ接続する


 2019/4/1 参考記事を間違ってたので修正。

---
PHPでmySQLを操作するところが理解できなかったのでまとめてみました。
正直、ちゃんと理屈をまとめられるほど理解できてないので **どうすりゃできるんだよ！**ってところだけメモ。
まぁ、1.DBへ接続する、　2.クエリを作って実行する、　3.戻り値を取得する　ってだけです。


#DBへの接続情報
インスタンスを生成する際、引数で接続先情報を渡します。

```php
$dbh = new PDO('mysql:host=$hostname;dbname=$dbname', $user, $pass);
```

\$hostname:接続先のホスト名
\$dbname:接続先のデータベース名
\$user:ユーザ名
\$pass:パスワード

#SQL文を実行
実行には2種類の方法があります。
***queryメソッド***
1回きりの処理ならこちらの方が楽です。
ただSQLが長いと読みづらいかな…。

```php
$dbh->query($SQL);
```

\$SQL：クエリを記述

***prepareメソッド***
繰り返し利用することを前提に変数をバインドしたりします。
prepareで準備して、executeで実行します。
queryと違ってexecuteしないと実行されない。

```php
<?php
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);

// 行を挿入します
$name = 'one';
$value = 1;
$stmt->execute();

// パラメータを変更し、別の行を挿入します
$name = 'two';
$value = 2;
$stmt->execute();
?>
```

#出力
結果を出力する方法を指定して、戻り値を取得します。
まず複数の戻り値があると思うので、例ではwhileで全部取得してます。


```php
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
      $results[] = $row;
}
```

#感想
はじめての投稿ですが、こんな薄っぺらい内容にすごく時間かかった…。
でも調べながら記事書いてると、自分が分からないことが分かるのでようやくなんとなく理解できました。
またローカルで動作確認して疑問とか間違いあれば修正しよう。
しかしアウトプットって本当に大切…。

---
参考サイト
@7968 様
　[【PHP超入門】クラス～例外処理～PDOの基礎](https://qiita.com/7968/items/6f089fec8dde676abb5b#%E7%AC%AC3%E7%AB%A0-pdo%E3%81%AE%E5%9F%BA%E7%A4%8E)
@mitsuru793 様
　[PDOを使ったPHPでのデータベース基本操作](https://qiita.com/mitsuru793/items/45b2452284e321c7a5a9)
[公式ドキュメント(PHP Data Objects ¶)](https://www.php.net/manual/ja/refs.database.abstract.php)
論文：AN ANALYSIS OF DEEP NEURAL NETWORK MODELS FOR PRACTICAL APPLICATIONS を読んだときのメモ

# はじめに
AN ANALYSIS OF DEEP NEURAL NETWORK MODELS
FOR PRACTICAL APPLICATIONS を読んだときのメモです。
正確なところは原文をお願いします。<(_ _)>
https://arxiv.org/pdf/1605.07678.pdf

# 論文の概要
* ImageNet等のコンペの目的はaccuracyである
* 一方で、実運用では考えるべき、推論時間は？メモリ使用量は？命令数は？消費電力は？にも着目して、主要CNNについて比較した。

# 論文には書いていないが知っておくべきこと
* AlexNet,VGGは全結合層がとにかく重い。
    * NIN以降、Global Average Poolongにより劇的に改善
    * AlexNetだと、全結合層が全パラメータ数の93%を占める。
    * Kerasでは、VGGも引数一つでGAPにできる

# 比較結果❶accuracy
* 新しめの技法であるResnetとInceptionがよいaccuracyを出している。
* VGGは、精度に対する命令数を圧倒的に要する。（多くのアプリケーションで使われているにも関わらず）
![cnn_01_accuracy.png](https://qiita-image-store.s3.amazonaws.com/0/92368/bb199ee8-341f-5d74-0f9f-7b8269126e77.png)

# 比較結果❷推論時間と消費電力
* VGGが、1枚の推論に0.2秒近くかかっている。
* Alexnetは、バッチサイズを変更すると推論時間が3倍はやくなっている。（AlexNetで支配的なのは全結合層、新しめのCNNで支配的なのは畳み込み層であるため？）
* 消費電力は、多くの場合、バッチサイズと相関がある。
![cnn_02_推論時間と消費電力.png](https://qiita-image-store.s3.amazonaws.com/0/92368/b235af98-7ef1-3f17-2897-55bf4c63c901.png)

# 比較結果❸メモリ使用料
* メモリ使用量は、はじめにモデルそのものがメモリを確保し、あとはバッチサイズに従って増加する
* モデルのサイズが100Mを下回っていようと、確保するメモリのサイズは200Mを下回らない。また、モデルの種類によらずパラメータ数に対する傾きは1.3。
![cnn_03_メモリ使用量.png](https://qiita-image-store.s3.amazonaws.com/0/92368/1bea70aa-1992-88fc-3a1a-d287bb5d3587.png)

# 比較結果❹命令数
* 命令数と推論時間は比例関係にある。（バッチサイズ16では）
* よって、設計時に、リアルタイムアプリケーションや、リソースが限られた環境にて、許容できる推論時間を満たすための命令数を推定することができる。
![cnn_04_命令数.png](https://qiita-image-store.s3.amazonaws.com/0/92368/6af12693-2274-eec4-908b-bea8901bdf1f.png)

# 比較結果❺命令数と消費電力
* モデルの種類によって消費電力が大きく変わるということはなかった
* バッテリー等に不安があるのであれば、アプリケーションの要件を満たす範囲で処理時間が遅いモデルを選択すればよい
![cnn_05_命令数と消費電力.png](https://qiita-image-store.s3.amazonaws.com/0/92368/49033c66-68e2-bc0a-9046-2387954f5112.png)

# 比較結果❻accuracyとスループット
* 予測精度とスピードはトレードオフ
![cnn_06_accuracyとスループット.png](https://qiita-image-store.s3.amazonaws.com/0/92368/5c6285dd-a6ad-9681-8219-145750e39496.png)

# 比較結果❼パラメータ数
* VGGはAlexNetより精度はよいが、パラメータあたりの精度は劣る
* 筆者のENetが最もパラメータあたりの精度密度があり、優れている？
![cnn_07_パラメータ数.png](https://qiita-image-store.s3.amazonaws.com/0/92368/5b52f4ca-acf4-c14b-934a-278f70596a0c.png)

# 結論
* 予測精度と推論時間はhyperbolic relationship。わずかでも予測精度を上げようとすると、computational timeが大きくかかる。
* モデルの命令数から、推論時間を推定できる。
* energy constraintが accuracy and model complexity, in terms of operations countsの上限を決めてしまう。
* ENetが、最もパラメータあたりの情報量が多い。AlexNetの13倍。VGG-19の24倍。
PHPの新元号対応についてのスライドの裏話 in PHPerKaigi 2019  #PHPerKaigi #新元号  #32FF

![589AB509-1E77-497A-938D-7B8DF15C80C9.png](https://qiita-image-store.s3.amazonaws.com/0/77441/ef4dd550-9abd-90bd-98ca-933ea57f85f6.png)
### 概要
PHPerKaigi 2019のPHP勉強会で登壇しました。
その際、PHPerチャンレンジのトークンを入れることになり、画面を一つ追加したのですが、実は追加した画面にはJavaScriptが入っておりました。（Googleスライドで作ってあります）
1分ごとにトリガーが発動し右下の日時がカウントダウンしております。
そう、あの日時はフェイクじゃないです。
ちゃんと発表予定日時の「㍻３１年4月1日 am 11:30」に向けてカウントダウンしておりました。
PHPネタじゃないので、Qiitaにこっそり公開しておきます。
### ソースコードの補足
ソースコードの"テキストBOXのID"は以下のURLからスライドIDを入れると取得できます。
https://developers.google.com/slides/reference/rest/v1/presentations/get?authuser=1&hl=ja
"スライドID"は、URLのEDITの前にあるランダムな文字列です。

presentationIdに"スライドID"を入れて、EXECUTEを押してパーミッション許可して取得します。
pageElements配下のobjectIdが"テキストBOXのID"になります。


### ソースコード
```JavaScript:元号.gs
// テキストボックスの取得
var presentation = SlidesApp.openById("スライドID");
var slide = presentation.getSlides()[10];
var pageElements = slide.getPageElements();
var textBox = pageElements.filter(function(e){return e.getObjectId() == "テキストBOXのID"})[0];
var text = textBox.asShape().getText();

// 比較日時の設定
var xday = new Date(2019, 4-1, 1, 11, 30, 0);

//main処理
function main() {
  text.clear();
  var now = new Date();
  var period = xday.getTime() - now.getTime();
  // 終了
  if (period<0) {
    delTrigger(); // トリガー削除
    return "新元号発表！";
  }
  // 日をを取得
  var cDay = Math.floor(period / (1000 * 60 * 60 * 24));
  period -= (cDay * (1000 * 60 * 60 * 24));

  // 時間を取得
  var cHour = Math.floor(period / (1000 * 60 * 60));
  period -= (cHour * (1000 * 60 * 60));

  // 分を取得
  var cMinute = Math.floor(period / (1000 * 60));

  var msg = cDay + ":" + cHour + ":" + cMinute;
  text.appendText(msg);
}

// トリガー削除
function delTrigger() {
  var triggers = ScriptApp.getProjectTriggers();
  for(var i=0; i < triggers.length; i++) {
    ScriptApp.deleteTrigger(triggers[i]);
  }
}
```
Golangでビルド時にバージョン情報を埋め込む(2019.03)

Golangでビルド時に`ldflag`オプションをつけると、パッケージ内の変数に任意の情報を埋め込むことができるが、ちょっとハマったのでメモ。

以下の`go1.4`の記事だと書き方が現在のバージョンとは異なるみたいなので、2019/03現在の`go1.12`で書いてみたという位置づけです。
[Go言語: ビルド時にバージョン情報を埋め込みたい](https://qiita.com/suin/items/d643a0ccb6270e8e3734)

# 前提

`go version go1.12.1 darwin/amd64`

こんな感じの変数を用意。

```go:main.go
package main

import (
	"fmt"
)

var version string
var revision string

func main() {
    fmt.Printf("version: %s-%s\n", version, revision)
}
```

# よくある書き方
main packageのversionという変数に値を埋め込む
変数と値は`=`でつなげる

```
go build -ldflags "-X main.version=v1.0.0"
```

# 複数の変数を埋め込む

```
go build -ldflags "-X main.version=v1.0.0 -X main.revision=$(git rev-parse --short HEAD)"
```

# mainではないパッケージの変数に埋め込む
`main.version`ではなく`$GOPATH/src`からのパスを指定する。
パスなのでパッケージ名ではなくディレクトリ名を指定する。

```
go build -ldflags "-X github.com/irotoris/jobkickqd/cmd.version=v1.0.0"
```

こんな感じで`github.com/spf13/cobra`使ったコマンドにビルド情報を埋め込みたかったんです。

```go:go/src/github.com/irotoris/jobkickqd/cmd/version.go
package cmd

import (
	"fmt"
	"github.com/spf13/cobra"
)

var version string
var revision string

// version command shows version and build revision
var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Show version and build revision.",
	Long:  `Show version and build revision.`,
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Printf("version: %s-%s\n", version, revision)
	},
}

func init() {
	rootCmd.AddCommand(versionCmd)
}
```
# 埋め込む変数に空白を入れる
`-X`の文字列を`''`で囲ってあげる。そうしないとオプションのパースが失敗してエラーになる。

```
go build -ldflags "-X 'main.version=v1.0.0 rc'"
```
AWS（EC2）本番環境へのデプロイ手順をついつい忘れがちなのでメモ

AWS（EC2）本番環境へのデプロイはそんなに頻繁に行う作業ではないので、手順をついつい忘れがち。。。ということで、いつでも見返せるように手順をまとめました。

AWS（EC2）の環境構築については、こちらの記事を参照
[Rails + Nginx + Unicorn + postgreSQL を使ったAWS（EC2）の環境構築 -Rails起動してHello Worldを表示させる-](https://chopesu.com/aws/rails-nginx-unicorn-postgresql/)

##前提
・開発環境：VirtualBox
・本番環境：AWS（EC2）
・仕様サーバー：Nginx、Unicorn
・ローカルリポジトリのブランチで開発したソースをGitHubにプッシュし、本番環境ではorigin/masterをプルする、という方法を取る

## 手順① 現状のブランチを確認し、変更内容をステージング環境にaddする

```shell
 git branch -a
```

これで、ローカルリポジトリのブランチ一覧と現在どのブランチにいるのか確認

```shell
 git add .
```
上記コマンドの「.」は変更があった全てのファイルを指している。例えば、ある特定のファイルだけをステージング環境にaddしたければ、「.」の部分をaddしたいファイル名に変更すればOK！

##手順② ステージング環境にaddされたファイルをリポートリポジトリにコミットする

```shell
git commit -m "コミットメッセージ"
```
コミットが出来たら、コミットできたかを下記コマンドで確認

```shell
git log
```

##手順③ GitHubにプッシュし、ブランチをmasterブランチにマージする

```shell
git push origin ブランチ名
```
プッシュしたら、GitHubのページに遷移してプルリクエスト。プルリクエスト後のマージは、個人開発をしているのか、チーム開発をしているのか、等状況に応じて変わるので、臨機応変に対応

##手順④ AWSにSSHでログインし、Unicornのプロセスを停止させる

```shell
 kill -QUIT `cat tmp/pids/unicorn.pid` #pidはプロセスIDのこと
```

###なぜ、Unicornのプロセスを停止させるのか？
vagrantの開発環境であれば、Webブラウザをリロードすれば、変更内容が即時反映されるが、本番環境では変更されたアプリケーションの内容は即時反映されないので、一度プロセスを停止させた状態で、変更内容をGitHubからプルし、再度Unicornを起動させる必要がある。

###production（本番）環境にすぐに変更が反映されない理由

それは、development環境とproduction環境に以下の違いがあるから

■development：キャッシュが無効
■production：キャッシュが有効 

http://railsdoc.com/rails_base#Rails%E3%81%AE%E5%AE%9F%E8%A1%8C%E7%92%B0%E5%A2%83

####キャッシュとは？
リクエスト・レスポンスのサイクルの中で生成されたコンテンツを保存しておき、次回同じようなリクエストが発生したときのレスポンスでそのコンテンツを再利用すること。単一サーバー、単一データベースのWebサイトでも数千ユーザーの同時接続による負荷に耐えられるようになる。https://railsguides.jp/caching_with_rails.html
キャッシュにもコンテンツキャッシュやクエリキャッシュなど、いくつか種類があるが、今回変更内容がすぐに反映されない原因を作っているのは、静的ページ等のコンテンツをキャッシュしておく、コンテンツキャッシュ

###production（本番）環境にすぐに変更が反映されない理由（続き）

■development環境はキャッシュが無効だから、Railsアプリケーションに変更を加えてreloadし、再度リクエストを送ると即時反映される。

■production環境はキャッシュが有効だから、Railsアプリケーションに変更を加えてreloadし、再度リクエストを送っても変更前のアプリケーションのコンテンツ内容がキャッシュにより再利用されるので、変更がすぐに反映されない。変更を反映させる場合は一度キャッシュによるコンテンツの再利用を止める必要があるので、Unicornを一度落として、再起動させる必要が生じる。

##手順⑤ git pullする

```shell
git pull origin master
```

##手順⑥ bundle installする

```shell
bundle install
```

##手順⑦ production環境でrake db:migrateする

```shell
rake db:migrate RAILS_ENV=production
```
ローカル環境では、「$ rake db:migrate」しか入力しないかもしれないが、「rake db:migrate」はmigrateする環境指定の記述を省略しており、下記のようにデフォルトでdevelopment環境が指定されていることは頭の片隅に置いておいた方が良い

```shell

rake db:migrate RAILS_ENV=development
```

##手順⑧ production環境でプリコンパイルする

```shell
bundle exec rake assets:precompile RAILS_ENV=production
```

プリコンパイルとは、アセットパイプラインというJavaScriptやCSSのアセットを最小化または圧縮して連結するためのフレームワークで行われる一連の処理を指すが、詳細は下記の記事を参照
https://numb86-tech.hatenablog.com/entry/2018/11/10/002439https://railsguides.jp/asset_pipeline.html

##手順⑨ Unicornを再度、起動させる

```shell
unicorn_rails -c /var/www/rails/アプリケーション名/config/unicorn.conf.rb -D -E production
```

これでUnicornが起動し、git pullされたアプリケーションとUnicornが接続されてデプロイが完了！

AWS（EC2）の環境構築については、こちらの記事を参照
[Rails + Nginx + Unicorn + postgreSQL を使ったAWS（EC2）の環境構築 -Rails起動してHello Worldを表示させる-](https://chopesu.com/aws/rails-nginx-unicorn-postgresql/)
GameObjectの表示非表示

GameObjectの表示・非表示についてのメモ

```ruby:C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ClaccName : MonoBehaviour {

    GameObject obj;

    // Use this for initialization
    void Start () {
        // シーンのゲームオブジェクトを取得する
        obj = GameObject.Find("Object");
    }

	  // Update is called once per frame
	  void Update () {
        // ゲームオブジェクトが表示されているかどうかのステータスを取得
        bool isActive;
        isActive = obj.activeSelf;

        // ゲームオブジェクトを表示させる
        obj.SetActive(true);

        // ゲームオブジェクトを非表示にする
        obj.SetActive(false);
    }
}
```
Spring Batch 4.1.x - Reference Documentation読んで訳した


[Spring Batch - Reference Documentation - Version 4.1.x](https://docs.spring.io/spring-batch/4.1.x/reference/html/index.html)を読んで訳した。

少し前にSpring Batch熱が再燃したため、とりあえずリファレンス読むことにした。ついでに勝手に訳す事にもした。以下はその原文と俺の勝手訳の一覧。

|原文|俺|
|:-----------|:-----------|
|[Spring Batch Introduction](https://docs.spring.io/spring-batch/4.1.x/reference/html/spring-batch-intro.html#spring-batch-intro)|http://kagamihoge.hatenablog.com/entry/2019/03/15/224302|
|[What’s new in Spring Batch 4.1](https://docs.spring.io/spring-batch/4.1.x/reference/html/whatsnew.html#whatsNew)|http://kagamihoge.hatenablog.com/entry/2019/03/16/090423|
|[The Domain Language of Batch](https://docs.spring.io/spring-batch/4.1.x/reference/html/domain.html#domainLanguageOfBatch)|http://kagamihoge.hatenablog.com/entry/2019/03/16/163619|
|[Configuring and Running a Job](https://docs.spring.io/spring-batch/4.1.x/reference/html/job.html#configureJob)|http://kagamihoge.hatenablog.com/entry/2019/03/16/163929|
|[Configuring a Step](https://docs.spring.io/spring-batch/4.1.x/reference/html/step.html#configureStep)|http://kagamihoge.hatenablog.com/entry/2019/03/16/164117|
|[ItemReaders and ItemWriters](https://docs.spring.io/spring-batch/4.1.x/reference/html/readersAndWriters.html#readersAndWriters)|http://kagamihoge.hatenablog.com/entry/2019/03/17/183309 start-1.6<br />http://kagamihoge.hatenablog.com/entry/2019/03/17/183309 1.7-end|
|[Scaling and Parallel Processing](https://docs.spring.io/spring-batch/4.1.x/reference/html/scalability.html#scalability)|http://kagamihoge.hatenablog.com/entry/2019/03/17/183309|
|[Repeat](https://docs.spring.io/spring-batch/4.1.x/reference/html/repeat.html#repeat)|http://kagamihoge.hatenablog.com/entry/2019/03/17/183309|
|[Retry](https://docs.spring.io/spring-batch/4.1.x/reference/html/retry.html#retry)|http://kagamihoge.hatenablog.com/entry/2019/03/19/215439|
|[Unit Testing](https://docs.spring.io/spring-batch/4.1.x/reference/html/testing.html#testing)|http://kagamihoge.hatenablog.com/entry/2019/03/20/212542|
|[Common Patterns](https://docs.spring.io/spring-batch/4.1.x/reference/html/common-patterns.html#commonPatterns)|http://kagamihoge.hatenablog.com/entry/2019/03/23/203620|
|[JSR-352 Support](https://docs.spring.io/spring-batch/4.1.x/reference/html/jsr-352.html#jsr-352)|http://kagamihoge.hatenablog.com/entry/2019/03/27/184614|
|[Spring Batch Integration](https://docs.spring.io/spring-batch/4.1.x/reference/html/spring-batch-integration.html#springBatchIntegration)|http://kagamihoge.hatenablog.com/entry/2019/03/31/223015|



なお自己学習が第一の目的なので、推敲は全くと言っていいほどしていません。情報源として使用する場合は必ずしも正確な訳ではない可能性がある点に注意していただくようお願いします。特に、アンマリ興味がないとこ（JSR-352 Supportとか）や、ロクに使ったことない機能のとこ（Remote Chunking/Remote Partitioning）は、間違ってる可能性が更に高いので、参考資料として使用する場合は注意してください。



> Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically.
> https://docs.spring.io/spring-batch/4.1.x/reference/html/index.html から抜粋
Firebase FunctionsでSlack botを作ってみる

## モチベーション
Firestoreに保存してある誕生日情報をもとに、おめでとう通知をSlackにさせたかったので簡単なSlack botをfunctionsで作ってみました。
公式のnode.js用のSlackクライアントがnpmに転がっているのですが、使われている記事をみたことがなかったので試しに使ってみました。
## 必要なもののインストール
```shell:yarn
yarn add @slack/client
```
Functionsでfirebase adminを動かすために、認証情報が必要になるので、functionsの環境変数に設定しておくか、jsonファイルをfirebaseのコンソールからダウンロードしてプロジェクトに配置してください。
## コード
```typescript:index.ts
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
import * as serviceAccountKey from '../serviceAccountKey.json';
import { WebClient } from '@slack/client';

admin.initializeApp({credential: admin.credential.cert(serviceAccountKey as any)});

const slack = new WebClient(functions.config().slack.api_key);

interface IUser {
    birthday: Date;
    name: string;
}

const notifySlack = async (users: IUser[]) => {
    let names = '';

    if (users.length === 1) {
        users.map(user => names += user.name + ', ');
    } else {
        names = users[0].name;
    }
    
    const res = await slack.chat.postMessage(
        {
            channel: functions.config().slack.channel,
            text: "今日は" + names + "が誕生日！",
        }
    )

    console.log(res);
}

const aggregateUsers = (snapshot: FirebaseFirestore.QuerySnapshot): IUser[] => {
    const today = new Date();
    const users: IUser[] = new Array();

    snapshot.docs.forEach(doc => {
        const birthday: Date = doc.data().birthday.toDate();
        if(birthday.getDate() === today.getDate() && birthday.getMonth() === today.getMonth()){
            users.push(
                {
                    birthday: doc.data().birthday,
                    name: doc.id,
                }
            );
        };
    });

    return users;
}

export const checkBirthday = functions.https.onRequest((req, resp) => {
    const ref = admin.firestore().collection('users');
    
    ref.get()
    .then(snapshot => {
        const users = aggregateUsers(snapshot);
        
        users.length === 0 ?
            resp.send('ok')
            :
            notifySlack(users)
                .then(() => resp.send('ok'))
                .catch((e) => resp.send('error:' + e))
    })
    .catch((e) => {
        resp.send('error:' + e);
    });
});
```
上記のコードでデプロイして、関数を発火させるためのURLを発行します。
## cronの設定
毎日、誕生日に該当する人がいないかチェックしたいので、[cron-job.org](https://cron-job.org)に発行したURLを設定してcronを回します。
ちなみに、slack通知させることは外部アクセスにあたるのでfirebaseの無料枠ではできません。
firebaseのプランはBlazeプランにしましょう。
新米SEのExcel Tips ③

2018年度も今日が最後ですが、今回はVBAの初歩の初歩を紹介します。
業務用に簡単なマクロを作ってみたい、となっても一から調べるのは面倒なので自分用のメモも兼ねています。

セルに何か書き込んだりするだけならマクロを記録する機能で十分ですが、
開発環境を作らずに、書けてすぐ動かしてみることができるのがVBAの魅力でもあると思うので。

---
###・Activate

指定したシートをアクティベート(選択)する。

```vba:例1
Worksheets("シートA").Activate
```

Worksheetsというプロパティにシート名を渡し、「.Activate」でそのシートを選択することができる。
次に紹介するSelectメソッドと一緒に使うことが多い。
ActivateしないとSelectしても画面がそのシートに切り替わらない。

###・Select
指定したセルを選択する。

```vba:例2
Cells("A1").Select
```

説明不要の一目瞭然さ。
ここではCellsでセルを指定していますが、「Range」でもセルを指定できる。
上の場合のような単一セルを選択したい場合はCellsで十分だが、複数セルや範囲で選択したいときはRangeが適している。
詳しくはこちらの記事をどうぞ ⇒ [VBAの高速化（RangeとCellsの使い分け）](https://vbabeginner.net/vba%E3%81%AE%E9%AB%98%E9%80%9F%E5%8C%96%EF%BC%88range%E3%81%A8cells%E3%81%AE%E4%BD%BF%E3%81%84%E5%88%86%E3%81%91%EF%BC%89/)

###・Format
日付型をフォーマットする。

```vba:例3
today = Date
Format(today , "yyyy月mm月dd日（aaa）") 
```

JavaでいうSimpleDateFormat。
第一引数にDate型変数を、第二引数にフォーマットしたい形式を指定する。
独断で選んだよく使いそうな設定は以下。

|書式|説明|例|
|---|---|---|
|yyyy|西暦年の4桁の数値|2019|
|mm|月(1桁の場合、先頭に0を付ける)| 03|
|dd|日付1桁の場合、先頭に0を付ける| 31|
|aaa|日本語表記の曜日(漢字1文字)|日|
|aaaa|日本語表記の曜日(〇曜日)|日曜日 |
|y|1年のうちで何日目かを表す数値| 90|
|w|曜日を表す数値|1(土曜日は7)|
|oooo|日本語表記の月の名前| 3月|
|ggg|年号|平成|

vbaは開発されてから20年近くアップデートされていない言語なので、明日発表の新元号は恐らく使えない。
WindowsアップデートでExcelのアプデも降ってくればなんとかなる？

###・Open
指定したファイルを開く。
Open ⇒ Print ⇒ Close の流れで説明する。

```vba:例4-①
Open C:\sample.txt For Output As #1
```
JavaでいうFileReaderやFileWriter。
Openの
Forの次にそのファイルを開いて何をしたいかを記述する。

| キーワード | モード     | 処理     |
|------------|------------|----------|
| Input      | 入力モード | 読み込み |
| Output     | 出力モード | 書き込み |
| Append     | 追加モード | 書き込み |

Asにはファイル番号をつけるのだが、ファイルを閉じる(後述)場合に必要なので「#(数字)」を指定する。

###・Print
Openで開いているファイルに書き込みを行う。

```vba:例4-②
Open C:\sample.txt For Output As #1
Print #1, Range("A1:E1")
```

\#1でCドライブ直下にあるsample.txtを指定しているので、
このテキストファイルにRangeで範囲選択したセルに入っている文字が書き込まれる。
(追記して上書きではないので注意)

###・Close
Openで開いているファイルを閉じて処理を終了する。

```vba:例4-③
Open C:\sample.txt For Output As #1
Print #1, Range("A1:E1")
Close #1
```

この場合はJavaでいうclose()。
初めのうちはピンとこなかったが、vbaに限らず、
ファイル操作を行う際はストリームに読み込んでいる状態を終了するのがプログラミングをする上で必須である。

上記のCloseはあくまでステートメントだが、
メソッドのCloseはExcel自体に使うことができる。

```vba:例5
Workbooks("ブックC".xlsx).Close
```

もちろん、Workbooksプロパティで指定したブック(そのマクロが動いているブックでなくても可)を閉じる動きになる。

---
変数の型についてやIf、Forなどの他のステートメントはわかりやすいページがいくらでもありますので割愛させてください。

元号を取得する「ggg」、何かしらのアップデートが来ない限り「平成」が永遠に続くのではないでしょうか。。
ちなみにExcel(というよりOffice？)は、新しい関数や機能が追加されても、買い切りのものではWindowsアップデートで降ってくることはありません。
[Office365](https://www.office.com/?omkt=ja-jp)なら常に最新の機能を使えるとのことです。

今年度は3回しか投稿できませんでしたが、
普段は業務中でもQiitaの先達にお世話になることが多いので、せめて自分と同じ新米エンジニアの助けになれば幸いです。
Windows10へのPython OpenCVのインストール

# OpenCVとは
　**Open Source Computer Vision Library** の略です。インテル社が開発した画像処理および画像解析のオープンソースのライブラリです。ここではPython用のライブラリをwindows10 にインストールする方法をメモ書きします。OpenCVライブラリはPythonで画像処理の機械学習機能を実装するときによく用いられるようです。

# 何故にいまさらWindows10？

　小学生、中学生、高校生のプログラマ、IT系エンジニアを目指す方には親のPCを使ってプログラミングを行う。そういうパターンは非常に多いと思います。ITエンジニアの理想であるmac OS系のPCは高値の花という場合も少なくないと私は考えています。

　そこで、あえてポピュラーで親世代が一般的に使っているであろうwindows10 PCへのインストールをメモってみました。

# Anacondaのインストール
1. Webブラウザで、　[Anacondaのインストールサイト](https://www.anaconda.com/distribution/#download-section)　にアクセスします
2. 上記の [Windows](https://www.anaconda.com/distribution/#windows)　をクリックします
3. **Anaconda 2018.12 for Windows Installer** のページが表示されます
![anaconda2018.12forwindowsinstaller.PNG](https://qiita-image-store.s3.amazonaws.com/0/124810/7408a204-c414-14d5-2008-18c1b58ad523.png)
3. **Python 3.7 version** の下の [Download](https://repo.anaconda.com/archive/Anaconda3-2018.12-Windows-x86_64.exe)　ボタンをクリックします
4. ダウンロードされた **Anaconda3-2018.12-Windows-x86_64.exe** を実行します
5. インストールダイアログが次々表示されますが全てデフォルトのままで[ Next > ]ボタンをクリックし続けてインストールして問題ないと思います。
![welcometoanaconda.PNG](https://qiita-image-store.s3.amazonaws.com/0/124810/79bb99a3-71f8-77b3-dd28-94d38773b131.png)

# Anaconda Promptを起動
1. スタートメニュー　⇒　``ana``　と入力します
2. **Anaconda Prompt**　アイコンが表示されます
![anacondaprompt.png](https://qiita-image-store.s3.amazonaws.com/0/124810/ffa41e3c-849d-adea-e237-b13181db18c9.png)
3. 右マウスボタンでコンテキストメニューを表示します
4. **管理者として実行** をクリックします

- **管理者として実行**しないと権限違反でインストールできませんので、注意が必要です。

# Open CVのインストール
1. Anaconda Promptで　``conda install -c conda-forge opencv`` と入力します
2. ``Proceed ([y]/n)?`` と聞かれるので、"y" を入力します

```shell:AnacondaPrompt
(base) C:\WINDOWS\system32>conda install -c conda-forge opencv
Solving environment: done

==> WARNING: A newer version of conda exists. <==
  current version: 4.5.12
  latest version: 4.6.8

Please update conda by running

    $ conda update -n base -c defaults conda

## Package Plan ##

  environment location: C:\ProgramData\Anaconda3

  added / updated specs:
    - opencv

The following NEW packages will be INSTALLED:

    libopencv: 3.4.1-h875b8b8_3
    opencv:    3.4.1-py37h6fd60c2_3
    py-opencv: 3.4.1-py37h1b0d24d_3

The following packages will be UPDATED:

    conda:     4.5.12-py37_0        --> 4.6.8-py37_0 conda-forge

Proceed ([y]/n)? y

Preparing transaction: done
Verifying transaction: done
Executing transaction: done
```

# OpenCVのモジュールをインストール

1. Anaconda Promptで　``python`` と入力し、pythonを起動します
2. Anaconda Promptで　``import cv2`` と入力し、OpenCVのモジュールをインストールします
3. 何も表示されず、　　``>>>`` が返ってきたら、インストール成功です。

```shell:AnacondaPrompt
(base) C:\WINDOWS\system32>python
Python 3.7.1 (default, Dec 10 2018, 22:54:23) [MSC v.1915 64 bit (AMD64)] :: Anaconda, Inc. on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import cv2
>>>
```
Pandas ピボットテーブル、pivot_table についてのメモ (作成中)

# 2つの使用方法がある

1. pandas.pivot_table()
2. df.pivot_table()

この記事は1についてのみ書いています。

# オプション

|引数|役割|値|値の例|
|:--|:--|:--|:--|
|index=|||
|values=|集計する列||
|margins=|集計行を付加するか否か|Bool値||
|margins_name=|集計行の名前||"Total"|
|aggfunc=|集計の方法|初期値numpy.mean|np.sum(ここでは関数に括弧不要)|
|dropna=|欠損値を除外するか否か|Bool値(初期値True)||
|fill_value=|欠損値を穴埋めする際の代わりの値||0|

           
# 例

```python:例

# pivot
df_piv = pd.pivot_table(df_out ,
                        index=["製品品番",'品名',"品目","部品"] ,
                        values=["単価","総生産数",'お金'],
                        margins=True ,
                        margins_name="Total" ,
                        aggfunc=np.sum,
                        dropna=False,
                        fill_value = 0)
```
yamlの書き方

### yamlの特徴
- インデントを使って、データの階層構造を表現する
    - そのため、インデントが少しでもずれるとうまく実行されなかったりするので、ちゃんとしたエディタを使う必要がある
- XMLのような終了タグが必要なく、シンプル
- データを配列、ハッシュ、スカラーの3つの組み合わせで表現できる

### データの表現方法
#### 配列
```ruby:yaml
- aaa
- bbb
- ccc
```
#### ハッシュ
```ruby:yaml
A: aaa
B: bbb
C: ccc
```

#### スカラー
- 配列やハッシュ以外の数値や文字列のデータ
- 以下を自動的に判別し、それ以外を文字列と認識する(文字列をシングルクオートなどで囲む必要がない)
    - 整数
    - 浮動小数点
    - 真偽値
    - Null型
    - 日付
    - タイムスタンプ

### 2つのスタイル
- ブロックスタイルとフロースタイルがある
- 通常はブロックスタイルを使う

#### 配列の場合
- ブロックスタイル

```ruby:yaml
- aaa
- bbb
- ccc
```

- フロースタイル

```ruby:yaml
[aaa, bbb, ccc]
```

#### ハッシュの場合
- ブロックスタイル

```ruby:yaml
A: aaa
B: bbb
C: ccc
```

- フロースタイル

```ruby:yaml
{A: aaa, B: bbb, C: ccc}
```

### 少し複雑なyaml
#### 配列を持つハッシュ

- フロースタイル

```ruby:yaml
XXX: [aaa, bbb, ccc]
```

- ブロックスタイル

```ruby:yaml
XXX:
  - aaa
  - bbb
  - ccc
```

#### ハッシュを持つ配列

- フロースタイル

```ruby:yaml
[{id: 1, name: Tom}, {id:2, name: Kate}]
```

- ブロックスタイル

```ruby:yaml
-
  id: 1
  name: Tom
-
  id: 2
  name: Kate
```
モバイルブラウザの height: 100vh の話。

`height: 100vh;`または`min-height:100vh;`したい場面というのは多いですがモバイルブラウザでは想定した動きをしてくれません。

## 原因: なぜ`height: 100vh;`が効かないのか。

多くのモバイルブラウザでは

* 描画領域が固定ではない(スクロールなどで可変する)
* vhの基準値は再計算されない
* 描画領域の最大値の高さからvhの基準値を計算する

そのため`100vh = 現在の画面の高さ`とは限らないのです。


## 解決策: `resize`に合わせてpx指定する

cssは`100vh`で高さ指定をして`resize`をトリガーに高さを変更します。サンプルコードは`React`です。

```ContainerWithResize.js
class ContainerWithResize extends React.Component {
  state = { appHeight: 0 };
  componentDidMount = () => {
    this.setState({ appHeight: window.innerHeight });
    window.addEventListener('resize', () => {
      this.setState({ appHeight: window.innerHeight });
    });
  };
  componentWillUnmount = () => window.removeEventListener('resize');
  render() {
    const { appHeight } = ;
    return (
      <Container appHeight={this.state.appHeight}>
        {this.props.children} 
      </Container>
    );
  }
}

export default ContainerWithResize;

const Container = styled.div`
  min-height: ${props => (props.appHeight === 0 ? '100vh' : `${props.appHeight}px`)};
`;
```
React Native+Firebaseのおかげで1週間で17歳のCEOがAndroidアプリをリリースできた話



![メイン](https://qiita-image-store.s3.amazonaws.com/0/135482/9d679c09-f27f-adb9-618c-bb262dbcde2b.png)
)

##経緯
元々仮想通貨系のサービスをやるべく会社を創業したものの開発期間がかかる為かVCにあまりよく受け止められない為急遽、はてブのスマホオプティマイズ版を作ることに、資金調達と事も考えると早くリリースしたいそこで僕自身Node.jsばっかり最近書いている人間であり、クロスプラットフォームに魅力を感じReact Nativeを使うことに。元々web developerだからAPI自分で作りたかったが何しろ時間がない、リアルタイムの為のWebSocketサーバー立てるのコストかかるからヤダということでFirebaseを使うことにしました。

##使ったもの
Firestore
React Native
React Native Elements
React Navigation

##機能

###Twitterのようなフォロー機能

stateが本当に良かったです。webならajaxだけどstateはすごいシンプルで感激しました

![Screenshot_1553720260.png](https://qiita-image-store.s3.amazonaws.com/0/135482/fc53b136-345f-cfc1-d6d7-8c53ba0f4b67.png)


###Auth系
標準でメール用意してくれるの本当にありがたいです。

###このアプリの醍醐味の自動でブックマークしたページのスクショが追加される機能

![Screenshot_1553721460.png](https://qiita-image-store.s3.amazonaws.com/0/135482/a6f75b45-ff6b-de5e-4bb5-999151d516e4.png)

Firebase Functions+puppeteer(Headless Browserテストに使われる軽量ブラウザらしい)で実装しました。ただ、これが実は本当に**酷い**。というのもAWSのlambdaと比べて超鈍いです。デプロイも鈍いし、実行環境も鈍いです。ただ、triggerをfirestoreにブックマークが追加されたタイミングとしているので使わざるを得ない為、我慢して使ってます。


##そういえばなんでブックマークアプリ？？
はてブがTech系だった時のことを懐かしんでいる人を見たり、はてブのアプリの評判が悪いのを見て
ワンタップでブックマークできて自動で何ブックマークしたか一目瞭然のブックマークSNS作って本当に興味ある人だけと情報共有したらいいのではと思い今時ブックマークアプリ作りました！
現状AndroidしかApp Storeにリストするまで時間がかかるので対応できてないのが心残りですが

[興味ある人はダウンロードお願いします](https://play.google.com/store/apps/details?id=xyz.transx.translog)
go modでモジュール管理、はじめました


# What’s "go mod" ?

ざっくりと

- モジュール管理ができるやつだよー
- go1.12から使えるよー

というもの

# Why need "go mod" ?

- 外部パッケージを使ってる時、バージョンの管理簡単にできるよー
- 今まではvenderディレクトリで管理するのが主流っぽいよー
- 私の場合はdockerを利用してCIするときに、go get全部書くのが面倒だったから入れたよー

# How to use?

0. `GO111MODULE=on` を設定しておくよー (v1.12ではこれしないと上手く動かないことあるよー)
1. 開発してる環境で `go mod init プロジェクトパス` を叩くとmodファイルつくるよー
2. パッケージを管理したいgoファイルをgo build するよー
3. go.modに使ってるモジュールが自動で入力されるよー
4. バージョン上げたければ go getするといいよー

# Let's Try!

例えば、↓みたいな簡単な「gin」を用いたクライアントサーバーを立ち上げるパッケージがあったとします

```
package main

import "github.com/gin-gonic/gin"

func main() {
	r := gin.Default()
	r.GET("/ping", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "pong",
		})
	})
	r.Run() // listen and serve on 0.0.0.0:8080
}
```

ここで使ってるパッケージは `gin-gonic/gin` ですねー
とすると、 `gin-gonic/gin` のバージョンをmodで管理できると楽ですよねー

まずは modファイルを作っていきますー

```
$ go mod init main
go: creating new go.mod: module main

$ ls
go.mod  main.go
```

プロジェクト名は本当は$GOPATHでのパスを設定するのが良さそうですよー
でも今回は動作テストのために適当な名前をつけてますー

中身を確認すると

```
$ cat go.mod 
module main

go 1.12
```

こんな感じになってますー

次はbuildしたあとに中身を確認しますよー

```
$ cat go.mod 
module main

go 1.12

require (
        github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 // indirect
        github.com/gin-gonic/gin v1.3.0
        github.com/golang/protobuf v1.3.1 // indirect
        github.com/mattn/go-isatty v0.0.7 // indirect
        github.com/ugorji/go/codec v0.0.0-20190320090025-2dc34c0b8780 // indirect
        gopkg.in/go-playground/validator.v8 v8.18.2 // indirect
        gopkg.in/yaml.v2 v2.2.2 // indirect
)
```

なんかすごく色々増えてることがわかりますねー
gin-gonic/gin でサーバーを立ち上げる時に利用しているパッケージをまとめて管理してくれてるようですねー

ちなみに、↑のように色々パッケージが書かれているmodファイルがあれば、go buildするときに勝手に足りないパッケージをDLしてくれますよー
firebase authentication+nuxtでtwitterログイン、ログアウト機能をつくる

# やりたいこと

* nuxt.js
* firebase authentication

の構成でログイン、ログアウト機能をつくる

# バージョン

* Nuxt.js v2.10.0

# 全体設計

* firebaseauthにsignInWithRedirectを使ってログイン
* onAuthStateChangedオブザーバーで状態の変化を察知
* vuexにstateを保存
* 再度訪問時にvuexのstateを参照
* ログアウトはfirebase.auth().signOut()で行い、vuexのstateも上書き

signInWithRedirect
https://firebase.google.com/docs/reference/js/firebase.auth.Auth.html#signinwithredirect

onAuthStateChangedオブザーバー
https://firebase.google.com/docs/auth/web/manage-users?hl=ja

# firebase側の設定

https://qiita.com/sin_tanaka/items/ea149a33bd9e4b388241#%E3%83%90%E3%83%83%E3%82%AF%E3%82%A8%E3%83%B3%E3%83%89%E9%83%A8%E3%82%92%E5%AE%9F%E8%A3%85%E3%81%99%E3%82%8B

この記事がわかりやすかったです。

# vuex、nuxtの実装

## ログイン機能の動き

![a.jpg](https://qiita-image-store.s3.amazonaws.com/0/193389/2da2ad1e-af38-e3df-c27a-ff27619c25b2.jpeg)

＊このときはisLoginをcomponentごとに定義していたが各componentで書くの面倒なのでstoreに集約した。毎回storeに聞くようにすることでDRYな設計にした。

### ログインボタンを押す

signInWithRedirectでfirebaseで用意されたログインページにいけるのでそこでログイン

```javascript:default.vue
<template>
    <button @click="googleLogin">googleでログイン</button>
</template>

<script>
import firebase from '@/plugins/firebase'
export default {
  methods: {
    googleLogin: function () {
      firebase.auth().signInWithRedirect(new firebase.auth.TwitterAuthProvider())
    }
}
</script>
```

### onAuthStateChangedでログインしたことを察知してvuexのstateを更新

vuexのmutationについて
https://vuex.vuejs.org/ja/guide/mutations.html

このドキュメントに書いてあるようにvuexのstateはmutationにコミットすることで行います。commitの第一引数がmustationのハンドラを起動させるもので第二引数が追加の引数になります。今回はuserのnameなどを第二引数で渡しています。で、第一引数でloginを動かしている。もしuserがnullだったらログアウトしていると判断してlogoutを動かす。

```javascript:default.vue

  mounted: function () {
    firebase.auth().onAuthStateChanged(user => {
      var user = firebase.auth().currentUser
      if (user) {
        user.isLogin = true
        this.$store.commit('login', user)
      } else {
        this.$store.commit('logout', user)
      };
    })
  }
```

```javascript:index.js
import Vuex from 'vuex'

const store = () => {
  return new Vuex.Store({
    state: {
      uid: '', // 初期値
      name: ''
    },
    mutations: {
      login (state, user) {
        state.uid = user.uid
        state.name = user.displayName
        state.isLogin = user.isLogin
      },
      logout (state) {
        state.user = null
      }
    }
  })
}
export default store
```

## ログアウト機能の動き

![プライベートメモ-4.jpg](https://qiita-image-store.s3.amazonaws.com/0/193389/21598ad3-645d-c80c-e1ca-e8da005114a5.jpeg)


```javascript:default.vue
  methods: {
    googleLogout: function () {
      firebase.auth().signOut().then(() => {
        this.isLogin = false
        window.location.href = '/'
      })
    }
  }
```

## ログイン、未ログイン時で振り分け

下記のようにisLoginのステータスで描画を振り分けているが再描画がうまくできなかったのでredirectして無理やり再描画。条件文はtrueかnullなのでfalseではなく!== trueでtrueじゃない場合とした。

```javascript
<Mypage v-if="$store.state.isLogin === true"></Mypage>
<Home v-if="$store.state.isLogin !== true"></Home>
```
## statusはasyncdataで

もしstoreの情報をdataでもってcomponent内でリアクティブにやりとりするならasyncDataでまずサーバー側で受け取っておいてレンダリングしてdataでやり取りする必要がある

```javascript
asyncData () {
    return {
      isLogin: false,
      user: []
    }
  }
```
メモ１：初歩、つまづいたものたち(java、javascript ）

# エンジニア初心者としてつまづいたこと、早く知っておきたかったことのメモ
自分用メモ、あとは本当に初心者くらいの人むけ

## eclipse デバッグモード

プログラム実行時、ブレークポイント（自分で設定する停止ポイントみたいなもの）で処理を一時停止できる。
停めた時点での変数の中身が確認できるので、組んだプログラムがどう動いているか確認できる。

（参考）
https://ittoybox.com/archives/341


## 開発者ツール
IEやChromeならF12で出現。
DOMやネットワーク（リクエスト、レスポンス結果）やブラウザ上で動くjavascriptのデバッグができる。
DOMエクスプローラでCSSも書け、その場で文字の色、サイズなどレイアウト要素を操作して確認できるため画面デザインを行う際は確実に使用する。
デバッグは上記のeclipse同様、ブレークポイントの挿入による操作が可能。
当然ブラウザごとに見た目は異なるので留意。

（参考）※Chromeの開発者ツールについて
https://www.buildinsider.net/web/chromedevtools/01


## javaの参照渡し、値渡し
要は引数にどう渡すかということだが、つまづく人も多いはず。
結論、javaは”参照値”を渡している＝”参照値”の値渡し。

（参考）色々拝見した中で、個人的に端的かつわかりやすかったです
https://qiita.com/mdstoy/items/2ef4ada6f88341466783

※補足※
「参照」ひとつの意味をとっても、例えばjavaとC#では異なる。
自分が扱う言語で何を指すかは、？？となった際に押さえておきたい。
keyword
・プリミティブ型
・参照型
・値渡し
・参照渡し
・参照の値渡し

## オブジェクト、プロパティ（javascript）

「犬」というオブジェクトがもつ”名前”、”年齢”、”犬種”がプロパティ
オブジェクト名.プロパティ名でアクセスできる。
ここら辺は調べればいくらでも情報が手に入る。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Objects_and_Properties

javascriptに限った話ではないが、オブジェクトやらプロパティの話をする際に以下キーワードもきっと目に入るため押さえておきたい
keyword
・グローバル変数、ローカル変数
・スコープ
・クロージャ
【HTML】属性「src」と「href」

#経緯
>imgタグで参照先を指定する属性はsrc
>aタグで参照先を指定する属性はhref

同じ参照でもどういう区別してるんだろうか。

#まとめてみた

|属性|語源|語意|出典|
|:-:|:-:|:-:|:-:|:-:|
|src|source|源泉、元、源、原因、水源(地)、情報源、出所|[Weblio](https://ejje.weblio.jp/content/source)|
|href|hypertext reference|(reference)言及、論及、参照、照合、参考、参照文、引用文、参考文献、参考図書|[Weblio](https://ejje.weblio.jp/content/reference)|

(hypertext…テキストを超えたテキスト テキストとテキストの関連付け
→テキストのリンクを押すと他のテキストに移る仕組み(つまりはWEBページ)　HTML)

hyper text([Wikipedia](https://ja.wikipedia.org/wiki/%E3%83%8F%E3%82%A4%E3%83%91%E3%83%BC%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88))
#何を指定できるの？
URL（絶対パス）
URL（相対パス）
ページ内の特定要素
他プロトコル（メールやFTP）
スクリプト

#どんなタグに使われているの？
###src属性
|タグ|使い方|
|:-:|:-:|
|audio|メディアファイルを埋め込む|
|embed|プラグインが必要なデータを埋め込む|
|iframe|フレームを埋め込む(HTMLを埋め込む)|
|img|画像を埋め込む|
|input|入力欄を埋め込む|
|script|javascriptを埋め込む|
|source|メディアファイルのURLを指定|
|video|動画ファイルを埋め込む|


###href属性
|タグ|使い方|
|:-:|:-:|
|a|ハイパーリンクの出発点を指定|
|area|イメージマップのハイパーリンク領域を設定|
|base|相対パスの基準URLを指定|
|link|外部リソース(CSSとかjavascriptとか)のパスを指定|

#つまりどんなイメージ？
###src属性
HTMLに埋め込むファイルのパス情報

###href属性
HTMLから他のHTML(外部リソース)へのハイパーリンクを指定
#参考
[W3 Watch Reference](https://reference.hyper-text.org/)




#Qiita初投稿
いえーい
些細なことでも投稿していきます。
build.gradle.kts移行したプロジェクトで、appModuleすら認識しなくなってしまったときの解決法

# はじめに
build.gradle.kts移行をしたアプリでdependenciesをいじったりしていたら、Studioのprojectビューにルートのgradleファイルしか見えなくなってしまいアプリ実行ができない問題に直面したので、その時の解決方法を記します。

# 対応(結論)
settings.gradleとプロジェクトルートのbuild.gradleをktsから元に戻してSync
app/build.gradle.ktsはそのままでOK(私は大丈夫でした)

基本構成であれば、groovyでも認識できる書き方も多々あるため下記をするだけ。

- settings.gradle.ktsは、拡張子を戻すだけ
- プロジェクトルートのbuild.gradle.ktsは、拡張子を戻す
  - `val kotlin_version by extra("1.3.21")`を使っていれば、`ext.kotlin_version = "1.3.21"`に戻す

# 原因(不明)
力不足。
AndroidStudioでktsが公式対応されているわけではない？
groovyに戻しただけで直ったので、IDEの認識がうまく行かなかったのかなと推測。

# 最後に
groovyとktsは共存できるので、app/build.gradleだけktsにしています。
画面とソースコードがうまく紐付けできないときの解消法

Xcodeで開発を行っているときボタンと実装の紐付きが行えない事象が発生しました。

<img width="256" alt="スクリーンショット 2019-03-30 23.44.33.png" src="https://qiita-image-store.s3.amazonaws.com/0/239560/359c510f-e65a-ede4-544a-436997c72d2a.png">

ボタンをソースコードのほうにドラッグ＆ドロップして、名前を設定したら**Could not insert new outlet connection** となり、うまく接続が出来ません・・・
ほとんどの場合はXcodeのクリーンを実行してみたり、再起動すれば解消されるはずですが、今回はそれでも解消されなかったのでメモとして残したいと思います。

今回、私が行った事はソースコードに先に変数を指定して、画像と紐づけをすると言う方法です。
<img width="609" alt="スクリーンショット 2019-03-31 21.54.45.png" src="https://qiita-image-store.s3.amazonaws.com/0/239560/e88ed68b-c7b7-0096-669a-1f85ecf888d5.png">

上記のように、うまく接続できました。

Xcodeはたまに挙動が不自然な場合があると感じているので、クリーンや再起動でうまくいかない場合は、逆転の発想や他の人が試していないことをやってみるといいかもしれません(私は責任がとれませんが...)
新卒エンジニアのAtCoder観察日記

##はじめに
- 技術に関する記事ではありません。ノイズになることをここでお詫び申し上げます。
- この記事は約１ヶ月ごとに追記されます。
- それ故、初期の記事は大変粗末なものになるかと思います。~~検索妨害とか言わないで~~


## お前はだれだ
１．都内某所でエンジニア、今年度から新社会人スタート
２．2019/3/31時点でAtCoder灰色
![image.png](https://qiita-image-store.s3.amazonaws.com/0/180586/53c3b29d-ac5a-f7ff-a3a7-522f62ca8122.png)
３．AtCoder、B問題までは大抵解けるレベル
４．コンペ出場２回

つまるところ、競プロ界ではよわよわ駆け出しプレーヤーである。

## この日記の目的
- **時間ないマンである社会人が、どのように日々を過ごせば競プロする機械になれるか実験する**
- **これから競プロをはじめたいという人に向けて、成長のイメージをできるようにしてほしい**
- **競プロは挫折しやすい。だからこそ、挫折がどのタイミングで発生するかを記録し、競プロer全員の救いになればうれしい**



## ぴっかぴかの１年生
- 新社会人だし！節目だし！目標決めてがんばろう！（小学生）
- ABCのAB問題をすべて埋める
- 朝型人間なので早起きをして就業前、もしくは休憩時間等で解く。（３０分目安）
- ABCコンは絶対に出場する。
- チーター、蟻、螺旋本を買う。

### 何度でも繰り返される理不尽
- そう、花見である。
- 新卒歓迎花見イベントは新卒が開催しました（これが時間泥棒）
- AB埋め、４月中には終わらないと判断
- →残１８３問に対し、１週間で埋めたのが１１問のため
- 第２週でどれだけ埋められるか確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180586/b18d94ed-2711-c24e-989a-72a9d118fdbd.png)

### 四月は君の嘘

**目標達成ならず**

【所感】

- 他に勉強すべきことが大量にある。（キャリアを捨てて精進するという手もあるが。。）
- 社会人、本当に時間がない。本当に。（在学中に精進しまくってください）
- IPA試験があった（） 

【反省】

- 事象：ABC-Aすら終わってない。
- 原因：日頃のノルマの設定が厳しい（？）
- 解決：１日４ACで、濃い草を生やすことをノルマにする

## 五月雨、延長戦
**だらだら ＆＆ 圧倒的モチベダウン**
**そしてこれが６月まで続く(５月分の更新がないの。察して。)**

### 歯車になること
 - 研修期間でしたほんとすみません。ずっとJavaやってましたすみません
 - 結局Bはまだ半分残っている
 - 会社に還元しなきゃいけないので、そちらの勉強も並行（これがまためんどい）

### 人間環境構築
- 研修で一緒になった他社さんにも駆け出し競プロマンがいた
- 打ち解ける
- モチベアップ（ありがとうありがとうありがとう）
- そしてやっとこさ茶色上陸
 ![FireShot Capture 037 - enkdkn - AtCoder - atcoder.jp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180586/1a0a683d-e1ba-c905-b7e5-d94fdd93213c.png)

- 進捗です
![FireShot Capture 038 - AtCoder Problems - kenkoooo.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180586/131932fe-5765-0efc-d543-660dbbae2099.png)

- パフォもほどほどに。D、Eが解けるようにすることが課題。
- ABC早解きでも、ABC132ではABC１０分でかなりパフォ出てるらしく、早解き力も大事。


### 利益衡量
**（脳内）**

- （ここはパフォ優先で早解きして、早く緑に行くほうがいい！）
- （でも今は、早解きよりも地力をつけていったほうが後々いい！）
- （地力つけて、速さよりも解答数で殴りたい。水色になるには必要だ！）
- (解説もだんだん理解できるようになって来たし、ここが成長期だ！)

**などと、今までの失態をすべて忘れたかの如く、この男は７月の精進を誓うのであった（To Be Continue????）**



####　１年後、?Coderになる
MySQL8.0に変えたら起こるアレ

# MySQL8.0にしたらエラーが起こった
エラー内容

```
SQLSTATE[HY000] [2054] The server requested authentication method unknown to the client
```

解決方法はこれ↓
[MySQL8.0以降で接続できない場合は「認証プラグイン」を変更する
](https://www.petitmonte.com/database/mysql_authentication_plugin.html)

## 記事の抜粋

>MySQL8.0以降では認証プラグインがデフォルトでは「caching_sha2_password」となっています。その為、PHP/Ruby/Pythonなどのプログラム言語から接続できない場合があります。

#### 認証方式の確認

```
mysql> SELECT user, host, plugin FROM mysql.user;
+------------------+-----------+-----------------------+
| user             | host      | plugin                |
+------------------+-----------+-----------------------+
| my-home-page     | %         | caching_sha2_password |
| root             | %         | caching_sha2_password |
| mysql.infoschema | localhost | caching_sha2_password |
| mysql.session    | localhost | caching_sha2_password |
| mysql.sys        | localhost | caching_sha2_password |
| root             | localhost | caching_sha2_password |
+------------------+-----------+-----------------------+
```

#### 認証方式の変更

```
mysql> ALTER USER 'my-home-page'@'%' IDENTIFIED WITH mysql_native_password BY 'パスワード';
mysql> ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'パスワード';
mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'パスワード';

mysql> SELECT user, host, plugin FROM mysql.user;
+------------------+-----------+-----------------------+
| user             | host      | plugin                |
+------------------+-----------+-----------------------+
| my-home-page     | %         | mysql_native_password |
| root             | %         | mysql_native_password |
| mysql.infoschema | localhost | caching_sha2_password |
| mysql.session    | localhost | caching_sha2_password |
| mysql.sys        | localhost | caching_sha2_password |
| root             | localhost | mysql_native_password |
+------------------+-----------+-----------------------+
```
`root`を変えたいのであれば`test`の部分を`root`などの任意のものに指定する。

## 事前の対策
`/etc/my.cnf`に書きを追記

```
[mysqld]
default-authentication-plugin = mysql_native_password
```

## 余談
僕はLaravelの`php artisan migrate`した時に起こりました。
エラー内容やキーワードを詰め込んだので同じ様に困った人がこの記事にたどり着いて問題を解決してくれるといいな。
gitのTAB補完をVersionに合わせていい感じにする

「私は最新版の`git-completion.bash`を使いたい！」
そんなあなたへ

# 条件
- homebrewで`git`をinstallしている
- `.bashrc`を以下のように書いてしまっている

```
source /usr/local/Cellar/git/2.21.0/etc/bash_completion.d/git-completion.bash
```

# 問題
- homebrewのアップデートを行い、`git`のアップデートが行われる
- `.bashrc`の`git-completion.bash`のパスが通らずにgitのTAB補完ができなくなる

# 実験

- `git --version`コマンドの第三引数を使えばいけるのでは？

```
$ git --version
git version 2.21.0
```

- `cut`コマンドを使う

```
$ git --version | cut -d ' ' -f3
2.21.0
```

# 実装

- `.bashrc`で以下に変更

```
source /usr/local/Cellar/git/$(git --version | cut -d ' ' -f3)/etc/bash_completion.d/git-completion.bash
```

- 補完できた

# 修正2019/4/16
- `バッククォート`ではなく`シングルクォート`もしくは`ダブルクォート`です。申し訳ございません
- 資料はすでに修正済みです

# 参考
- [【2ステップ】Gitコマンドでtab補完を有効にする](https://qiita.com/growsic/items/1fff6286061e0cd27d54)
- [cut、head、tail、sort･･･定番のフィルタコマンドを使いこなす！
～業務でラクするためのUNIXテクニック～](https://codezine.jp/article/detail/3643)
PhotoShopのカラースウォッチをUnityにインポートするツール

##概要
PhotoShopのカラースウォッチのファイル, AcoファイルをUnityにインポートするツール。
<img width="279" alt="スクリーンショット 2019-03-31 21.52.23.png" src="https://qiita-image-store.s3.amazonaws.com/0/46278/a24983dd-231b-7406-ca2d-5c1e7998c89a.png">


##動作環境
Unity2018.3で確認
UPMの[2D PSD Importer](https://docs.unity3d.com/Packages/com.unity.2d.psdimporter@1.0/manual/index.html)が必要
(上に含まれる[Photoshop PSD FileType Plugin for Paint.NET](https://www.psdplugin.com/)が必要)


##導入
以下のファイルをEditorフォルダ内に入れる。
https://gist.github.com/ShunMc/5b2ddbe4c29e04aefacac7150482496d

##使用方法
AcoファイルをUnityProjectにImportする。

##参考
http://www.nomodes.com/aco.html
https://www.cyotek.com/blog/reading-photoshop-color-swatch-aco-files-using-csharp
http://baba-s.hatenablog.com/entry/2018/01/23/100000
GitHubから組織のすべての公開リポジトリをgit cloneする方法

[自分の過去のブログ](https://blog.haniokasai.com/2016/11/githubgit-clone.html)　から。


githubからorganizationのすべてのリポジトリをgit cloneする方法

githubのプライベートリポジトリをブルーレイにバックアップしようと思ったので、調べてみた。


あくまでも組織のみの場合です。ユーザーの場合は api.github.com/orgs　を　api.github.com/usersに変えるように。

```shell:gitbp.sh
#/bin/sh
username=*****
password=******
oauthtoken=***
 ORGANIZATION=ダウンロードしたい組織名
mkdir $ORGANIZATION;
cd $ORGANIZATION;
for i in `curl -u $username:$oauthtoken -s https://api.github.com/orgs/$ORGANIZATION/repos?per_page=200 |grep html_url|awk 'NR%2 == 0'|cut -d ':'  -f 2-3|tr -d '",'`; do 
expect -c "
set timeout 20
spawn git clone $i.git
expect \"Username for \'https://github.com\':\"
send \"$username\n\"
expect \"Password for \'https://$username@github.com\':\"
send \"$password\n\"
interact
"; 
done
```



ユーザーの公開リポジトリは


```shell:gitbp.sh
#/bin/sh
 ORGANIZATION=******
mkdir $ORGANIZATION;
cd $ORGANIZATION;

for i in `curl   -s https://api.github.com/users/$ORGANIZATION/repos?per_page=200 |grep html_url|awk 'NR%2 == 0'|cut -d ':'  -f 2-3|tr -d '",'`; do 
git clone $i.git; 
done
```

でできます

#参考
https://gist.github.com/caniszczyk/3856584
http://futurismo.biz/archives/1357
なぜKubernetesではなくAmazon ECSを使うべきなのか

## TL;DR
- Kubernetesはマイクロサービスには適しているが複雑
- 未だに学習コストが高く、周辺ツールにも振り回される
- ECSはKubernetesよりはるかに運用しやすい
- AWSへのベンダーロックインによる悲観は必要ない
- Kubernetesのデメリットを把握した上で導入するべき

## オーケストレーションツール
KubernetesとAmazon ECSは、同じくDockerコンテナのオーケストレーションツールに位置する。

そもそもオーケストレーションツールはなぜ必要かというと、**プロダクションレベルでの運用を実現するため**である。複数ホストに分散されて起動されているDockerコンテナの死活監視、オートスケーリングなどを管理するのはそう簡単ではない。これらの課題を解決するためにKubernetesやECSなどのオーケストレーションツールが存在している。

### Kubernetes
このツールの代表的な存在にあるのがKubernetes。KubernetesはGoogle内で利用されていた「Borg」というツールがオープンソース化したものであり、現在は様々な開発者やクラウドプロバイダによってメンテナンスされている。

### Amazon ECS
Amazon ECSは、AWSが提供するコンテナのオーケストレーションサービス。ECSはKubernetesにある様々な概念をなくし、ライトなオーケストレーションツールという位置付けになる。必要なタスク定義（起動するコンテナ数やリソースなど）を指定すれば、それだけでECSがマネージドよろしく管理してくれる。

## Kubernetesの懸念点とは何か

### サービス/チームへの過剰な権限管理
KubernetesはNamespaceというサービスの空間のようなものを設定し、このNamespaceごとに細かく権限を与えられる。これにより、例えば各マイクロサービスチームが1つのサービスを自律的に運用することが可能になる。

マイクロサービスのアーキテクチャならまだしも、一つのアカウントで複数のモノリシックサービスを運営するケースにおいては不要と言いきれる。各チームへKubernetesの基礎を教え、そして「これからは自立して運用してくださいね」と言っても、そこに何もメリットは無いし、多くの組織ではスキルセット的に難しい。

### インフラが属人化すること
Kubernetesは様々な環境や用途を想定して高度に抽象化されており、自分の組織で運用するために具象化していくのには、ECSに比べて多くの時間やリソースが必要になる。後述する周辺ツールの乱立期を踏まえると、Kubernetesがただの時間泥棒になる恐れを感じている。

### カナリアデプロイは必要か
KubernetesのContinuous Deliveryツールとして「Spinnaker」が有名であり、Spinnakerはカナリアデプロイを行える。ただカナリアデプロイがKubernetesを導入する理由となるかは怪しい。多くの場合、ブルー・グリーンデプロイメントで十分だし、そもそも毎回カナリアを使わなければならないほどデプロイを恐れている状態は不健全であり、根本的な解決にはならない。

またSpinnakerそのものの構築や運用も必要になる。私もSpinnakerの構築をしたことがあるが、多くの人が導入や運用にハマるような印象を受けている。それに対しAWSではマネージドなデプロイサービスであるCodeDeployを提供し、CodeDeployはECSへのブルー・グリーンデプロイメントをサポートしている。もちろんCodeDeployは構築や運用の手間は必要ない。

### App Meshの登場
サービスメッシュは各マイクロサービス間の通信やその経路を制御するための考え方であり、これらは複数のサービスにまたがって考慮しなければならない。ECSでは現状、サービスメッシュの導入は難しいが、KubernetesではIstioやEnvoyなどを使って導入することができる。

ただECSやEKSに統合できるマイクロサービスの管理基盤として[AWS App Mesh](https://aws.amazon.com/jp/blogs/news/aws-app-mesh-application-level-networking-for-cloud-applications/)のようなものも出ている。（まだ正式にリリースされているわけではない。）こうしてAWSがマネージドなサービスを出していく中で、Kubernetesを自分達自身で運用していくメリットは、次第に小さくなっていくだろう。

### 非ベンダーロックインであるべきか
Kubernetesの利点を一つ上げるとなれば、特定のベンダーに依存しない点がある。Amazon ECSではAWSでの稼働を前提としており、例えばGCPや自社サーバーではKubernetesを使うしか他ない。

このように「ベンダーへ依存してしまうことがECSを使うべきではない理由だ」という意見もある。しかしベンダーロックに関しては事実避けられないものであり、クラウドをAWSから他に移動するという事もほぼ起こりえない。仮にクラウドを移行することになっても、ECSで10～30個のモノリシックサービスが運用されている程度では移行の障壁となるとは到底思えない。

### 周辺ツールの乱立期
もしECSを使う場合、アプリケーションの設定やContinuous Deliveryの構築まで、全てTerraform上で完結できる。例えばNuxt.jsをECSで動かしてCodePipelineでCDしたい、となれば全て[このTerraformリポジトリのように](https://github.com/hareku/terraform-nuxt-fargate/tree/master/terraform)1リポジトリで管理することができる。

しかしKubernetesの場合、HelmやKustomizeなどを使ってのYAMLの作成や、必要であればSpinnakerとの統合も行う必要がある。個人的にKubernetesのYAMLの管理はツールが多すぎてとっつきづらい。未だに周辺ツールの乱立期から抜けられていないし、ツールに振り回されるという印象も否めない。

## 結論
**AWS使えてECSで十分なら、ECSでいこう。**

上述の通り、Kubernetesを使う理由は、多くの組織には存在しない。ECSで本番レベルのDockerアプリケーションを十分に運用できる。

Kubernetesでしかできない試みとして[Kubernetesで数百以上のDocker開発環境を運用](https://qiita.com/hareku/items/443136c54d339066df6c)していたりする。採用のアピール活動としてKubernetesを導入する場合は、慎重に考えていきたい。