OmniAICreator/Qiita-1.07M huggingface dataset:
pay.jpがAWS（本番環境）で作動しないエラーから環境変数を学ぶ

##背景
PAY.JPを利用した決済システムがローカル環境では問題なく動作するのに、本番環境（AWS,EC２）ではエラーとなってしまった。

![スクリーンショット 2020-12-05 18.08.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864534/d9ffd316-3bc2-452d-45a2-3ca5af865198.png)




その過程で環境変数について初学者なりに学んだことを備忘録として記録。

##問題
①AWSに環境変数として公開鍵、秘密鍵の設定を行っていなかった。
②ENVファイルに記載している鍵情報を読み込む設定ではエラーが解消されない

##解決
①AWSに鍵情報を環境変数として設定する
②ENVファイルからではなく、credentilas.ymlから鍵情報を読み込むように設定
③②の為に、credentials.ymlに鍵情報を環境変数として設定

##詳細
①AWSの環境変数の設定
本番環境への設定なので、EC２ユーザーでログインして、
`[ec2-user@ip-172-31-45-207 ~]$ sudo vim /etc/environment`
ENVファイルを開く。iでインサートモードにして、
`PAYJP_SECRET_KEY='sk_test_{pay.jpの秘密鍵情報}'`
`PAYJP_PUBLIC_KEY='pk_test_{pay.jpの公開鍵情報}'`
を記述。esc、:、wqで保存。

ENVファイルに記述した環境変数をコントローラで読み込む記述。
`Payjp.api_key = ENV["PAYJP_SECRET_KEY"]`

これで行ける！と思われましたが、まだエラーが解消されません。

②ENVファイルではなくcredentials.ymlから環境変数を読み込む設定をする。
（本番環境でのみなぜ、このように設定する必要があるのかは勉強不足で不明です。しかし、このエラーのおかげでcredentialsファイルとはなんぞやということを勉強するきっかけとなりました。）

https://qiita.com/777mountain/items/74757248980fcddb7652
こちらの記事を参考にしました。

`Payjp.api_key = Rails.application.credentials.PAYJP[:PAYJP_SECRET_KEY]`

これだけではまだエラーは解消されません。credentialsファイルに環境変数で鍵情報が設定されていない為です。そもそもcredentialsファイルってなんぞや？


````config/credentials.yml.enc
`VhSwT9zhK87oJuVNsMUN/I3Oh/....`
````

暗号化された環境変数情報が記載されています。rails newした時に作成され、これを別ファイルのマスターキーを照合して読み込む仕様になっています。ちなみに、機密ファイルなのでコーダー上で直接このファイルを変更しようとすると、再起動不能になり、ファイルを削除して作り直す等の処理が必要になるので注意です。

③credentials.ymlに鍵情報を環境変数として設定

ターミナル上で
`EDITOR="vi" bin/rails credentials:edit`
iでインサートモードにして、
`PAYJP:
  PAYJP_SECRET_KEY: sk_test_秘密鍵
  PAYJP_PUBLIC_KEY: pk_test_公開鍵`

esc、:、wq で保存。

注意点としては、ENVファイルと記述方法が違うということです。
ENVだと''で囲んでいたりしましたが、こちらの場合 キー:値
という形式でないとエラーになります。

これでコントローラに記述した

`Payjp.api_key = Rails.application.credentials.PAYJP[:PAYJP_SECRET_KEY]`

が動きます。こちらの書き方もENVの時とは違うので留意しましょう。

これで完了です。ローカルと本番でこの辺の動き方が変わる理由が未だよく分かりませんが、
（誰かわかる人いればご教授お願い致します！）
環境変数の設定方法がこのように複数あるということは学びになりました。ちなみに、環境変数を設定する際、無駄なスペース等を入れてしまうと、アプリ全体に影響を及ぼす重篤なエラーに繋がり、初学者は特にどこに原因があるのか突き止めるのに苦労すると思いますので、慎重に記述しましょう。
Do not use empty rulests css

vscodeのstylesheet.cssファイルで
以下のようにコードを打ったら`Do not use empty rulests css`と警告が出ました。

```
.header {
    background-color: #fafafa grey lighten-5;

}
.main {

}
.foter {
    
}
```

###意味
cssで中身のないカッコを作らないでくださいという意味だそうです。
カッコの中にカラーなどを指定したら消えました。
[Riverpod] StateNotifierのstateが特定の値のときだけWidgetをビルドするには・過去のStateを取得するには

# はじめに

- Flutterでの状態管理に使われる最もポピュラーなパッケージのひとつにProviderがあります。RiverpodはこのProviderを改良した新しいパッケージです。
- [StateNotifier](https://pub.dev/packages/state_notifier)はValueNotifierのパフォーマンスやユーティリティに関して改善を加えたパッケージで、Providerとよく併用されます(Riverpodには同梱されています)。

# StateNotiferでstateが特定の値のときだけWidgetをビルドしたい

`StateNotifer.state`の値で条件分岐することってよくありますよね。
でも、stateの値によってWidgetをビルドするのではなく、**特定の値のときにだけWidgetをビルド**したいときってありませんか？

例えば以下のような場合、`state!=null`のときだけリビルドするにはどうすればいいでしょうか。

```dart

@freezed
abstract class LoaderState with _$LoaderState {
  const factory LoaderState.preload(String initialData) = Preload;
  const factory LoaderState.success(String data) = Success;
  const factory LoaderState.error() = Error;
  const factory LoaderState.canceled() = Canceled;
}

final myServiceProvider = StateProvider((_) => MyService());

final textProvider = Provider((ref) {
  final state = ref.watch(myServiceProvider.state);
  return state.maybeWhen(
    preload: (initialData) => initialData,
    success: (data) => data,
    orElse: () => null,
  );
});

class MyWidget extends HookWidget {
  @override
  Widget build(BuildContext context) {
    final text = useProvider(textProvider);// text == nullのとき、過去のstateを使いたい・リビルドさせたくない
    return Text(text);
  }
}
```

# モデルを作り変えるのは冗長
ひとつは、以下のようにWidgetの条件分岐のための変数をStateのモデル内部につくり、buildメソッド内で`useProvider.select`することです。
しかし、`useProvider`はHook系Widget内でしか使えませんし、モデルが複雑になってしまいます。

```dart

@freezed
abstract class MyState with _$MyState {
  const factory MyState ({
    @required String text,
    @required LoaderState loaderState,
  }) = _MyState;
}

@freezed
abstract class LoaderState with _$LoaderState {
  const factory LoaderState.preload(String initialData) = Preload;
  const factory LoaderState.success(String data) = Success;
  const factory LoaderState.error() = Error;
  const factory LoaderState.canceled() = Canceled;
}

final myServiceProvider = StateNotifierProvider((_) => MyService());

class MyWidget extends HookWidget {
  @override
  Widget build(BuildContext context) {
    final text = useProvider(myServiceProvider.state.select((state) => state.text))
    return Text(text);
  }
}
```

# StateControllerでStateをキャッシュする
そんなときはモデルを作り変えるのではなくStateをキャッシュしましょう。
StateNotifierを継承したStateControllerを使えば、より簡単に書くことができます。

```dart 

final myServiceProvider = StateProvider((_) => MyService());

final textProvider = StateNotifierProvider<StateController<String>>((ref) {
  final notifier = StateController('');

  final removeListener = ref.watch(myServiceProvider).addListener((value) {
    // MyService.stateがPreload・Successの場合のみテキストを更新
    value.state.maybeWhen({
       preload: (initialData) => notifier.state = initialData,
       success: (data) => notifier.state = data,
       orElese: () {}
    });
  });
  ref.onDispose(removeListener);

  return notifier;
});

class MyWidget extends HookWidget {
  @override
  Widget build(BuildContext context) {
    final text = useProvider(textProvider.state);
    return Text(text);
  }
}
```

# 参考記事
- [Listening to selected states of StateNotifierProvider](https://github.com/rrousselGit/river_pod/issues/186)
【Swift】フルスクリーンの画面遷移から戻る

# どういうことか

ストーリーボードを使った、ボタンを押したら画面遷移する簡単なパターン。
画面遷移の設定を

![0abe083be6ad4a81caf4a17bd3a21f3d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413699/a16720f1-6a19-fe30-0ab6-e41ebf1eac8e.png)

こんな感じにしてフルスクリーンにする。

![8b770289a82d1c2b5bddfa08edcacadf.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413699/9a33973b-9e09-31b7-6551-dac708a16ce6.png)

前画面（ホワイト）の頭のほうがちょろっと出ていないので、指でモーダル（ここで言うとオレンジの画面）を下にクイッと下げて前画面に戻ることができない。なので画像のオレンジのように戻るボタンをつける。

## 処理

オレンジの画面にもコントローラが設定されているものとする。
`button`として置いた『BACK』を`controlキー`を押しながらコントローラにグイッとドラッグドロップ。そしたら1行書く。

```swift
  @IBAction func back(_ sender: Any) {
    // ボタンを押したら戻る
    dismiss(animated: true, completion: nil)
  }
```

これだけ。
firebase functionsのonCall呼出し時に認証する

思い付きで書くのでアドベントカレンダーに参加できなかった。。。
# この記事の対象者
onCallファンクションの中で認証が必要なDB操作等をしたい人向け。

ググっても出なかったので書き出します。

onCallの中では認証情報が渡されているのでuidを取り出してcustomTokenを作り認証すればOK!!

##以下サンプルソース

### web 側
バッチ実行ボタン等から呼ばれるclickHandler関数の中でfunctions.httpsCallableにfunctions側の関数名(ここでは'hoge')を渡して非同期で実行する

```client.js
import firebase from 'firebase/app'
import 'firebase/auth'
import 'firebase/functions'
import firebaseConfig from './firebaseConfig'

const clickHandler = async () => {
  const hoge = functions.httpsCallable('hoge')
  const result = await hoge({ piyo: 'fuga' })
  alert(result.data)
}
```

### cloud functions 側(サーバー側)の認証処理部分
※1 firebase-adminsdkのjsonを利用してadminの初期化を事前に済ませます
※2 onCallのcallbak関数の第2引数に認証情報などが含まれている
※3 uidからcustomTokenを作りsignInWithCustomTokenでログインさせる

```functions/index.js
const functions = require('firebase-functions')

const firebase = require('firebase/app')
require('firebase/auth')
require('firebase/database')
const firebaseConfig = require('../firebaseConfig')
firebase.initializeApp(firebaseConfig)

// ※1 firebase-adminsdkのjsonを利用してadminの初期化を事前に済ませます
const admin = require("firebase-admin")
const serviceAccount = require('../firebase-adminsdk.xxx.json')
admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: firebaseConfig.databaseURL
})

// ※2 onCallのcallbak関数の第2引数に認証情報などが含まれている
exports.hoge = functions.https.onCall(async (data, context) => {
  if (!context.auth) {
    return 'ログインしてください'
  }

  // ※3 uidからcustomTokenを作りsignInWithCustomTokenでログインさせる
  try {
    const token = await admin.auth().createCustomToken(context.auth.uid)
    await firebase.auth().signInWithCustomToken(token)
  } catch {
    return 'ログインしてください'
  }

  // db操作とかの処理

  return 'OK' // DB操作結果
}
```

以下設定ファイルなど

```firebaseConfig.js
const firebaseConfig = {
  apiKey: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
  authDomain: 'xxx.firebaseapp.com',
  databaseURL: 'https://xxx.firebaseio.com',
  projectId: 'xxx',
  storageBucket: 'xxx.appspot.com',
  messagingSenderId: 'yyyyyyyyyy',
  appId: 'zzzzzzzzzzzzzzzzzzzzz'
}

module.exports = firebaseConfig
```
Visual Studio CodeでJSONを表示する方法（自分用メモ

#VSCodeでJSONを表示する方法を簡単に記載します（自分用メモ）
[Visual Studio Code（VSCode）](https://code.visualstudio.com/download)よりダウンロード＆インストールしたら、日本語化。

[View]-[Command Palette]
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/2617633d-2868-dd38-3bec-9ff50c81e1a2.png)
[Configure Display Language]を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/13baafc4-0e13-bae1-dd7d-201b3348aea0.png)
[Install additional languages]を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/8ef79959-f1f8-4af6-8658-1f338ebc51fb.png)
言語のリストが表示されるので、目的の言語（日本語）で[Install]
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/f1c335e4-c4c7-0c93-b702-e01476ca9ebb.png)
右下に現れるメッセージウィンドウで[Yes]
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/35c40600-4c92-2cd6-931a-97107eae993f.png)

VSCodeが再起動し日本語化されます。

次はJSONファイルを成型していきます。

［ファイル］-[新規ファイル]
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/0ff62b06-fa17-c4e4-88d3-774b7480f708.png)
開いたエディターにJSONを張り付けます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/bee595c3-78c4-2ecc-b7ef-7647baefc1b4.png)
画面右下メニューの[プレーンテキスト]をクリックし
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/196b4e70-be6e-6f35-564e-076b848cdd89.png)
開いたメニューで[JSON(json)]を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/05208a6d-1d4a-dded-754e-1ca75b0c3ae9.png)
エディターで右クリックメニューを開き、[ドキュメントのフォーマット]
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/a954a868-231c-4d1b-9c2e-f1504b8b3852.png)

こんな感じで表示されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480768/4ba99542-9047-c23d-50b7-982b64e4e11f.png)
[Rails] ルーティングの設定方法

Railsルーティングンの役割は**「リクエストとして受け取ったURLを、コントローラ内のアクションに振り分けていく」**というものです。

記述方法
---
Railsのルーティングは、configディレクトリのroutes.rbに記述します。


```routes.rb
[HTTPメソッド] '[URIパターン]', to: '[コントローラー名]#[アクション名]'
```



確認方法
---
ルーティングを設定したら、確認しましょう。

```ターミナル
rails routes
```
コマンドで、アプリケーションで設定済みのルーティングを確認できます。
すると、下記のような結果がターミナルで表示されました。

```ターミナル
 Prefix  Verb   URI Pattern   Controller#Action
 posts   GET  /posts(.:format)     posts#index
```

**Verb + URIパターン = リクエストの内容**
**Controller#Action = リクエストの行き先**　　を表しています。
【Rails】投稿を「何分前」「何日前」と表示したい!!と思ったので実装してみた

## 時間

[![Image from Gyazo](https://i.gyazo.com/9e95928dea8657f772e9a03b8b86328c.png)](https://gyazo.com/9e95928dea8657f772e9a03b8b86328c)

よく見るこんなやつです。
ぼくはSNSサービスを開発していたので開発日数は「何分前」「何日前」とかにしたかったんですよね。
そこで調べたらめちゃくちゃ簡単に実装できることを知りました。

## 結論
time_ago_in_wordsメソッドを使う


```ruby
<%= time_ago_in_words(post.created_at) %>
```

上記の写真のように作るのであれば以下のコードを使えばOKです。

```ruby
<i class="far fa-clock clock-icon"></i><%= time_ago_in_words(comment.created_at) %>前
```

めちゃくちゃ簡単ですね笑
ささっと実装しちゃってくださいませ〜。

おわり
written by aoi(https://twitter.com/aoi_engineer)
【新卒エンジニア向け】新卒１年目だからこそやりやすい、「自分のことを棚に上げる」提案のすゝめ

こんにちは！[Ateam Hikkoshi samurai Inc.× Ateam Connect Inc. Advent Calendar 2020](https://qiita.com/advent-calendar/2020/hikkoshizamurai-connect)の5日目は、Go、Clean architectureの勉強がトレンドになっている、バックエンド開発を担当する新卒１年目webエンジニアの[@sho-hata](https://qiita.com/sho-hata)がお送りします。

本記事は、エンジニアとして入社してからの9ヶ月を振り返り、**「新卒1年目だからこそできること」**を改めて考えて、書いた内容になります。捉え方によっては、無能が足を引っ張っているという内容に見えますので、「何もできない奴があれこれ口を出すもんじゃない」と思われたりするかもしれません。意見が合わないと思われましたら、参考にしないでください。

散文的で読みづらく、拙い文章ではありますが、自分と同じ新卒１年目の方々や、これから新卒エンジニアとしてキャリアをスタートされる方々の少しでもお役に立てれば嬉しいです。

## 言いたいこと
「自分は口出しできるほど優秀なエンジニアじゃないしな...」と考えていると、**何も提案できません。**

**自分のことはいったん棚に上げて**、自分が良いと思ったツールの導入や技術イベント開催などの提案は遠慮せずに提案してみましょう！！

### 前提：新卒１年目は「できていないこと」が多い
学生の頃から積極的にインターンに参加していたり、余程の天才肌ではない限り、新卒１年目のうちは業務で「できること」より「できないこと」の方が多いのではないかと思います。

できていないことが多いからと言って、ずっと巣の中で口を開けて親からの餌をもらうだけの雛鳥のようにいればいいのかといえば、そうではないはずです。価値創出の対価として賃金を受け取る仕事である以上、何らかの価値を生み出す存在であった方が良いはずです。

では新卒１年目が生み出せる価値は何か。そのひとつに、提案することが挙げられます。新しい技術や、業務効率化のツールの導入、技術力向上のイベント開催の提案など...提案のかたちは多々ありますが、新卒はこのような提案がしやすいのではと感じました。
理由を以下に示します。

## 新卒が提案をしやすい理由
### 提案するときに、ストッパーがかかりにくい
新卒１年目のメリットの１つとして、なにかを提案する際、変なストッパーがかかりにくいことが挙げられます。どうしても業務知識が増えると、「それはこういう理由で難しいから...」というストッパーがかかってしまうと思います（※これはあくまで主観ですが）。

ですが、新卒１年目ではそのようなストッパーは形成されていません。会社・組織に対して、ある意味純粋に疑問を問いかけることができます。業界に染まり切っていない意見は案外貴重なため、恐れず、自分が良いと思ったことはガンガン提案しまくりましょう。そして、ガンガンフィードバックをもらいましょう。

### 自分ができていないからこそ、提案する
前述しましたが、新卒１年目は、できることよりできていないことの方が多いです。そのため、組織ができていないことで、自分ができていることはめったにないと思います。

ここで、「自分ができていないから...」といって提案することをやめてしまうと、組織にとっても自分にとっても良くありません。自分ができていないからこそ、できるようにするための仕組み作りを考える方向に発想を転換した方が、ポジティブです。

自分の体験談にはなりますが、入社した当初、組織には技術のアウトプットができてないのではないか、という課題がありました。確かに、アウトプット量に課題感を持っている割にQiitaの投稿数が少ないよな、、、と正直なところ感じていました。

ただ、それは自分にも当てはまることで、自分のアウトプット量も決して多くはありませんでした。
ですがあえて、**「（自分もできていないけど）組織のアウトプット量が少ないと思うので、お祭り感覚のQiitaへのアウトプットイベントがあったら良いと思います！」**と企画を提案しました。すると、とんとん拍子で会社全体を巻き込んだ企画の実行にまでこぎつけ、Qiitaの月間Organizationランキングにランクインするほどのアウトプットがされるようになりました。

おそらく、「自分ができていないから...」といって尻込みをしていたら、なにもできていなかったでしょう。



## まとめ
体験談垂れ流しの読みにくいポエムのようになってしまいましたが、言いたいことは以下です。

**「自分は口出しできるほど優秀なエンジニアじゃないしな...」と考えていると、何も提案できません。**

 ある意味**「イキって」**、自分ができていないことでも、いったん棚に上げて、良いと思った提案はどんどんしていきましょう！！！
（※そのために組織内で合意をとっておくことや、成長するための努力は必要です！）

## 次回予告
[Ateam Hikkoshi samurai Inc.× Ateam Connect Inc. Advent Calendar 2020](https://qiita.com/advent-calendar/2020/hikkoshizamurai-connect) ５日目の記事でした！

明日はエンジニアの@Ingwardさんです！お楽しみに〜〜〜！！

---

### 合わせて読みたい
[コードレビューの極意。それは「自分のことは棚に上げる」こと！！](https://qiita.com/jnchito/items/0a0b46106681f41f2f0e)
Firefoxアドオンでfetch APIを使うと "TypeError: NetworkError when attempting to fetch resource." になる

## 概要

拡張機能のcontentscript上で`fetch`を使うと、chromeでは動作するのにfirefoxでは動作しない

## 原因

Firefoxのpermissionにて許可する必要がある。
`manifest.json`に拡張機能を動作させて良いURIパターンを追記する。
テストであれば以下の記述にすると、全ページで利用できるようになる。

```json
  "permissions": [
    "*://*/*"
  ]
```

manifest.jsonに書く場合

```json:manifest.json
{
  "name": "",
  "short_name": "",
  "description": "",
  "version": "0.0.0",
  "manifest_version": 2,
  "default_locale": "en",
   "icons": {
  },
  "background": {
  },
  "browser_action": {
  },
  "content_scripts": [
  ],
  "permissions": [
    "*://*/*"
  ]
}
```

## 試したこと

- pollyfillを入れる
    - pollyfillでも同様のエラーが発生

## 参考

- [permissions - Mozilla | MDN](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions "permissions - Mozilla | MDN")
- [TypeError: NetworkError when attempting to fetch resource - firefox issue · Issue #310 · github/fetch](https://github.com/github/fetch/issues/310#issuecomment-454662463")
    - [Fetch api not working in firefox addon : firefox](https://www.reddit.com/r/firefox/ "Fetch api not working in firefox addon : firefox")
機械学習における「大域的(global)な説明」と「局所的(local)な説明の違い」


# 概要、背景

* 機械学習における「大域的(global)な説明」と「局所的(local)な説明の違い」、について調べてまとめる
* 「[データサイエンティストスキルチェックリスト](https://www.datascientist.or.jp/common/docs/skillcheck_ver3.00.pdf)」の「データサイエンス力」項目で**「機械学習における大域的(global)な説明（モデル単位の各変数の寄与度など）と局所的(local)な説明（予測するレコード単位の各変数の寄与度など）の違いを理解している」**とあるため、勉強を兼ねて
* スタート時点：機械学習の種類はボチボチ知ってるが、「モデル単位の各変数の寄与度」「レコード単位の各変数の寄与度」と言われてイメージが湧かない

# 「大域的(global)な説明」と「局所的(local)な説明の違い」とは

* 大域的(global)な説明
  * **複雑な機械学習モデルを、可読性の高いモデルで置き換えて説明すること**
* 局所的(local)な説明
  * **複雑な機械学習モデルの、ある入出力例の周辺に対する挙動を(可読性の高いモデルなどを使って)説明すること**
* 調べた内容は↓

# 調べたもの

## [機械学習における解釈性 - 人工知能学会](https://www.ai-gakkai.or.jp/my-bookmark_vol33-no3/)

> 1. 大域的な説明
>   * 複雑なブラックボックスモデルを可読性の高い解釈可能なモデルで表現することで説明とする方法。
>   * 深層学習モデルやランダムフォレストのような決定木のアンサンブルなどの複雑なモデルを可読性の高いモデル、例えば単一の決定木やルールモデルで近似的に表現することでモデルの説明とする。
> 2. 局所的な説明
>   * 特定の入力に対するブラックボックスモデルの予測の根拠を提示することで説明とする方法。
>   * ある入力xをモデルがyと予測したときに、その予測の根拠を説明として提示する。

* 大域的な説明
  * ブラックボックスモデルに対して、似た結果を出せる可読性が高いモデルを作って、それで代わりに説明する
* 局所的な説明
  * 「このインプットをしたら、中でこういう処理がされて、このアウトプットが出ます」と説明する

## [機械学習における解釈性について](https://engineering.mercari.com/blog/entry/2019-12-24-070000/)

> * 大域的な説明を与えるアプローチ；どの特徴量が重要か、あるいは支配的なのかを知りたい
> * 局所的な説明を与えるアプローチ；ある入力対して各特徴量がどのように予測に寄与しているかを知りたい

* 大域的な説明
  * モデルとしてどの特徴量が効いてるのか、に注目
* 局所的な説明
  * インプットからアウトプットまでの途中経過、に注目

## [Interpretable Machine Learning](https://christophm.github.io/interpretable-ml-book/index.html)

### [5.6 Global Surrogate](https://christophm.github.io/interpretable-ml-book/global.html)

* 大域的な説明
* データセットに対するブラックボックスモデルの出力を、解釈可能なモデルで説明する

1. データセット準備
2. データセットに対して、ブラックボックスモデルで予測する
3. 解釈可能なモデルを選び、データセットを説明変数、ブラックボックスモデルの予測値を目的変数として学習する
4. 解釈可能なモデルで、ブラックボックスモデルを説明する。

### [5.7 Local Surrogate (LIME)](https://christophm.github.io/interpretable-ml-book/lime.html)

* 局所的な説明
* **ある入出力例の周辺の**ブラックボックスモデルの挙動を、解釈可能なモデルで説明する

1. ブラックボックスモデルの挙動を説明したい入出力例を選ぶ
2. 入力例の周辺で入力データのセットを作り、ブラックボックスモデルで出力データのセットを作る
3. 作ったデータたちに重みづけする（説明したい入力例に近いほど大きい数値）
4. 解釈可能なモデルで、入力データ・出力データのセットを学習する（重みづけを考慮する）
5. 作った解釈可能なモデルで、**入出力例周辺の**ブラックボックスモデルの挙動を説明する。

## なぜ解釈性が大事なのか

* 社会からの、ブラックボックスでは安易に信頼できない、という懸念の声
* [「AI開発ガイドライン案」](https://www.soumu.go.jp/main_content/000499625.pdf)での以下の要求。
  * 透明性の原則: 開発者は、AIシステムの入出力の検証可能性及び判断結果の説明可能性に留意する。
  * アカウンタビリティの原則: 開発者は、利用者を含むステークホルダに対しアカウンタビリティを果たすよう努める。
* サービスを提供する事業者としての説明責任
* 推論結果に対する社内外の関係者の理解
* モデルのデバッグ、精度改善

# 参考にしたサイト

* 人工知能学会：[機械学習における解釈性（Interpretability in Machine Learning）](https://www.ai-gakkai.or.jp/my-bookmark_vol33-no3/)
* [Interpretable Machine Learning](https://christophm.github.io/interpretable-ml-book/index.html)
  * [Chapter 5 Model-Agnostic Methods](https://christophm.github.io/interpretable-ml-book/agnostic.html)
  * [5.6 Global Surrogate](https://christophm.github.io/interpretable-ml-book/global.html)
  * [5.7 Local Surrogate (LIME)](https://christophm.github.io/interpretable-ml-book/lime.html)
* メルカリのエンジニア情報ポータルサイト：[機械学習における解釈性について](https://engineering.mercari.com/blog/entry/2019-12-24-070000/)
* [機械学習モデルの予測結果を説明するための力が欲しいか...？](https://pesuchin.hatenablog.com/entry/2017/01/07/170859)
[Swift][xcode12]「iPhoneアプリ超入門 Xcode 11 ＆ Swift 5で学ぶはじめてのスマホアプリ作成」レビュー

#前提
業務でObjective-cは触ったことありましたが、swiftは触ったことがなく、
作成したいアプリがあったので、swiftの基本的なことが学べる本を探してました。
いろいろ迷いましたが、結果として[こちら](https://www.nikkeibp.co.jp/atclpubmkt/book/20/P53910/)にしました。
簡単なレビューをしたいと思うので参考になればいいなと思います。
著書の中ではAPPストアに公開方法まで乗っていましたが、業務で経験済みのためそちらは見てません。
##自分のスペック
・基本的なIT、プログラムの知識あり
・Objective-cを業務で触ったことがあり、簡単な修正等ならば可能
##環境
・xcode12.2
著書の中ではxcode11が前提でしたが、xcode12.2でも基本的に問題がなく同様に進めることができました。
違いとしてはアトリビュートインスペクタ等のアイコンの違いくらいだった気がします。(慣れれば問題ない)

#レビュー
##内容に関して
内容に関して、最初はswiftでの画面の作り方、画面とコードの紐付け、
if文や変数について等のプログラムの基本的な内容からスタートして、
画面遷移の方法やUI描画処理等を用いて
最終的には簡単なクイズアプリを作成するものでした。

##レベルについて
内容で一部難しい部分(UIの描画処理等)はありますが、プログラムの基本的なことを学べたり、
難しいとこでも記載してあることを模写していけば見本と同じ形になっていくので、
初心者にはちょうど良い内容かと思います。
私にようにある多少業務でプログラムの知識がある人にしては少し簡単かもしれません。(私は簡単な本を探していたので問題はなかったですが)
個人的にはクイズの問題文をSQLite等を使用してデータを取得して表示のようなところまであるといいかなとは思いました。

#まとめ
これからアプリ作りたいプログラム初心者の方、難しい本では嫌だって方にはおすすめの内容になってると思います。
ECSのauto scalingとcapacity providersの違い

`AutoScaling` と `capacity providers` の違い。

## AutoScaling
ECSの`タスク数`を自動で増減させることができる。
サービスのCPUとメモリ使用率を含んだCloudWatchメトリクスを利用してスケールインとスケールアウトができる。
スケーリングポリシーとしては

- targetスケーリング
- stepスケーリング
- スケジュールスケーリング

がある。

▼リファレンス
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/service-auto-scaling.html

## capacity providers
クラスターに登録された`EC2インスタンス`を自動で増減できる。
EC2起動タイプの場合に用いられる。（FargateはそもそもサーバーレスなのでEC2の管理が必要ない）
autoScalingグループを利用できる。

`CapacityProviderReservation（CPR）`という値が用いられ、

```
CPR = 必要インスタンス数 / 利用可能インスタンス数 ✖️ 100
```

として計算される。
CPRの値に基づいてEC2インスタンスを増減させる。

▼リファレンス
https://aws.amazon.com/jp/blogs/news/deep-dive-on-amazon-ecs-cluster-auto-scaling/
AWS Lambdaのコア数を確認

2020年12月01日以降、
Lambdaで以下のアップデートが行われたことが発表されました。
・メモリ上限を10240MB（10GB）に拡大（従来は3008MB）
・vCPU数を上限6に拡大
・コンテナイメージのサポート

[AWS Lambda now supports up to 10 GB of memory and 6 vCPU cores for Lambda Functions](https://aws.amazon.com/jp/about-aws/whats-new/2020/12/aws-lambda-supports-10gb-memory-6-vcpu-cores-lambda-functions/)
[AWS Lambda の新機能 – コンテナイメージのサポート](https://aws.amazon.com/jp/blogs/news/new-for-aws-lambda-container-image-support/)

上記アップデートのうち、Lambdaで取り扱われるvCPUについて
Lambda内でCPU情報を取得し、どのようになっているか確認しました。

# 確認方法
コードはたったの5行です。
egrepで/proc/cpuinfo 内を検索してます。

```python
import subprocess

def lambda_handler(event, context):
    output = subprocess.run(['egrep','"|model name|processor|cpu family|model|physical id|core id|cpu cores|^$"','/proc/cpuinfo'], check=True, stdout=subprocess.PIPE).stdout
stdout=subprocess.PIPE).stdout
    res = output.decode('utf8')
    print(res)
```

【解説】
model name : CPUの名称
processor : プロセッサ番号
cup family : CPUファミリー番号
model : CPUのモデル番号
physical id : 物理番号（CPUソケットの数）
core id : CPUコアの番号
cpu cores : CPUコア数の合計



##CPU取得の取得結果
CPU情報を取得した結果の一部を掲載。
※色分けは単に見やすくするため

#### 赤枠で囲った部分（Lambdaのメモリが0.5GB）に注目　####
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/389667/a84dbe1f-2d90-8f2f-3a30-ed003ca5ce37.png)

* processorとcore idが同一になっている
* physical id が0だから、ソケット数は1コ
* 以上で1コアに対して1プロセス、つまり1コア1スレッド（1C1T）と判定可能<br>※core id が2行とも0だった場合は、1コアに対して2プロセス、つまり1コア2スレッド（1C2T）　になる 

* さらにcpu coresが2であるため、メモリ0.5GB時のCPUは2C2Tと判断できる。
* メモリ3GB（背景緑色部分）では、3C3Tになっていることがわかる。

上記の内容を、メモリ10GBまで確認しました。



## Xeonのうち、どのCPUか？
赤枠部分では、CPUの型番などがわかる。
Lambdaでは、下記CPUが動作している模様。※10GBまで同じ結果でした
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/389667/49ddc60f-f318-9bf9-e212-fe320baaaf12.png)

・ブランドはXeon
・ベースクロックは2.50GHz
・モデル番号（model）は63
・CPU族（cpu family）は6

ちなみに、下記サイトでcpu family 6 と model 63 で 検索したところ、
XeonのE、EPシリーズがヒット。
[WikiChip](https://en.wikichip.org/wiki/intel/cpuid#Big_Cores_.28Server.29)

さらにググったところ、これっぽいことが判明。
[Intel® Xeon® Processor E5-2680 v3](https://ark.intel.com/content/www/us/en/ark/products/81908/intel-xeon-processor-e5-2680-v3-30m-cache-2-50-ghz.html)
Haswell世代なので、Coreシリーズ（i3,i5,i7）の4000番台。2014年とかそのあたり。
AWSが使っているサーバをAMDのEPYCに更新して、余ったサーバが割り当てられているのかな？？？

##結論
最低2C2Tから始まり、最高で6C6Tになっていることがわかった。
確かにvCPU数が6まで拡大している。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/389667/e9f2707e-0e75-c1a8-c055-3d58ed287b1c.png)

##所感
確かにvCPUは6まで増加しているが、Lambdaはコンテナ内で動いているため、
実際の物理CPUがどう割り当てられているかは不明です。
仮にハイパースレッディングが有効であるなら
物理1コア = 2スレッドのため、次のようになります

2C2T = 物理CPU1コア
6C6T = 物理CPU3コア

AVX2もサポートされたとはいえ、以下の2点
・MAXでも物理3コア
・ベースクロックが2.5GHz（MAX 3.3GHz）と小さい
を考慮すると、
そこまでCPUパワーに依存しない処理に使うことが適切と思われます。

##参考
以下の記事を参考にさせていただきました。
[試験運用中なLinux備忘録・旧記事](https://kakurasan.hatenadiary.jp/entry/20110117/p1)
[AWS LambdaのCPUを見てみる](https://qiita.com/kurimoto/items/eca091cccc54d7c07634)
Google Chrome の JavaScript エンジン V8 って？ 

# はじめに
V8 エンジンは、Google のオープンソースで Javascript, WebAssembly のエンジンです。
V8 は、 C++ で書かれており、Google Chrome や Node.js で動いています。

# Javascript はどうやって動いているの？
V8 エンジンは、２つのコンポーネントで構成されています。

1. Meomry Heap（メモリの割り当てなど）
2. Call Stack(コードを実行するためのスタック)

Javascript から使える API （`setTimeout` など）には様々なものがありますが、これらは V8 エンジンから提供しているものではなく、ブラウザによって、提供されているものです。

## Call Stack
Javascript は、シングルスレッドで動くので、Call Stack もシリアルに動きます。

例えば、このようなコードがあるとします。

```javascript
function multiply(x, y) {
    return x * y;
}
function printSquare(x) {
    var s = multiply(x, x);
    console.log(s);
}
printSquare(5);
```

すると、以下のようにスタックされます。

![call stack.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659561/3db0671a-069b-6128-9f7c-f56bc1f77c99.png)

エラーが throw される場合もこの CallStack が使われているので、エラーを辿ることができます。

```javascript
function foo() {
    throw new Error('SessionStack will help you resolve crashes :)');
}
function bar() {
    foo();
}
function start() {
    bar();
}
start();
```
![スクリーンショット 2020-08-16 1.10.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659561/89535d09-3841-a9cd-5bf7-07655216ee3a.png)

また、無限ループの処理をする際は、このようになります。

```javascript
function foo() {
    foo();
}
foo();
```
![call stack 2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659561/05c46e58-08bc-95bd-c757-ebb069615eb8.png)

このエラーはシングルスレッドなので見つかりやすいですが、マルチスレッドになると少し複雑になります。しかし、その分シングルスレッドでの処理は遅くなってしまいます。

## 並行性とイベントループ
例えば、画像を変換する処理など時間がかかる処理をするプログラムがあった場合になかなか表示されないページを見たことがあるかもしれません。
その時はダイアログで警告されます。
![スクリーンショット 2020-08-16 1.24.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659561/c6794c84-af70-f05d-c53f-5e00024b8417.png)

こういったサイトは、UX 的にとても残念なページですね。

これを解消するために `asynchronous callbacks` を使った方法があります。

## TurboFan コンパイラ, Ignition インタプリタ
Javascript は、 JIT (just-in-time compile) で動作しているので、いくつかのトレードオフが存在します。

1. コンパイルして生成されたネイティブコードは、実行されるピーク時の速度が早い一方で、コードの量が多いほど、最初に実行されるまでに遅延が発生する。一方で、トランスレーターを使った場合は、実行されるまでの遅延は小さいけど、実行時の速度が遅い。
2. JavaScriptエンジンは、パフォーマンスを良くしようとするとメモリの消費量が多くなる。一方で、省メモリを進めようとするとパフォーマンスは悪化する。

これらを最適化するため、V8 では様々な改善が行われてきました。V8 のバージョン 5.9 までは２つのコンパイラが使われていましたが、現在では、TurboFan コンパイラ, Ignition インタプリタが使われています。
![スクリーンショット 2020-08-16 1.44.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659561/3d5533ad-e6f2-8546-b31e-182d658096d1.png)

### Ignition インタプリタ
中間コードを生成して実行するインタプリタ。メモリ消費が小さく動く、Fast Startupも最適という特徴があります。

* モバイルなどのメモリの小さな環境で動かすのに最適
* Startup Timeに最適化すべきコードの実行に向いている
* TurboFanと組み合わせることで、実行速度を最適化できる

### TurboFan コンパイラ
主として、最適化を行うことを目的としたコンパイラです。

使われ方としては、拡張的な感じになります。ただ、あらゆる新しいJavaScript機能に対応していき、その場合も活用されます。
WebAssembly のバックエンドでもあります。
最近はtry/catch/finallyとか、ES2015+の最適化が可能になりました。

# おわりに
V8 のコンパイラについては、いろいろと最適化が繰り返され、今のシンプルな形になっています。こうすることで管理しやすくしているのか思います。Web エンジニアとしては、V8 の仕組みはしっかり知っておきたいですが、まだまだわからないところも多いです。また、ガベージコレクションまでは書ききれませんでしたので、その辺はまた別の機会に書いてみたいと思います。

# 参考
https://v8.dev/docs
tscでトランスパイル後のTypeORMのパス問題に対処する

TypeScriptを用いたサーバーサイドの開発で、ORMとしてTypeORMを使っている人も多いと思います。TypeORMはモデルを設定ファイルや環境変数で指定されたパスから動的に読み込むことから、ts-nodeやts-node-devなどでTypeScriptのまま動かす場合とtscでJavaScriptにトランスパイルしてから動かす場合で、パスに差異が出て困ることがあります。

# 問題となるケース

`ormconfig.js`に設定を書く運用の場合を考えます。最初は公式ドキュメントを真似して以下のように書いていました。

```js:ormconfig.js
module.exports = [{
  name: 'default',
  type: 'mysql',
  host: process.env.MYSQL_SERVER,
  port: process.env.MYSQL_PORT,
  username: process.env.MYSQL_USER,
  password: process.env.MYSQL_PASSWORD,
  database: process.env.MYSQL_DATABASE,
  synchronize: true,
  logging: false,
  entities: ['src/entity/**/*.ts'],
  migrations: ['src/migration/**/*.ts'],
  subscribers: ['src/subscriber/**/*.ts']
}];
```

開発中はずっとts-node-devでTypeScriptのまま動かしていたのでこれで何の問題もなかったのですが、いざ本番環境向けにtscでトランスパイルしてみると、Repository Not Foundとかで全然動かない。

原因はすぐ察しがつく通り、`entities`や`migrations`や`subscribers`の指定が拡張子`.ts`になっていること。トランスパイル後は`.js`になるので、TypeORMはモデルを読み込むことができません。また`tsconfig.json`の内容次第ではディレクトリ構成も変わったりすることもあり得ます。

# 解決策

## 本番運用をts-nodeにする

正直これが一番手っ取り早い気がしています。起動さえしてしまえばトランスパイルする場合とパフォーマンスに大差はないという話もありますし。一応、今回の本題はこれではありません。

## ormconfig.jsの設定値を実行環境に応じて切り換える

こっちが本題です。まず、`ormconfig.js`をこんな感じにします。

```js:ormconfig.js
const commonConfig = {
  name: 'default',
  type: 'mysql',
  host: process.env.MYSQL_SERVER,
  port: process.env.MYSQL_PORT,
  username: process.env.MYSQL_USER,
  password: process.env.MYSQL_PASSWORD,
  database: process.env.MYSQL_DATABASE,
  synchronize: true,
  logging: false
};

const tsConfig = {
  entities: ['src/entity/**/*.ts'],
  migrations: ['src/migration/**/*.ts'],
  subscribers: ['src/subscriber/**/*.ts']
};

const jsConfig = {
  entities: ['dist/entity/**/*.js'],
  migrations: ['dist/migration/**/*.js'],
  subscribers: ['dist/subscriber/**/*.js']
}

if (process.env.TS_NODE) {
  module.exports = [{...commonConfig, ...tsConfig}];
} else {
  module.exports = [{...commonConfig, ...jsConfig}];
}
```

`package.json`の`scripts`をこうします。

```json:package.json
  "scripts": {
    "dev": "TS_NODE=true ts-node ./src/index.ts",
    "dev:watch": "TS_NODE=true ts-node-dev ./src/index.ts",
    "build": "npm-run-all clean tsc",
    "clean": "rimraf dist/*",
    "tsc": "tsc",
    "start": "TS_NODE= node ./dist/index.js"
  },
```

ts-nodeやts-node-devで動かす場合は`TS_NODE`に適当な値を設定して、nodeで動かす場合は`TS_NODE`を空にします。`ormconfig.js`では`TS_NODE`を見てモデルのロードパスを切り換えます。

`ormconfig`はJSONやYAMLなどで書くこともできますが、その場合ロジックが書けないのでJavaScriptで書く方が何かと便利です。

これを応用すると、例えば開発・ステージング・本番でDB周りの設定値を切り換えるといったことも比較的シンプルに実現できます。
[webpack]初回ビルド時に通知するプラグインを作ってみた！

## はじめに
webpackのビルド完了時に通知してくれるライブラリでwebpack-build-notifierなどがありますが、見た感じ初回ビルドのみはなかったので、今回はnode-notifierを使って、初回ビルド時に通知してくれるwebpackのプラグインを作ってみました！
webpackの簡単な設定などは済んでいる前提で進めていきます。

以下のサイトを参考にさせていただきました。
[node-notifier](https://github.com/mikaelbr/node-notifier)
[簡単な Webpack plugin を作成して Webpack と仲良くなる (ビルド時情報を console.log に表示する)](https://o296.com/e/%E7%B0%A1%E5%8D%98%E3%81%AAWebpackplugin%E3%82%92%E4%BD%9C%E6%88%90%E3%81%97%E3%81%A6Webpack%E3%81%A8%E4%BB%B2%E8%89%AF%E3%81%8F%E3%81%AA%E3%82%8B(%E3%83%93%E3%83%AB%E3%83%89%E6%99%82%E6%83%85%E5%A0%B1%E3%82%92console.log%E3%81%AB%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B).html)

## インストール
デスクトップ通知ができる、node-notifierをインストールします。

```zsh
## npm
npm install node-notifier

## yarn
yarn add node-notifier
```

## プラグインを作成
適当な名前でファイルを作ります。今回は`first-build-plugin.js`という名前にしました。

```js:first-build-plugin.js
const notifier = require('node-notifier');

module.exports = class FirstBuildPlugin {
  constructor() {
    this.is_build = false;
  }

  apply(compiler) {
    compiler.hooks.done.tap('FirstBuildPlugin', () => {
      if (!this.is_build) {
        notifier.notify({
          title: 'webpack',
          message: 'ビルドが完了しました！',
          sound: 'Ping',
        });
        this.is_build = true;
      }
    });
  }
};
```

- webpackでpluginを参照するときにapplyというのが実行されて、applyはcompilerを引数にとります。
- compilerからアクセスできるhooksで実行タイミングを設定することができ、doneはコンパイル完了時に呼び出されるhooksです。
- なので、その中にnode-notifierの通知の記述をしていますが、このままだとビルド時に毎回通知が来てしまうのでif文で初回のみになるようにしています。
- title,messageで通知のメッセージを、soundで通知オンを設定しています。他にもiconで画像を設定したりなどできます。詳しくはnode-notifierのgithubページを見てみてください。

## プラグインの読み込み

webpackの設定ファイルで読み込みます。

```js:webpack.config.js
// 〜　省略　〜　他のライブラリなどインポート
const FirstBuildPlugin = require('./first-build-plugin.js'); // ファイル名や場所によって変えてください

module.exports = {
// 〜　省略　〜　設定など
  plugins: [
    // 〜　省略　〜　他のプラグインなど
    new FirstBuildPlugin(),
  ]
};

// 〜　省略　〜
```

以下のコマンドを実行します。

```zsh
webpack --watch
```

<br/>
↓こんな感じで表示されます！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/697143/1e63af41-4b47-a4ac-8fb6-dedacbc93024.png)

## 終わりに
ここまで読んでいただきありがとうございます！この記事が少しでもお役に立てたら嬉しいです！
初回ビルドのみじゃなくて、毎回表示したりしたい場合は`webpack-build-notifier`ですぐ使えるのでオススメです。
webpack5が少し前にリリースされたので見ていきたいですね〜
投稿を削除する時にアラートを表示させる

##使用環境

ruby 2.6.5 
rails 6.0.0

##目標
投稿した記事を削除する際にアラートを表示させる。

##実装
ポートフォリオなどを作成するときに削除ボタンを作ることがあるかと思います。僕の場合はこちらですね↓

```ruby
<%= link_to '削除', song_path, method: :delete, class:'song-destroy',data: {confirm: "本当に削除しますか？"} %>
```

大切な箇所はこの　data: {confirm: "本当に削除しますか？"}　の部分です。
これをつけるだけで削除するときに確認のアラートが表示されるようになります。（タブだらけなのは気にしないでください笑）

![スクリーンショット 2020-12-05 17.39.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/927542/a9157357-0d95-65da-715d-85ca6670b3c9.png)
簡単に実装でき、ユーザーが使う際に必須の機能ですが初学者の方でつけてない人をたくさん見かけたので記事にしました。

##以上です!
初めてQiitaに投稿したので慣れてないことだらけなのですがとりあえず簡単な記事から投稿させていただきました。自分が疑問に思ったことやポートフォリオ作成で学んだことなどたくさんアウトプットしていこうと思います。
Action Cableを使用したリアルタイムチャットで投稿者の名前を表示させる

---
Action Cableを使用したリアルタイムチャットで投稿者の名前を表示させる方法についてのまとめ。
メッセージの投稿機能はできたが、誰が投稿したものか分からないため投稿者の名前を表示させたい人のために書きました。

##Action Cable の大まかな仕組みの説明
Action Cableは、通常のRailsのアプリケーションと同様の記述で、即時更新機能を実装できるフレームワークです。

実装内容
・メッセージの保存や送信に必要なRubyのコーディング
・保存したメッセージを即時に表示させるJavaScriptのコーディング


### Channel（チャネル）とは？
即時更新機能を実現するサーバー側の仕組みのこと。
メッセージを即座に表示させるために、データの経路を設定したり、送られてきたデータをクライアントの画面上に表示させるJavaScriptを記述したりします。
これらの役割をChannel（チャネル）が担っています。


![Action Cableの仕組み図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/923115/20459e14-f56d-d384-3b89-5e6aa05ef974.png)
※画像（TECH-CAMP）


####チャネルを作成すると作られる2つのファイル
 1.message_channel.rb と 2.message_channel.js


1.message_channel.rb はクライアントとサーバーを結びつけるためのファイル
stream_fromメソッドを使用して結びつける。MVCでいうところのルーティングの機能。


stream_fromメソッドで関連付けられるデータの経路（図：ピンク色の←の部分）のことを、broadcast （ブロードキャスト）と呼びます。
メッセージの保存が成功したときに、broadcastを介してメッセージが送信されるように◯◯◯_controller.rbに記述します。


2.message_channel.js はサーバーから送られてきたデータをクライアントの画面に描画するためのファイル
## 投稿内容と投稿したユーザーを紐付ける

#####message_channel.rbに stream_from "message_channel" でクライアントとサーバーを結びつけていること前提。

```
class MessageChannel < ApplicationCable::Channel
  def subscribed
    stream_from "message_channel"
  end
```

message_params にログイン中のユーザーidをマージさせる。
current_userを@userというインスタンス変数に代入してbroadcastを介して、user: @userのデータが送信されるようにする。


#####controller.rbに記述

```
def create
    @message = Message.new(message_params)
    @user = current_user 
    if @message.save
      ActionCable.server.broadcast 'message_channel', content: @message, user: @user
    end
  end


  private
  def message_params
    params.require(:message).permit(:text).merge(user_id: current_user.id)
  end
```

## 投稿内容と投稿者の名前、投稿日時を表示させる

#####message_channel.js にクライアントの画面上に表示させる記述を行う。
受け取った情報は、receivedの引数dataに入ります。
表示に関してはhtmlの部分の記述。

＊ 私は見やすいように名前はspan要素を使って括弧で囲んで、p要素でメッセージ名前と投稿日時の下に来るように段落を作っています。

```
received(data) {
    const html = `<p><span>【</span>${data.user.name}<span>】</span>${data.content.updated_at}</p>
                  <p>${data.content.text}</p>`;
    const messages = document.getElementById('messages');
    const newMessage = document.getElementById('message_text');
    messages.insertAdjacentHTML('afterbegin', html);
    newMessage.value='';
  }
});
```
イメージはこんな感じになります。
![Qiita 資料.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/923115/c689b454-fbd0-bcd4-f8f3-9ce7a34b78c0.png)


#まとめ
今回Action Cableを初めて使って、リアルタイムチャットアプリを作成しました。
個人的にはコントローラーの記述が難しかったですが、一度使い方や流れを理解できると名前や日時だけでなくいろいろなデータを結び付けて表示させることができると思いました。


リロードすると表示の形が変わってしまう点の改善や無限スクロール機能がまだできず勉強中です。
市場価値の高めなITエンジニアの特徴２選【結論：技術力か思考力です】

<br>
「市場価値の高いITエンジニアの特徴って何か種類があるの？」

結論、2種類の特徴があります。

今回は現役のエンジニアから聞いた情報で、市場価値の高いITエンジニアの特徴について、ご紹介しようと思います。

最後まで読んでみて、もし良いなと思ったら、記事を書く励みになるので、ぜひLGTMをお願いします！
<br>
<br>

## 2種類の市場価値の高いITエンジニア
冒頭でもお伝えしましたが、市場価値の高いITエンジニアは、概ね２種類の特徴に集約する事ができると言われております。

先日僕がツイートした内容がこちら。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">【２種類の高単価エンジニア】<br><br>エンジニア歴30年以上でフリーランスの方が言われていたことで、高単価なエンジニアは下記のどちらか。<br><br>・GAFA並の圧倒的な技術力<br>・ユーザ視点に立てる思考力<br><br>未経験なら、まず後者を目指すべきとのこと。<br><br><a href="https://twitter.com/hashtag/%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E8%BB%A2%E8%81%B7?src=hash&amp;ref_src=twsrc%5Etfw">#エンジニア転職</a><br><a href="https://twitter.com/hashtag/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0?src=hash&amp;ref_src=twsrc%5Etfw">#プログラミング</a><br><a href="https://twitter.com/hashtag/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E5%88%9D%E5%BF%83%E8%80%85?src=hash&amp;ref_src=twsrc%5Etfw">#プログラミング初心者</a></p>&mdash; yuki｜IT転職に向けたリアルな活動を発信｜元トップ営業マン(訪販)→未経験からエンジニア転職へ (@yukifullstack) <a href="https://twitter.com/yukifullstack/status/1332603416502124545?ref_src=twsrc%5Etfw">November 28, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

上記のツイートで書いてある通り、市場価値の高いITエンジニアは、以下どちらかの特徴を有してるとの事。

<ul>
  <li>GAFA並の圧倒的な技術力</li>
  <li>ユーザ視点に立てる思考力</li>
</ul>

これが結論です。
<br>
<br>


### GAFA並の圧倒的な技術力
まず1つ目の特徴にですが、そもそもITエンジニアとは、プログラミング言語を扱う能力や、サーバやネットワークなどのインフラ構築など、ある程度の専門知識が必要な技術職なります。

となれば、必然的に幅広い知識や経験を持ち、技術力のあるITエンジニアは、業界的に見ても貴重な人材となり、評価が高くなります。
<br>

「じゃあGAFA並の圧倒的な技術力って、どのくらいの事を言ってるの？」

まずGAFAとは、以下の企業の総称になります。

<ul>
  <li>G：Google</li>
  <li>A：Amazon</li>
  <li>F：Facebook</li>
  <li>A：Apple</li>
</ul>

要するに、GAFA並の圧倒的な技術力とは、これらの時代を牽引している企業でも充分通用するほどの技術力を指します。

技術力を求められるIT業界に置いて、そのような技術力があるITエンジニアは、まず間違いなく市場価値が高いエンジニアとして挙げられます。
<br>
<br>

### ユーザ視点に立てる思考力
そして2つ目の特徴は、実は技術力云々ではなく、思考力の話になります。

これは未経験のITエンジニア転職においても、求められる力の1つなのですが、要はユーザに寄り添った機能の実装や、アイディアを考えられる人は、市場価値が高いITエンジニアと言われてるようです。
<br>

>例えば日本では、コストがどれだけ安く抑えられる画期的なアプリを開発したとしても、そもそも現状で使用しているエクセルなどのシステムなどから、移り変わりたくないと言う人が、一定数おられます。
<br>
そう言う方たちに対して、「じゃあコストの削減をしつつ、見た目は今と変わらないようなシステムはどうですか？」などと、ユーザに寄り添った機能の提案ができるITエンジニアは、顧客にも満足してもらいつつ、自社の売り上げを向上させる事にも繋がりやすいので、必然的に市場価値も高くなります。

<br>

技術の移り変わりが激しく、日々学習や新しいことをしているITエンジニアの人からしたら、このような非論理的な思考を持つ人の事は、ある意味、理解しにくくなると考えられます。

しかし、あえてそこでユーザの視点に立ち、ユーザの求める形での提案を考えられる思考力を持つ人は、逆に希少性も出てくるので、市場価値が高いと言えます。
<br>
<br>

## まとめ
以上がITエンジニアにおける、市場価値の高い人の特徴になります。もし未経験でこれからIT転職を目指している方であれば、**ユーザ視点に立てる思考力**は割とすぐに身に付けられると思うので、オススメかと思います。

最後まで読んでいただき、ありがとうございました！
<br>
<br>
<br>

筆者：yuki｜IT業界のリアルな転職事情など発信｜元トップ営業マン(訪販)→未経験からエンジニア転職へ
Qiita：https://qiita.com/yuki4839
Twitter：https://twitter.com/yukifullstack
<br>
Visual Studio Code(Windows版)でspring bootのセットアップ

## はじめに

Windows10でVisual Studio Codeでspring boot用の設定を行った時のメモをシェアします。

OS: Windows10
Visual Studio Codeのバージョン：1.51.1

※Visual Studio Codeは日本語化した状態で操作してます。
日本語化する方法は[こちら](https://qiita.com/aoyaman/items/28f962650637ca64c4cf)。

## Java Extension Pack をインストール

### 拡張機能の画面を開く
![vscode_拡張機能画面を開く.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150699/e0f3489e-33f8-acbb-bf0f-55946e69d03a.jpeg)

### "Java Ex"と入力

"Java Ex"まで入力すると Java Extension Packが表示されるので選択する
![vscode_java_extension_pack.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150699/3b6fa0b7-bdb6-8f5e-75e0-45ade7454da3.jpeg)

### install する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150699/3de80362-bb61-57c6-4ffa-31232d2b40d9.png)

↓

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150699/fc2a735e-20a0-434e-ccca-63052abc1c07.png)

インストールボタンがアンインストールに変わったらインストール完了。

Packなので、いくつかの機能がインストールされました。

## Spring boot Extension Pack をインストール

### "spring boot"と入力

"spring boot"と入力すると「Spring Boot Extension Pack」が表示されるので選択する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150699/51a86f7c-ed4c-dbca-7587-7345af632261.png)

### installする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150699/5d5a53ac-b1cb-73e5-6453-4d0ea403c022.png)
↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150699/89047716-151b-e661-c51b-d1408c948205.png)

インストールボタンがアンインストールに変わったらインストール完了。
こいつもPackなので、いくつかの機能がインストールされました。

## おわりに。

上述の「Java Extension Pack」と「Spring Boot Exteion Pack」の２つをインストールするだけで良いのは楽ちんですね。
（ほんとは １つのPackになってるのも欲しいけど）

次は、実際にSpring Bootのプロジェクトを新規作成したり、GitからCloneしてきたりしようと思います。

おわり。
Sequel Aceを使ってDocker＆MySQL環境でデータベース接続に失敗した話

こんにちは、JeffTechです。

# この記事で実現できること
- Docker＆MySQL環境でSequel Aceを接続する

# 開発環境
- Sequel Ace
- Dokcer
- MySQL
- Laravel
- PHP

# 説明
Dockerを使用してMySQL環境を構築した人の中で、正攻法で「Sequel Ace」に接続できなかった人が、この記事読むことで「Sequel Ace」を使用してMySQLをGUIで操作できるようにできるようになります。

# 実装の流れ
1. docker-compose.ymlの編集
1. docker-compose up -d
1. Sequel Aceの設定

# 実装
## docker-compose.ymlの編集
正攻法で「Sequel Ace」に接続できなかった場合、ポート番号が悪さをしている可能性大です。
なので、docker-compose.ymlを編集して、ポート番号の変更をしていきます。

```yml:docker-compose.yml
version: "3"
services:
    mysql:
        container_name: MySQLのコンテナ名
        image: mysql:5.7
        environment:
            MYSQL_ROOT_PASSWORD: パスワード
            MYSQL_DATABASE: データベース
            MYSQL_USER: ユーザー
            MYSQL_PASSWORD: パスワード
        ports:

            - "4306:3306" //ここを変更

        volumes:
            - mysql-data:/var/lib/mysql
```

ローカル環境で開発している時は、ローカルのポート番号３３０６番でMySQLを使用しているかと思います。
なので、今回はローカルのポート番号４３０６番を３３０６番と繋ぐように設定しました。

## docker-compose up -d
`docker-compose.yml`の変更が終わったら、念の為サービスを終了させましょう。

```bash:ターミナル
$ docker-compose stop
```

それでは、`docker-compose up`でコンテナを起動させましょう！
いつもコンテナを起動しているコマンドを使用してくださいね！

```bash:ターミナル
$ docker-compose up -d
```

## Sequel Aceの設定
ここまでできたら、最後はSequel AceでMySQLに接続をしましょう！
Sequel Aceのインストールが終わっていない人は下記からインストールをお願いします。
https://apps.apple.com/us/app/sequel-ace/id1518036000?mt=12

Sequel Aceを開くとこのような感じになってます。
![スクリーンショット 2020-12-05 17.19.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658326/afef1e42-aedd-d177-b5c2-8c23f2768c9f.png)

なので、先程設定したポート番号等を下記の画像を参考にしながら入力していきます。

- Name: 任意の名前を付けましょう！
- HOST: 127.0.0.1
- Username: MySQLへ接続するためのユーザー名（Laravelの場合.envに記述しています）
- Password: MySQLへ接続するためのパスワード（Laravelの場合.envに記述しています）
- Database: 今回は入力しません！
- Port: 4306

![スクリーンショット 2020-12-05 17.20.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658326/75b65798-e06d-17be-c349-50e06b594c07.png)

画像のように`Add to Favorites`をクリックすると、次回から左上のFAVORITESに設定が保存されるので、接続が楽になるのでぜひお気に入り登録しておきましょう！

最後にConnectをクリックすれば、接続できるはずです。

# 最後に
少しでも役に立った！という時は、いいねをポチッとして
フォローしてくださると嬉しいです、、、笑

役に立たなかった時は、怒らないでコメント頂けますと幸いです笑

Twitterもやってますので、よかったら見てみてくださいね！
https://twitter.com/jefftechsaku
VPNを複数接続したときのルーティング設定

[株式会社シンプルウェイ Advent Calendar 2020](https://qiita.com/advent-calendar/2020/simpleway) の5日目です。

サーバーへのアクセスできる回線が限定されている場合に、それをクリアするためによくVPNが使われます。

シンプルウェイでもテレワーク中に社内サーバーにアクセスするためにVPNを使いますし、接続元IPを固定化するためにインターネット上のVPNサーバーへ接続したりします。

ところで、VPNを多用しているとルーティングがごちゃごちゃになって、VPNにつないでいるのに目的のサーバーにアクセスできないってことも起こります。

特にWindowsビルトインのVPN(L2TP/IPsecやSSTPなど)では、何も考えずに接続するとデフォルトゲートウェイがVPNになるので、インターネットへの通信などほとんどの通信が最後に接続したVPNを経由するようになってしまいます。

これを回避するためには自分でルーティングを設定してあげる必要があります。どのサーバーへの通信が、どこのVPNを通るかを整理してあげれば良いわけです。

## VPN事例

例えばこんな接続を行いたいとします。

![VPN接続例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/219010/9430c0c1-77f4-7a21-eba8-feff276024fd.jpeg)

* インターネットへの通信はVPNを経由しない
* 会社の社内サーバーへの通信はVPN1を経由する
* example.comサーバーへの通信はVPN2を経由する

これを実現するためには下記のように設定します。

## (1) VPNのデフォルトゲートウェイ設定を外す

まずVPNのデフォルトゲートウェイ設定を外しましょう。

* Windowsキー+Rキーを押して「ファイル名を指定して実行」を起動
* 「control ncpa.cpl」を入力してコントロールパネルのネットワーク接続を開く
  ![ファイル名を指定して実行](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/219010/c6c4e73a-df47-9a79-6650-0f2b175b47b7.png)

* VPN接続用のネットワークアダプタを選択して、右クリックメニューからプロパティを選択
  ![VPN接続のプロパティ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/219010/c92d3858-a10e-30f4-7d0f-b9b9f367e140.jpeg)

* 「インターネット プロトコル バージョン4」を選択
* 「プロパティ」ボタンを選択
* 「詳細設定」ボタンを選択
* 「リモートネットワークでデフォルトゲートウェイを使う」のチェックボックスをOFFにする
  ![リモートネットワークでデフォルトゲートウェイを使う](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/219010/c97a8b6e-e4a2-2b53-c0c1-28ec90f703dc.jpeg)

ここまでの設定で事例の「インターネットへの通信はVPNを経由しない」「会社の社内サーバーへの通信はVPN1を経由する」が実現できています。

VPNを接続してもインターネットへの通信は通常通り手元の回線を通っていきます。

またVPN1が接続状態の場合、手元のPCに192.168.50.0/24のセグメントのIPが割り振られているので、社内LANへの通信は自動的にVPNの回線を通っていきます。

## (2) 特定IPへの通信をVPN経由にする

次に特定のサーバーへの通信はVPNを通るように設定します。

* スタートボタンを押して「cmd」を入力
* コマンドプロンプトを右クリック
* 「管理者として実行」を選択  
  ![コマンドプロンプト](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/219010/301d6eef-c6a4-24a4-1ccc-cfe777548fa0.jpeg)
* `route add [サーバーIP]/32 [ゲートウェイIP]` を入力して実行  
  事例の場合 `route add 203.0.113.1/32 192.168.100.1`
  ![route addコマンド](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/219010/4de482f2-2de0-8c3d-3df6-70ab1d7d1186.jpeg)

これでexample.comへの通信はVPN2を通るようになります。

サーバーが複数ある場合は、同様にルートを追加していけばOK、VPNが複数ある場合はゲートウェイを変えて同様にルートを追加していけばOKです。

-----

これであなたもルート設定自由自在。VPN接続がいくらあっても大丈夫!

なお、設定は自己責任でお願いします。管理者権限が必要な通り、PCの動作に影響を及ぼす操作です。もし通信がおかしくなってしまったら再起動しましょう。リセットされます。

※ シンプルウェイのスタッフで上記設定が可能なのはBYODの人だけです。会社貸与PCは管理者権限がないので設定不可です。
業務SEなあなたにFigmaのススメ

## はじめに

業務アプリといえばVB6やMFCで作られたバタ臭いUIのツールだったのが25年くらい前？
それはダサいなと、.netでWinFormsが登場したのが20年くらい前？
WPFやxamlがひっそりと流行らなかったりしつつ、とにもかくにも「業務アプリはおしゃれである必要はない」という謎の常識があったように思う。
そんな時代の画面定義と言えば、Excel方眼紙に罫線で描いたUI≒完成品のUIであったので、業務SEはデザインなど意識することなく三種の神器（ワード、Excel、パワポ）さえ使えてればよかった。

時は流れて2020年。

スマホが普及しTikTok, Instagram を始めとするモバイルアプリや、AmazonやNetflixの様なWebサービスなども登場し、一般の人々が**優れたUIのサービス**を利用することが当たり前となった。
これにより、業務アプリもWebサービスとして提供される事が多くなり、BtoCとBtoBの境目が曖昧になり**業務アプリが使いづらい**ことに疑問を持つ人々が現れてしまった。（たぶん）

よって、BtoB業務アプリを作っている企業でもそれなりのデザインの業務アプリを開発することが必要になってくるが、デザイナーを雇うのは以下の理由により難しい。

* デザイン必須の案件がない/取りに行かない（にわとりたまご問題）
* プログラマとデザイナは人種が違うので、１人だけ雇っても継続しない（めちゃくちゃいずらい）

であれば、業務SEのあなたに**「もっといい感じの画面デザインをするように」**と命令される未来が来るのは想像に苦しくないと思う。
しかし、パワポやExcelでいい感じのUI/UXデザインをするのは、**2030年にガソリン車販売が廃止になるのに、超ハイスペックなガソリン車を頑張って金型から作るようなこと**だと思う。
今するべきは電気自動車を作ることではないだろうか。すなわち今までのやり方を捨ててでも、新しく効率がよく、世界から受け入れられる方法を採択することではないだろうか。

## Figma の紹介プレゼン資料をつくってみた

前置きが長くなりましたが、ようやくFigma触りました。
bootstrap のUI Kit を使って画面デザインをしたところ、Excel方眼紙の1/2ぐらいの工数で作れる様な感触がありました。
似たような設定画面が大量にある場合はもっと工数が減ると思います。

プレゼン資料も作れないかと調べたら、プレゼンテーション用のテンプレがあったので作ってみました。

![01_タイトル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136165/80c2b87c-9506-0050-2698-eb0870451ee9.png)
![02_背景.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136165/270732dc-22ec-b170-361b-a106f001809f.png)
![03_Why Figma.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136165/a3f9b903-8c60-704a-3ecb-3dc8af4ea46b.png)
![04_How to start.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136165/deedb02b-2775-855a-f21e-251d2d58c842.png)
![05_Get templates.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136165/769304e2-3bbe-ae4b-a704-6d05ee8bc9b2.png)
![06_Figmation.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136165/c3a8ae4f-0031-4c45-cd66-923ad742e392.png)
![07_ショートカットキー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136165/190f3ec9-117c-bd5c-a2ed-ed5b73c16f14.png)

## おわりに

雑にfigmaでプレゼン資料を作りましたが、パワポより垢抜けた資料が簡単に作れたと思います。
Autolayout, constraints あたりで苦しむ可能性はありますが、慣れれば生産性が大きく向上すると思います。
もはや**DXによる働き方改革**と言ってもいいのではないでしょうか。
Yarnについてまとめ

#Yarnとは？

- 2016年にFacebook社からリリースされたパッケージ管理ツール

- Node.jsのデフォルト搭載のnpmの代替となるツール


なぜあえてnpmでは無くYarnが使われるのでしょうか？

# Yarnのメリット

- 並列処理によりインストールが高速 

- yarn.lockファイルによる厳密なモジュールのバージョン管理
  - （yarnリリース当初、npmにはpackge-lock.jsonファイルが無かった）

- npmとの互換性
  - npmと同じpackage.jsonが使える

  
#npmとyarnの主なコマンドの違い

##package.jsonの作成

```:npm
npm init
```

```:yarn
yarn init
```

##依存パッケージのインストール

```:npm
npm i
```

```:yarn
yarn
```

##新規パッケージのインストール

```:npm
npm i <パッケージ名>
```

```:yarn
yarn add <パッケージ名>
```

##パッケージのグローバルインストール

```:npm
npm i <パッケージ名> -g
```

```:yarn
yarn global add <パッケージ名>
```

##パッケージのアンインストール

```:npm
npm uninstall <パッケージ名>
```

```:yarn
yarn remove <パッケージ名>
```

##**scriptsのスクリプト実行**

```:npm
npm run <スクリプト名>
```

```:yarn
yarn <スクリプト名>
```
Serverless FrameworkでLambdaにGraphQL APIを立てる

基本的にはこちらを参考にしました。
How to Make a Serverless GraphQL API using Lambda and DynamoDB
https://www.serverless.com/blog/make-serverless-graphql-api-using-lambda-dynamodb

ただし、イベントハンドラを```async```関数にしたり、GETリクエストではなくPOSTリクエストを受け付けるようにしています。
また、上記では、```GraphQLSchema()```などを使っていますが、スキーマの定義などに関しては、GraphQL.js公式ページを参考にしました。
Getting Started With GraphQL.js
https://graphql.org/graphql-js/

あれ、「How to Make a Serverless GraphQL API」の方、ほとんど参考にしてない？笑

## 結論
特に難しいことはなく、POSTリクエストで送った値を```event.body```から取り出して、```graphql()```の第二引数に渡すだけ。

## コマンドやコード
```
$ sls create -t aws-nodejs-typescript -p sample-graphql-lambda-api
$ yarn init -y
$ yarn
$ yarn add graphql
```

```ts:serverless.ts
// 下記追加
// その他、region(ap-northeast-1など)を追加するのを忘れずに。
  functions: {
    query: {
      handler: "handler.query",
      events: [
        {
          http: {
            method: "post",
            path: "graphql",
          },
        },
      ],
    },
  }
```

```ts:handler.ts
//import { APIGatewayProxyHandler } from "aws-lambda";
import "source-map-support/register";
import {
  graphql,
  buildSchema
} from "graphql";

const schema = buildSchema(`
  type Query {
    hello: String
  }
`);

const root = {
  hello: () => {
    return "Hello world!";
  },
};

export const query = async (event) => {
  const query = event.body;
  const result = await graphql(schema, query, root);
  const response = {
    statusCode: 200,
    body: JSON.stringify(result),
  };
  return response;
};
```

```
$ curl --request POST --header "Content-Type: application/json" --data "{ hello }" '{Lambda関数のエンドポイント }}'

{"data":{"hello":"Hello world!"}}
```

おしまい。

## [番外編]リゾルバーで引数を取り出す時の```{ person }```ってなんだ？

引数を足したり、複数のデータを返す場合。

```ts:handler.ts
const schema = buildSchema(`
  type Query {
    hello(person: String): Text
  }
  type Text {
    text1: String,
    text2: String
  }
`)

const root = {
  hello: ({ person }) => {
    return { text1: `${person}さん、こんばんは!!!!!!!!!!`, text2: "おはようございます" }
  }
}
```

```
$ curl --request POST --header "Content-Type: application/json" --data "{ hello(person: \"tarou\"){text1 text2 }}" '{Lambda関数のエンドポイント }'

{"data":{"hello":{"text1":"tarouさん、こんばんは!!!!!!!!!!","text2":"おはようございます"}}}
```

```root```オブジェクトにクエリごとに設定する関数で引数を取り出す時、なんで```person```ではなく```{ person }```なのかと思っていた。

これはJSの記法で、分割代入らしい。

>var origin = {a:1, b:2, c:3};
var {a} = origin;
var {b} = origin;
var {c} = origin;
console.log('a = ' + a);  // a = 1
console.log('b = ' + b);  // b = 2
console.log('c = ' + c);  // c = 3
[JavaScriptの変数名が中括弧で囲まれた変数宣言](https://qiita.com/takahiro_itazuri/items/1016494c2e3b815cbe6d)

オブジェクトから```{}```の中で指定したプロパティの値を取り出して、それを同名の変数に代入してるらしい。
つまり、```root```オブジェクトでクエリごとに割り振る関数の引数には、オブジェクトが渡されているらしい。
→そういえば、```curl```でも、```--data "{ hello(person: \"tarou\"){text1 text2 }}"```という感じで、```person```keyを渡していたんだった(これがないとエラーになる)

ちなみに、「```root```オブジェクトでクエリごとに割り振る関数」は'resolver function'というらしい。

>// The root provides a resolver function for each API endpoint
var root = {
  hello: () => {
    return 'Hello world!';
  },
};
[Getting Started With GraphQL.js](https://graphql.org/graphql-js/)

番外編が長い。
別途、AppSyncってなんだ？GraphQL使うなら、API Gatewayじゃなくてこっち使った方がいいのかな。