OmniAICreator/Qiita-1.07M huggingface dataset:
[Oracle Cloud] oci cliをupdate (python2→3) するときは、LANGに注意することを学んだ

# 背景

とあるOracle Cloudを利用している社内サービスにて、運用自動化のためにoci cliを使ってスクリプトを作成していた。

oci cliを導入した時期が微妙なタイミングで、Python 2.x系で利用。
その後、Python2系のデサポートを知ったため、本番利用される前にPython 3系にアップデートしとこうと思い立つ。

Python3系へのアップデートは、以下の記事を参考にさせていただきました。
・[7系LinuxにPython3＋OCI CLIをインストールする&2020/2/13以降はOCI CLIがサポートするPythonのバージョンが3.5+になる件](https://qiita.com/yamada-hakase/items/2b4f33710d8ee41ab420)

やったことは以下の2コマンドだけ。とても簡単。

```
※ 念のため前バージョンのディレクトリを退避後に実施

# sudo yum install -y python3
# bash -c "$(curl -L https://raw.githubusercontent.com/oracle/oci-cli/master/scripts/install/install.sh)"
```
oci cliの単体動作は問題なさそうだった。

# 何が起きたか
oci cliの単体動作は問題なかったが、スクリプト実行時に以下のエラーが出るようになってしまった

```
Traceback (most recent call last):
  File "/home/oci/bin/oci", line 8, in <module>
    sys.exit(cli())
  File "/home/oci/lib/oracle-cli/lib/python3.6/site-packages/click/core.py", line 722, in __call__
    return self.main(*args, **kwargs)
  File "/home/oci/lib/oracle-cli/lib/python3.6/site-packages/click/core.py", line 676, in main
    _verify_python3_env()
  File "/home/oci/lib/oracle-cli/lib/python3.6/site-packages/click/_unicodefun.py", line 118, in _verify_python3_env
    'for mitigation steps.' + extra)
RuntimeError: Click will abort further execution because Python 3 was configured to use ASCII as encoding for the environment.  Consult http://click.pocoo.org/python3/for mitigation steps.
```

# 原因
調べた結果、スクリプト内の環境変数設定でLANG=Cを明示指定していたことが原因だった。
詳しくは調べ切れていないが、Python3から標準出力のエンコーディングが環境変数LANGに依存するようになったらしく、LANG=Cで実行すると上記のエラーが発生するようだ

LANG=en_US.UTF-8に変更したらエラーがでてこなくなった。このエラー以外は問題なく使えている。
本番環境のMySQLをターミナルで見やすくする

本番環境でちゃんとデータ入力出来てるかな〜って時にだいたい使うのが

```
select*from users
```

このクエリの結果表示されるデータはMySQLの要素が多いとごちゃごちゃに出てきます。

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

こんな感じで。


# うぉおおおん　見辛い！　見づら過ぎる！

この問題を解決したいと思います。

やり方は簡単です。

MySQLクエリの最後に　\Gをつけてあげる

```
select*from users\G;
```

すると

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

# 見やすい！　Beutiful!

ということで　\Gをつけてみましょう　というお話でした。
(ちなみにMacでの\は　option+¥です)
実践WPFアプリ設計と実装 -- 設計とビュー以外実装編

# 初めに

内容は連載予定です。

- 設計とビュー以外実装編(本記事)
- ビュー実装編(執筆予定)

教材を元に振り返り解説していきます。

# 誰向けの記事か？
- 気軽にWPFアプリを作れるようになりたい方
- 程よい規模のWPFアプリのソースコードを参考にしたい方
- MVVM入門してみたが身につかなかった方


# 教材

## [JitPad](https://github.com/YoshihiroIto/JitPad)  
解説用に用意したアプリではなく実用しているアプリを元に解説します。
C#コードを逐次逆アセンブルしx64コードを表示するアプリです。使うだけなら本記事の内容の理解は必要ありません。[こちら](https://github.com/YoshihiroIto/JitPad/releases)からダウンロードしてご利用ください。

このコミットを元に解説していきます。
https://github.com/YoshihiroIto/JitPad/tree/8315f7fda1857e0403f13e863e83f2a321c3f062

### アプリ動作イメージ
<img src="https://github.com/YoshihiroIto/JitPad/raw/master/JitPad.gif" width="800px">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17966/93bf649e-8cf3-5710-4579-6ad7596bda34.png" width="800px">


# 設計

問題領域の整理把握と問題領域内オブジェクトの洗い出しを行いました。
初期段階で完璧なものを用意するのは現実的ではなく、ある程度のものができれば一歩前進です。


## 問題領域

```
「C#コード」を受け取り「結果（x64コード）」を出力
```
問題領域はこれだけです。そしてこれがユーザー観点の目的です。  

他は外野。例えばGUI実装が代表的な外野領域です。***GUIアプリだといっても問題領域にGUIは含まれない***。

大事なことは問題解決そのものに最大限の価値を置くこと。ユーザー観点目的を最大限の価値に置くと最終的なアプリの仕上がりに差がでます。

## 一方通行関係

外野は問題領域に依存しているけど問題領域は外野に依存しない、一歩通行関係。

問題領域内のオブジェクトは問題解決のために尽力できなければいけない。
***問題領域解決するのが目的、だから問題解決に全力を務める。外野は邪魔しない、文句言わない！***

一歩通行ではなくお互いに関係を持つとどうなるでしょう。
自身変更時に依存先を考慮、依存先は自身に依存している、で自身を再調整して・・・。収拾つかない、巨大な泥団子の出来上がりです。



## 問題領域内のオブジェクトたち

問題領域を解決するにあたり、複数オブジェクトの連携が必要です。
オブジェクト間も闇雲に依存するのではなく一方通行関係を作ります。理由は同じくです。


# 実装

名前空間 [JitPad.Core](https://github.com/YoshihiroIto/JitPad/tree/8315f7fda1857e0403f13e863e83f2a321c3f062/JitPad.Core) 内のクラスが問題領域を扱います。
問題領域の解決には複数オブジェクトが連携して行われます。


## 主要クラスと役割

- [AppCore](https://github.com/YoshihiroIto/JitPad/blob/8315f7fda1857e0403f13e863e83f2a321c3f062/JitPad.Core/AppCore.cs) アプリ実態
- [Config](https://github.com/YoshihiroIto/JitPad/blob/8315f7fda1857e0403f13e863e83f2a321c3f062/JitPad.Core/Config.cs) アプリ設定
- [BuildingUnit](https://github.com/YoshihiroIto/JitPad/blob/8315f7fda1857e0403f13e863e83f2a321c3f062/JitPad.Core/BuildingUnit.cs)
    - ビルド単位
    - 指定のコンフィグで、コンパイルして逆アセンブルし結果を出力
    - 実行時には指定のコンパイラ、JIT逆コンパイラを使う。


## ビルド単位

```BuildingUnit``` はソースコードが入力されると指定コンフィグでビルド処理を行います。
依存するオブジェクト (コンパイラ、逆アセンブラ、コンフィグ)の詳細は関心外なので、構築時にを要求しこれらを組み合わせて処理します。


# まとめ

いざWPFアプリ開発となると、いきなり見てくれから作り始めてしまうこと必至ですが、ちょっと待って。
まずは問題領域を整理把握しましょうという話でした。

問題領域が整理把握実装できていれば、それに合わせてGUIが作れるというものです。

実装者のWPF習熟度にもよりますがGUIから作り始めたところ限界がきて、
「WPFの都合でーー」
とか言われて(ホント？)、低品質アプリが出来上がってしまういくつかの現場を見てきました。
  
アプリを使うユーザーはただ目的が達したいだけ、GUIを触ることは目的外。
目的が果たせれば GUI なんていらないです。
GUIを用意するのであれば、目的を心地よく果たせるものを用意したいものです。


ということで、次回はビュー実装編、乞うご期待。
[Oracle Cloud] 東京-大阪リージョン間リモートピアリングを、複数のVCNで共有する

# 背景

Oracle Cloud 大阪リージョンがGAしました！
これは、東京-大阪間の接続試してみたい。どうせだったら、リモートピアリングで閉域接続試したい。

リモート・ピアリングするには、まずは各リージョンでDRGを作る必要がある。

よし、作ろう！

![drg-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456818/246a18d6-3b33-166f-c522-321f0a80fbb0.png)

なんと。。Service Limitにひっかかった。。~~しかも、SRで拡張依頼しても現状5個が上限という(人伝て)~~ ※ 増やせるらしい(未確定)。確かに、ここ([Service Limits](https://docs.cloud.oracle.com/en-us/iaas/Content/General/Concepts/servicelimits.htm#))を見ても増やせない制限は書いてない。

そうか、DRGはそんな気軽に使って遊べるものではなかたのか。これは共有環境が必要だ。ということで、複数VCN間で東京-大阪のリモートピアリングを共有できる方法を検証した。

# 作ったもの

いろいろと調べた結果、DRGを複数VCNで共有するためには、Transit Routingを利用したHub & Spoke構成にする必要があるという結論になりました。

![drg-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456818/cb8c8e31-b97d-aef0-9c0b-2e72625e2924.png)


各VCNに対してルーティングを設定する必要があるため、各VCNに割り当てるCIDRブロックを管理して採番してあげる必要がありそうです。

# 参考にしたリンク
[Oracle Cloud：VCN Transit Routing で Hub and Spoke構成をしてみてみた](https://qiita.com/shirok/items/fe5cfb09af219703be0e)

# ポイント
手順は煩雑なので、ポイントだけ

## CIDRの採番
ルーティングを意識する必要があるので、東京と大阪で重複しない範囲のCIDRを割り当てます。
ルーティング設定がシンプルになるように、以下のように決めました。

### 東京側のVCN CIDRブロック

10.0.0.0/16 ~ 10.127.0.0/16 を割り当てることとする。
(第二オクテットの先頭ビットが0)

### 大阪側のVCN CIDRブロック

10.128.0.0/16 ~ 10.255.0.0/16 を割り当てることとする。
(第二オクテットの先頭ビットが1)

### DRGのVCN

上記と異なるアドレス帯を適当に。

# 構成

## HUB用VCN

以下を、大阪と東京で2セット作ります
・DRG
　・リモートピアリング接続
　　 東京と大阪それぞれで作成した後、「接続の確立」でピアリング
　　 (なぜか、東京側からやったら、なぜかap-osaka-1がプルダウンにでてこなかったので大阪側から実施した)
・VCN (作ったDRGをアタッチ)
　・Local Peering GW (Spokeの数だけ)
　・ルート表×2 (DRG割り当て用とLocal Peering GW割り当て用)

　- 東京側
　　ルート表(DRG割り当て用)には、以下のエントリを登録
　　　10.0.0.0/16 → LPG -000- # 10.0.0.0/16のパケットをLPG -000-に転送
　　　10.1.0.0/16 → LPG -001- # 10.1.0.0/16のパケットをLPG -001-に転送

　　ルート表(Local Peering GW割り当て用)には、以下のエントリを登録
　　　10.128.0.0/9 → DRG -Tokyo- # 10.128.0.0/9(大阪のCIDR)のパケットをDRG -Tokyo-に転送

　- 大阪側

　　ルート表(DRG割り当て用)には、以下のエントリを登録
　　　10.128.0.0/16 → LPG -128- # 10.128.0.0/16のパケットをLPG -128-に転送
　　　10.129.0.0/16 → LPG -129- # 10.129.0.0/16のパケットをLPG -129-に転送

　　ルート表(Local Peering GW割り当て用)には、以下のエントリを登録
　　　10.0.0.0/9 → DRG -Osaka- # 10.0.0.0/9(東京のCIDR)のパケットをDRG -Osaka-に転送

# Spoke用VCN
Spoke用VCNごとに、以下のセットを作成します
・VCN
　・Subnet
　　- ルート表
　　　→ 大阪側CIDR宛てのパケットをLocal Peering GWに転送する設定
　　- セキュリティ・リスト
　　　→ イングレス・エグレスに、大阪側CIDRとの通信許可設定
　・Local Peering GW
　　→ 作成後、HubのLocal Peering GWとPeeringします。

## 結果
通信できました!!

```
[opc@tokyo2 ~]$ ping 10.129.2.2
PING 10.129.2.2 (10.129.2.2) 56(84) bytes of data.
64 bytes from 10.129.2.2: icmp_seq=1 ttl=62 time=7.86 ms
64 bytes from 10.129.2.2: icmp_seq=2 ttl=62 time=7.83 ms
64 bytes from 10.129.2.2: icmp_seq=3 ttl=62 time=7.83 ms
64 bytes from 10.129.2.2: icmp_seq=4 ttl=62 time=7.87 ms
64 bytes from 10.129.2.2: icmp_seq=5 ttl=62 time=7.84 ms
64 bytes from 10.129.2.2: icmp_seq=6 ttl=62 time=7.85 ms
64 bytes from 10.129.2.2: icmp_seq=7 ttl=62 time=7.85 ms
64 bytes from 10.129.2.2: icmp_seq=8 ttl=62 time=7.85 ms
```
【Spring Boot2】コントローラーからエラーハンドラーに変数を渡す方法

コントローラーごとに違う変数をセットする時や、コントローラーごとに処理を変える時などに使える方法です。
コードは、Kotlinで書いています。

まず、アノテーションクラスを自作します。
フィールドは渡したい変数を設定します。

# アノテーションクラス
```
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
annotation class Hoge(
    val value: Fuga
)
```

コントローラーのハンドラーメソッドに、上記のアノテーションを設定します。
# Controller
```
@Hoge(fuga)
fun handle() {}
```
# エラーハンドラーでの受け取り方法
エラーハンドラーでは、下記の方法でアクセスできます。
## フォームバリデーションエラー時
```
@RestControllerAdvice
class ErrorHandler : ResponseEntityExceptionHandler() {
    override fun handleMethodArgumentNotValid(
        ex: MethodArgumentNotValidException,
        headers: HttpHeaders,
        status: HttpStatus,
        request: WebRequest
    ): ResponseEntity<Any> {

    val fuga = ex.parameter.getMethodAnnotation(Hoge::class.java)!!.value
}
```

## パスパラメータ・クエリパラメータバリデーションエラー時
```
@RestControllerAdvice
class ErrorHandler : ResponseEntityExceptionHandler() {

    @ExceptionHandler(ConstraintViolationException::class)
    fun handleConstraintViolationException(
        ex: ConstraintViolationException,
        request: WebRequest,
        handlerMethod: HandlerMethod
    ): ResponseEntity<Any> {

    val fuga = handlerMethod.getMethodAnnotation(Hoge::class.java)!!.value
}
```
もちろん、@ExceptionHandlerのパラメータを変えることで、どんなエラーハンドラーでも上記の方法が使えます。
curl で Cloud Firestore のデータを更新 (Update)

Cloud Firestore の RestAPI を使ってデータを更新します。

```json:update01.json
{
  "fields": {
	"population": { "integerValue": "27513000" },
	"date_mod": { "stringValue": "2020-06-01" }
  }
}
```

project-aaa の cities の t0921 を更新

```bash:firestore_update.sh
#
#
#
export GOOGLE_APPLICATION_CREDENTIALS="***.json"
#
ACCESS_TOKEN=`gcloud auth application-default print-access-token`
#
project_id=`jq .project_id $GOOGLE_APPLICATION_CREDENTIALS | sed "s/\"//g"`
echo $project_id
#
URL='https://firestore.googleapis.com/v1/projects/'$project_id'/databases/(default)/documents/cities/t0921'
#
#
curl -H "Authorization: Bearer $ACCESS_TOKEN" \
	-H 'Content-Type: application/json' \
 	-X PATCH \
	-d@update01.json \
	$URL"?updateMask.fieldPaths=population&updateMask.fieldPaths=date_mod"
#
#
```
Spring Boot + Kotlin ページネーション

#簡単なページネーションを行います。

- 表示する量の制限

などができるようになります。

#前提（環境・完成図）

- 基本的なWeb開発ができて、CRUDもできている人向け（GetMappingの説明などは省いています）

##完成図
<img width="1440" alt="スクリーンショット 2020-01-29 16.36.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270887/1d0e5f20-6372-ab82-eb14-18df384bc5a4.png">


##環境
|                  | Version      |
|:-----------------|------------------:
| Kotlin             | 1.3.60 |
| spring Boot       |2.2.2 |



#ページネーションを表示する

行う場所(ファイル）は、

- Service
- Controller
- Repository


##1. Controller
```kotlin
import org.springframework.data.domain.Pageable

@GetMapping("/")
    fun index(model: Model, pageable: Pageable): String { // pageable: Pageableを追加

        val bookinfo = bookInfoservice.getfindAll(pageable) // bookInfoserviceから、getfindAll関数を呼び出す(引数は「pageable」にする）
        model.addAttribute("bookdata", bookinfo)

        return "Book/index"
    }
```

1. import org.springframework.data.domain.Pageableを追加する

2. index関数の引数に「pageable: Pageable」を追加する

3. Serviceレイヤ（ここでは、bookInfoservice）から、getfindAll関数を呼び出している。

4. 引数には、pageableを追加
 
そして・・・

##2. Service

```kotlin
import org.springframework.data.domain.Pageable
import org.springframework.data.domain.PageRequest

fun getfindAll(pageable: Pageable) = bookRepository.findAll(PageRequest.of(pageable.pageNumber, 5))
```

1. getfindAll関数を呼び出す
2. Repositoryレイヤ(bookRepository)から、findAll関数を呼び出す。
3. 引数には、PageRequest.of(page, size)を入れる


※ PageRequest.of(何ページ目を表示するのか, どれだけ表示したいのか) -> 全て数値で入れる
※ pageable.pageNumberは、pageableリクエストに含まれる一つの値です。

```
Page request [number: 2,・・・・・] このようにレスポンスが返ってきます。
```

そして・・・・


##3. Repository

```kotlin
override fun findAll(pageable: Pageable): Page<クラス名>
```

1. findAll関数は、標準で入っているため、override（オーバーライド）をして、関数を定義する。(新しい関数の場合は、overrideをする必要がない。）

2. 返り値は、Page<クラス名>とすれば、OK！

※Page<クラス名>・・・クラス名は、Entity内のdataクラス名などを入れる。or dbを作る際に使うクラス名を使う

##4. 完了。 Thymeleaf側で、ページをめくれるようにする。

```HAML

<div th:fragment='pagination'>
    <ul>
       <li th:class="${bookdata.first}" style="display:inline">
          <span th:if="${bookdata.first}">←先頭</span>
          <a th:if="${not bookdata.first}" th:href="@{${url}(page=0)}">←先頭</a>
       </li>
       <li th:each='i : ${#numbers.sequence(0, bookdata.totalPages-1)}' th:class="(${i}==${bookdata.number})? 'active' : ''" style="display:inline">
         <span th:if='${i}==${bookdata.number}' th:text='${i+1}'>1</span>
         <a th:href="@{${url}(page=${i})}">
            <span th:text='${i+1}'>1</span>
         </a>
       </li>
       <li th:class="${bookdata.last}" style="display:inline">
        <span th:if="${bookdata.last}">末尾➝</span>
        <a th:if="${not bookdata.last}" th:href="@{${url}(page=(${bookdata.totalPages}-1))}">末尾➝</a>
       </li>
   </ul>
</div>
```

※ ${bookdata}には現在のページの数字が入っています。 -> bookdata.numberで取り出すことが可能


終了！！


#まとめ
- 基本的な（CRUDが入っている)実装があれば、コードを少し追加するだけで完成できるかもしれない。
- PageableとPageの使い方でページネーションの実装は可能であること


#感想
今回のページネーションをSpring Bootで実装をするときは、Javaで行っている記事が多かったため、苦労しました。また、Kotlin + Spring Bootで実装しているものが少ない印象を持ったので、これから、少しずつアウトプットができればと思っております。
【JavaScript】Promiseよりも可読性の上がるasync/awaitの基本的な書き方

## はじめに
JavaScript(ES6)の**Promiseの`then`**、**`async/await`**それぞれで同じ結果を得るためのコードを比較しました。

`setTimeout`のみを使ったシンプルな例で説明しています。

## 環境
```yaml
OS: macOS Catalina 10.15.1
```

## 1.Promiseの`then`で書いたコード
先日の[この記事](https://qiita.com/terufumi1122/items/4cfcaa92e9a96058220c)から転用します。

```javascript:methodChain.js
function promiseOne() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve('いーち')
    }, 1000) //1秒後に'いーち'という文字列を返す
  })
}

function promiseTwo() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve('にーい')
    }, 1000) //1秒後に'にーい'という文字列を返す
  })
}

function promiseThree() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve('さーん')
    }, 1000) //1秒後に'さーん'という文字列を返す
  })
}

//出力例
promiseOne()
  .then(one => { //ここのoneにはpromiseOneのresolveの()内にある文字列が入る
  console.log(one)
  return promiseTwo() //ここでreturnした結果が次の引数twoに入る
})
  .then(two => { //ここのtwoにはpromiseTwoのresolveの()内にある文字列が入る
    console.log(two)
    return promiseThree() //ここでreturnした結果が次の引数threeに入る
})
  .then(three => { //ここのthreeにはpromiseThreeのresolveの()内にある文字列が入る
  console.log(three)
})
```
↓

```shell:出力(1秒後)
いーち
```
```shell:出力(2秒後)
いーち
にーい
```
```shell:出力(3秒後)
いーち
にーい
さーん
```

このように、**非同期処理を順番に処理**出来ていました
。

ただ、returnの結果が**次の`then`の第一引数に入る**あたりが**可読性を下げている**と思います。

これを`async/await`を使って書き換えると、どの変数に何が入っているのか非常に分かりやすくなります。

**では、書き換えていきましょう！**

## 2. `async/await`で書き換えたコード
最下部にあった**出力例**の箇所のみ`async/await`をつかって書き換えます。

```javascript:asyncAwait.js
...略

//非同期処理の順番を指示する関数を定義する
async function asyncAwait() { //必ずasync functionで始める
  const one = await promiseOne() //非同期関数にawaitをつけると、promiseOneの処理が全て完了した時点でresolveの()内がoneに入る
  console.log(one) //'いーち'
  const two = await promiseTwo() //同様にpromiseTwoの処理が全て完了した時点でresolveの()内がtwoに入る
  console.log(two) //'にーい'
  const three = await promiseThree() //同様にpromiseThreeの処理が全て完了した時点でresolveの()内がthreeに入る
  console.log(three) //'さーん'
}
  
//出力部
asyncAwait()
```
↓

```shell:出力(1秒後)
いーち
```
```shell:出力(2秒後)
いーち
にーい
```
```shell:出力(3秒後)
いーち
にーい
さーん
```
同様に処理できました。

`async/await`の方が、Promiseの`then`よりもスッキリ！
**コードの可読性**が高くなりました！

同じ結果を得られるなら、`async/await`を選ぶべきですね。

以上です！

## おわりに
最後まで読んで頂きありがとうございました:bow_tone1:

どなたかの参考になれば幸いです:relaxed:

## 参考にさせて頂いたサイト（いつもありがとうございます）
- [JavaScript Async Await - YouTube](https://www.youtube.com/watch?v=V_Kr9OSfDeU&t=103s)
- [async function - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/async_function)
hpa でスケールアウトした Pod も含めて rollingUpdate する

## TL;DR

- kubernetes で hpa 使うと rollingUpdate 時に縮退してしまうことがある
- これを防ぐには deployment で replicas を指定せず、hpa にすべて任せて `minReplicas` で調整するのが良い
- 既に デプロイ済みの deployment がある場合は、ワークアラウンドとして `kubectl edit` で、`spec.replicas` を削除してしまう手がある

## はじめに

[（株）いい生活 サーバープラットフォームチーム](https://jobs.qiita.com/employers/e-seikatsu/development_teams/24) の多田 (@es-y-tada)です。

Kubernetes で [hpa(Horizontal Pod Autoscaler)](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) を使っている際の rollingUpdate を安全に行う方法について解説します。

### 注釈

この記事は下記環境での実験的観測結果を記載しているため、実際に適用する際は改めて検証していただくことをおすすめいたします。

* Client Version: v1.17.2
* Server Version: v1.13.12-eks-eb1860

## スケールアウト時になにが起こるか

deployment で `spec.replicas=3` を指定した場合を想定します。
負荷の高まりに従って hpa によって pod 数が 9 にスケールアウトしていたとします。

Q. このとき `kubectl apply` によって pod の更新を行うとどうなるでしょう

A. 6pod が Terminate されると同時に、残りの 3pod の中で Strategy に従ったローリングアップデートが起こる

## 挙動の説明

hpa の機能は、ざっくりと言えば対象の負荷状況に応じた  pod の必要数 `desiredReplicas` を算出し、 deployment の `spec.replicas` を書き変えることです。

Deployment の `spec.replicas` に値が指定されている場合、 apply 時に Pod 数がテンプレートに指定された `spec.replicas` の値で上書きされます。

hpa の `desiredReplicas` の反映はそのあと遅れてやってきます。

実際の動きを今回に当てはめると、

1. deployment の `spec.replicas` が 9 -> 3 に置き換わると同時に、この 3pod に対して rollingUpdate がかかる。同時に、このとき過剰と判断された 6pod は削除される
2. hpa が負荷状況を察知したタイミングでスケールアウトを指示、  `desiredReplicas=9` となるよう 6pod が新しく作成される

という動きになります。

この動きの問題は、負荷状態だからスケールアウトしているにも関わらず、一時的にスケールアウト前のデフォルト数まで pod が縮退してしまうため、過負荷によって性能劣化やエラーを誘発してしまう点です。

## 解決法

こちらの issue に記載があります。

* https://github.com/kubernetes/kubernetes/issues/25238

`kubectl apply` 時に、`spec.replicas` が指定されていなければ元の値がキープされることを利用します。

ただし、 **既に replicas を指定して Deployment を作成している場合は、 edit して replicas フィールドを削除する必要があります** 。

`spec.replicas` 無指定の templete を初めて apply するタイミングでは、 apply 前の `spec.replicas` の値が優先されるため、従前と同様の pod縮退が起きてしまいます。
2回目以降の apply では、 `spec.replicas` 無指定のテンプレートを元に更新が行われるため、 hpa の `desiredReplicas` で置き換わってくれます。

初回適用時の問題に対処するには、 `kubectl apply edit-last-applied deployment/the-deployement` を使って、対象 deployment の `spec.replicas` フィールドを手動で削除しておく方法があります。


新しく作成する deployment の場合にはもちろんこのようなワークアラウンドな作業は不要です。

deployment + hpa で構成する多くの場合は、始めから deployment の `spec.replicas` を指定しないことをおすすめします。
Android gradle で cmake build のメモ

https://developer.android.com/studio/projects/add-native-code.html#create-cmake-script

## Cmake version

SDK manager の cmake (Android Studio 経由で落とす. Android SDK には付属していない. どこかに直接ダウンロード URL はあるかと思われる)を使うか(version 3.10 ベース), もしくは cmake 3.7 以上を使う.

SDK manager 経由で落とすと,

`$ANDROID_SDK/cmake/3.10.xxx/bin/cmake` にある.

## ビルドフォルダ

デフォルトでは, 

`app/.cxx/cmake/` に生成される.
たとえば

`app/.cxx/cmake/arm8Debug/arm64-v8a` など.

Android Studio では, CMake のエラーコードはパースしてくれないようで IDE 内でエラー位置に移動してくれないため, このフォルダで vim などで quickfix できるようにしたほうがよい.

`app/.externalNativeBuild/cmake` になる場合もあるっぽい?.
Slackで自分宛のmentionをGASを使って別チャンネルに転送してTODO化する試み

Slackのチャンネルが乱立してて、どこで自分にメンション付きで依頼が来たのかわからなくなってしまうことがあったので、自分宛のメンションをまとめてTODOチャンネルに放り込むということをしてみようと思った。

### 作成フロー

　1. slackのbotを作る
　2. botにincoming webhooksを設定する
　3. GASを準備する
　4. botにパーミッション与える。Event Subscriptionを設定する。
　5. 様子を見る（きっとtodoチャンネルに転送されてるはず）


### 準備するもの
 - 転送したいSlackユーザのID
 - 転送先のSlackチャンネル&そのチャンネルのID
 - 転送先のSlackチャンネル用にSlackBot->incoming webhoos設定
 - GAS


### GAS側ソースコード

```javascript

function doPost(e) {
  var params = JSON.parse(e.postData.getDataAsString());
  var response = {};
  if(params.type == 'url_verification') {
    response = {'challenge':params.challenge};
    return ContentService.createTextOutput(response).setMimeType(ContentService.MimeType.JSON);
  } 
  
  var url = 'https://hooks.slack.com/services/aaaaaa/aaaaaaa/aaaaaaaa'; //<- incoming webhook url
  var text = params.event.text;
  var userPattern = 'SLACKUSERID'; //<- Slackの自分のID
  var ignoreChannel = 'CHANNELID' // <- 転送先のチャンネルID
  
  if (params.event.channel != ignoreChannel && text.match(userPattern)) {
    var params = {
      method: 'post',
      contentType: 'application/json',
      payload: '{"text":"'+ text +'"}'
    };
    
    UrlFetchApp.fetch(url, params);
  }
}

```
 - urlにincoming webhook urlを投入
 - userPatternにSlackの自分のID（ユーザ名じゃないので注意）
 - ignoreChannelに転送先チャンネルのID（これ設定しないと永久ループしてすんごいことになる）

これをウェブアプリケーションとして導入。

### Slack側
細かいことは省略。
欲しいのは

 - bot本体
 - incoming webhooks
 - Event SubscriptionsのSubscribe to events on behalf of usersで```message.channels```のパーミッションを与える

多分これだけでいけるはず。（色々いじってみたので足りてない部分あるかもしれない）

### というわけで

 - botにチャンネル単位でパーミッションを与えるわけではなく、ワークスペースに対してパーミッションを与えるので、ちゃんとデータをフィルタリングしないと見たくもない内容が転送されることもあるかもしれない。。やっぱり大事な話はprivate channelにしないとどこでみられてるかわからないから怖いですね。
 - 転送内容が上記だとテキストだけなので、チャンネル名とかそういうのも転送してやることでもっと良くなるかも。
プロジェクトマネージメント

#プロジェクトマネージメントとは
※一部Wikiより引用　[Wiki](https://ja.wikipedia.org/wiki/%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%83%9E%E3%83%8D%E3%82%B8%E3%83%A1%E3%83%B3%E3%83%88)

- プロジェクトを成功裏に完了させることを目指して行われる活動のことである。<br>これにはプロジェクトを構成する各活動の計画立案、日程表の作成、および進捗管理が含まれる。
- システム開発を成功させるためには、プロジェクトを適切に管理することが求められる。

#プロジェクトとは？
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269200/3bcac45f-fd5e-23fb-3e37-0c130822c7e7.png" width=50%>

- 明確に定義された目標がある
- 必ず開始時点と終了時点がある
- 永続的でない一時的な組織
- プロジェクトマネージャ（リーダー）と複数のメンバーから構成される
- 目的達成のための予算が与えられる（人的資源、物的資源、コスト等の制約がある）
- いくつかの工程から成り立つ
- 予期できない事態が発生することがある
- 後工程ほど変更・修正の困難度が増す
- 独自のサービスやプロダクツ（成果物）を生み出す

#プロジェクトにおけるフェーズ
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269200/62b83a0e-b50c-0e0e-072b-7b67373b52e9.png" width=80%>

##立ち上げ
新しいプロジェクトやプロジェクト・フェイズを開始するために実行されるプロセスから構成される。キックオフミーティングなどを行い、顔合わせをする。

- 「スコープ」を決める・・・「スコープ」とは、プロダクトやサービスの最終形のこと。
- 立ち上げ時にスコープを決め、そのスコープに沿って計画を進める。
- プロジェクト計画書を作成し、プロジェクト全体の目的や意識を共有する。<br>立ち上げ時にはこの「スコープマネジメント」が非常に大切。

##計画
プロジェクトをどのように遂行していくかを計画するプロセスから構成される。
計画プロセス群には、プロジェクトをどのように進めていくかだけでなく、どのようにプロジェクトをマネジメントしていくかといった、プロジェクトマネージャの指針になるような活動も含まれる。

###「WBS」を作成
「計画」フェーズで重要なことは、WBS（Work Breakdown Structure）を作成してスケジュールとコスト計画を立てる。

- 機能一覧や立ち上げフェーズの「スコープ」を基に、WBSを作成。
- WBSの各アクティビティに対してリソース配分
- 当初リソースで足りなければ、パートナーや協力会社からリソースの協力を得る。

こうした「リソース計画」は「計画」フェーズで非常に大切な要素の一つ。

#監視コントロール
時にはトラブルが発生したり、計画とは異なる方向へ進んでしまったりすることもある。<br>監視コントロールの各プロセスは、プロジェクトの状況を監視し、プロジェクト計画とのギャップをチェック。<br>また、プロジェクト計画とのギャップが大きくなった場合は、是正処置を行い、プロジェクトの軌道修正を行うこともある。

##予期せぬ事態に遭遇
- ビジネス要因で、当初予定のスコープに変更がある
- 利用を予定していた外部サービスの仕様に一部問題があり、別のサービスへの変更を余儀なくされる
- メンバーのモチベーションから来る生産性の低下により、進捗が遅れる
- 優先順位の変更により、当初より早くリソースの調整が必要となる
- 当初見積額に大幅な変更がある

**この変更を監視し、対応する仕組みを持つことが、このフェーズでは最重要となる。**

- 「変更管理」をコントロールする委員会の設置
- 変更管理の「チケット」を管理する仕組み
- 「見える化」し、調整を迅速に進めていくことが必要。
- システムの一部分が再計画を余儀なくされる場合もあり、全体のコスト・進捗状況・品質を見ながらプロジェクトを推進していく。

#実行
プロジェクトの計画書に従って、プロジェクト作業を実際に推進していくプロセスから構成される。
##チームで戦う
「計画」フェーズで定義したWBSに沿って、プロジェクトを推進。

- ここで一番大切なのは**「チームのマネジメント」**。
- フルスタックと呼べるようなメンバーはごく一部に限られているので、チームでの推進が非常に大切。
- **「チームで戦えるか」**を重視する。


#終結
プロジェクトやプロジェクト・フェイズを公式に終了するためのプロセスから構成される。
正式に納品・検収の手順を経て、プロジェクトが「終結」。

最後もリクエスタとミーティングを行い、KPTを用いて「ふりかえり」ミーティングを実施するとよい。
お互いの良かったところ、悪かったところを「マインドマップ」など使って「見える化」し、後に続く「保守」や機能改修時に使ったりなど。

#各フェーズで必要なアウトプット
|フェーズ|大切な事|アウトプット|
|:-----------------|:------------------|:------------------|
|立ち上げ|・関係者と親睦を深めること<br>・プロダクト・プログラムのスコープを決めること|・プロジェクト計画書<br>・スコープ定義書|
|計画|・WBSを作成し、コスト・スケジュールの計画を立てること<br>・リソースの計画を立てること|・WBS<br>・リスク一覧<br>・リソース計画書|
|実行|チームのマネジメントを心掛けること|成果物（ソースコード・テスト計画書など）|
|監視・コントロール|・変更を監視し、対応する仕組みを持ち実践すること|・変更管理表（変更の履歴が分かるもの）<br>・WBS更新版<br>・リスク一覧更新版<br>・リソース計画書更新版|
|終結|・ふりかえりをする|・次回につなげる|

#最後に
私は今まで、規模の小さな案件で、立ち上げ～終結までは、経験してきました。
現在は、わりと規模の大きなものに携わっているので、全体的なPMはできませんが、主には「実行」「監視・コントロール」の部分を担っていると思います。
「予期せぬ変更」という部分で、**変更を監視し、対応する仕組みを持つ**ここに注力してはいますが、いまだにどういう対応が望ましく、どう仕組み化できるのだろうか、という部分に試行錯誤しています。
私が一番重きを置いていることは「プロジェクトを終わらせること」。
しかし、どんなやり方でも終わらせることはできると思いますが、人の管理・進行の管理・チームのマネジメントに努め、携わるすべての人が「良いものができた（達成感）。楽しく終えれた。」と思えるようなものを作っていきたいと思います。
Q21.ユーザーフォームでテキストボックスとボタンを利用するには？

今回はユーザーフォームのパーツの一種である、テキストボックスとボタンを利用していきます。

ユーザーフォームのテキストボックスに文字列を入れて、ボタンを押すと、アクティブセルに
文字列を入力するというものを作ってみましょう。


###■ユーザーフォームへテキストボックスとボタンの配置

1．まずは、ユーザフォームを開きます。
もし、ツールボックスが表示されていない場合は、以下から表示することができます。
![Q21-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560479/4c2eecbd-f2fa-8ee9-4369-acf7f8262bb1.png)

2．テキストボックスを配置します。ツールボックスからテキストボックスを選択して、
ユーザーフォームへ配置します。

![Q21-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560479/511d1691-4d06-dce2-f634-970ac5f64e4e.png)

3.コマンドボタンを配置します。ツールボックスからコマンドボックスを選択して、
ユーザーフォームへ配置します。

![Q21-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560479/960c375d-846b-880c-0ba4-b553058d0019.png)



4．配置したパーツの大きさを自分のお好みで適宜変更していきます。

![Q21-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560479/99f1f2aa-2974-636b-f3d8-4e90fde5ab4f.png)


5．コマンドボタンに表示されている文字列を変更します。コマンドボタンを選択して、
以下のCaptionにある文字列を変更していきます。今回は、入力とします。


![Q21-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560479/e810b0ce-7402-fc02-1e13-3de064574e45.png)




6．フォントから文字のサイズを変更して、スタイルを太字にします。
ここらへんもお好みでやってください。

![Q21-6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560479/efbd1ca2-67ca-18f1-e5aa-1fb99017c1f9.png)



これで、ユーザーフォームは完成です。
マクロですが、今回は標準モジュールへの記述ではありません。
なぜなら、ボタンを押した時の挙動を記述していくからです。


どこに記述するかというと、今回配置したコマンドボタンをダブルクリックすると、
コードを記述する画面が出てきます。

Private Sub CommandButton1_Click()
※ここにコードを記述。
End Sub



###■回答
```VB
Private Sub CommandButton1_Click()
ActiveCell.Value = TextBox1.Text
End Sub
```


###■解説
今回書くのはたったの1行です。
どちらかというと、ユーザーフォームの配置の方がメインですね。
TextBox1.Textから、先ほど配置したテキストボックスに入力した値を
取得することができます。

ただ、このままではユーザーフォームが呼び出せませんので、
標準モジュールに呼び出すマクロを記述しましょう。

UserForm1.Showと記述するだけでOKです。


実行結果は以下です。

適当なセル(今回はB2セル)を選択します。
![Q21-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560479/b891a644-39d9-400c-bea4-95d79c9cd02a.png)


ユーザーフォームを呼び出すマクロを実行し、テキストボックスにこんにちはと入力しました。
そのうえで、入力ボタンを押します。
![Q21-8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560479/83dc2397-b38c-86ae-a979-be682df1fc19.png)


B2セルへ"こんにちは"と入力することができました。
![Q21-9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560479/40e28512-1ad7-7d60-bfd1-109ae3d0c7ee.png)
JavaScript: 再帰でパイプライン、関数合成してみる

[JavaScript/TypeScript でお手軽パイプライン](https://qiita.com/nagtkk/items/5c54ec418c1c71fa491a) で再帰でパイプができると教えていただいたので、関数合成の方もあわせてやってみました。
あわせて、途中で計算が失敗したらそれ以降は計算しないで失敗の値をそのまま返し、関数適用時に何かエラーを投げたら、それも計算の失敗とみなしてnullを返すようにしてみました。

```js:
// パイプライン：
const pipe = x => f => 
  !isFunction(f) ? x 
  : pipe( applyIfSucceed(f)(x) ) 

// 関数合成：
const innerComp = fs => g => 
  !isFunction(g) ? fs.reduceRight( 
      (acc, f) => applyIfSucceed(f)(acc)
      , g 
    )
  : innerComp([...fs, g])

const compose = innerComp([])

// 共通の補助関数：
const isFunction = f => 
  typeof f === "function"

const applyIfSucceed = f => x => {
  if( isFailure(x) ) { return x }
  try { return f(x) }
  catch(e) { return null }
}

const isFailure = x => 
  x === null || x === undefined || Number.isNaN(x)

// 使い方の例：
pipe(2)(x=>x*5)(x=>x+3)();  // 13
compose(x=>x*5)(x=>x+3)(2);  // 25
// 途中で失敗したらその値を返す：
pipe(2)(x=>NaN)(x=>3)();  // NaN
compose(x=>5)(x=>null)(2);  // null
```
ちなみに、関数合成の方は本当には合成してなくて、逆向きのパイプラインになってます。
関数を配列に貯め込んで、値が来たら後ろの関数から順番に適用、ってしてます。
マジ関数合成しちゃった場合、途中で失敗というのが検知できなくてこうしました。あしからず(追記：あとで考えたらできました。末尾の追記参照)。

ちなみに、そのマジ関数合成しちゃう版はこちら：

```js:
const compose = f => g => 
  !isFunction(g) ? f(g) 
  : compose( x => f(g(x)) )

// 使い方の例：
compose(x=>x*5)(x=>x+3)(2);  // 25
// 途中で失敗しても教えてくれない...：
compose(x=>5)(x=>null)(2);  // 5
```

### 追記 ：マジ関数合成でもできました。

```js:
const compose2 = f => g => x =>
    f(g(x))
 
const id = x =>
    x

const innerComp = f => g =>
	! isFunction(g) ? f(g)
	: innerComp( compose2(f)( applyIfSucceed(g) ) )

const compose = innerComp(id)

// 使い方の例：
;
compose(x=>x*5)(x=>x+3)(2)  // 25
compose(x=>5)(x=>null)(2)  // null
```
最初の f には 恒等関数 id を持ってきて、 g を合成するかわりに applyIfSucceed(g) を合成していけばよい。
Kubernetesをハンズオンで理解する

#はじめに
今回はマネージドサービスではなく、プロキシ導入企業などの
特定環境下でのKubernetes構築を行ってみた。

参考にした記事：
[数時間で完全理解！わりとゴツいKubernetesハンズオン！！](https://qiita.com/Kta-M/items/ce475c0063d3d3f36d5d)



#kubernetesでできること
・関連するコンテナのグルーピング
・コンテナに割り振られるIPアドレスの管理
・コンテナ間のネットワークルーティング管理
・複数のコンテナを利用した負荷分散
・コンテナに割り当てるストレージの管理
・コンテナの監視


#構築
###アプリケーションのインストール
```
# yum install etcd kubernetes flannel
```

###ローカル以外からkubernetesへのアクセス許可設定
```shell:/etc/etcd/etcd.conf
#ETCD_LISTEN_CLIENT_URLS="http://localhost:2379"
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"
```

###etcd.confの項目
|項目|	意味|
|:--|:--|
|ETCD_NAME|	ホスト名を設定する|
|ETCD_DATA_DIR	|DBのパスを設定する。デフォルトのパス|は/var/lib/etcd/default.etcd
|ETCD_LISTEN_PEER_URLS|	etcdデーモン間の送受信に使うIPアドレスとポート番号を設定する|
|ETCD_INITIAL_CLUSTER|	etcdクラスタのメンバを設定する。|
|ETCD_INITIAL_CLUSTER_STATE	|newを設定する|
|ETCD_INITIAL_CLUSTER_TOKEN	|etcdクラスタを識別するための文字列。同一クラスタ内のメンバは同じ文字列を設定する|


###etcd起動
```
systemctl start etcd
```

###flannelネットワークの指定
```
# etcdctl mk /atomic.io/network/config '{"Network":"172.17.0.0/16"}'
{"Network":"172.17.0.0/16"}
```

###flannel起動
```
systemctl start flanneld
```

###追記予定
yarn create nuxt-app 「'C:\Program' は、内部コマンドまたは外部コマンド、 操作可能なプログラムまたはバッチ ファイルとして認識されていません。」

個人的に少しハマったのでメモ
## 事象
yarn createでNuxtのプロジェクトを作成しようとした際にエラー

```powershell
PS C:\Users\myname> yarn create nuxt-app helloworld
yarn create v1.21.1
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...

success Installed "create-nuxt-app@2.12.0" with binaries:
      - create-nuxt-app
'C:\Program' は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。
error Command failed.
Exit code: 1
Command: C:\Program Files (x86)\Nodist\bin\bin\create-nuxt-app
Arguments: helloworld
Directory: C:\Users\myname
Output:

info Visit https://yarnpkg.com/en/docs/cli/create for documentation about this command.
```

## 環境
- OS: Windows10
- yarn: v1.21.1
- node: v10.15.2(Nodistでバージョン管理)
- Nodist: 0.8.8

## 原因
Nodistのインストールディレクトリをデフォルトの`C:\Program Files (x86)`配下にしてしまったため、実行時コマンドに半角スペースが入ってしまい正しく`create-nuxt-app`が実行できない。

## 暫定対応
本来はNodistのインストールディレクトリを変更するなどが好ましいが、直接`create-nuxt-app`があるディレクトリを指定して実行する。

```powershell
c:\Progra~2\Nodist\bin\bin\create-nuxt-app helloworld
```
`Progra~2`の表記については以下の記事を参照
https://grum.hatenablog.com/entry/2017/05/16/110000
プログラミングにおける芸術と保守性の二律背反

# プログラミングは芸術である。

プログラミング「言語」というだけあって、
同じ目的だとしても、そこには幾通りのもの書き方があり、
書き方によってはパンドラの箱にもなり、かと思えば美しく書かれたコードは見るものを魅了する。

文章による表現である以上は、書き手の個人が反映され芸術性出てくるのが
プログラミングであり、それは工芸品に近いものである。

だが芸術でありながらも実用面(保守性)が良いものである必要があり
この二律背反が人を悩ませる元なんだろうなと思う。

今回は保守性というキーワードで記事を書いてみようと思う。

# 背景
はい。
自分の持てる全ての力でポエミーな導入文にしてみました。笑

自分は職業エンジニアであり趣味プログラマー(趣味なら気楽にやれる)でもあるんですが
この保守性の問題で良く頭を悩まします。
自分の中で意識している保守性をあげるための方法を記事にしてみたいと思います。

自分はある程度の大規模から小規模までPJ経験があるのですが、
小規模な場合は自分で開発し、自分でメンテし、自分で機能エンハンスします。
開発時に如何に保守性の良いものを作っておくかで自分のその後の苦しみが大きく変わります。
開発自体の終わりは始まりでしかなく、運用し始めてからが本番というのは
当然のことなのですが、全て自分でやってるとより実感します。

最初に結論を書いておくとやっぱりこれですね。

* クローンコードは悪
* まずは作ってリファクタリング
* C#大統一理論

それでは細かい部分を書いていきます。

# 保守性の良いコードを書くために

## 作る前にはプログラムレベルの役割分担図を手書きでも良いので書いてみる
闇雲に作るとコードが分散してクローンができたり、内容が散って修正時に苦労します。
ある程度のコード量が予見される場合は、クラスや名前空間などで固めておくのが良いですね。  
オブジェクト指向もこれに似た概念で、近い概念のもの(操作とデータ)はまとめておくことを
体系化したものと言えるのではと思っています。
人間は器用に考えるのは疲れます。考えれば分かるのはNGで素直にわかる仕組みにしておくのが大事ですね。

## まずは作ってみてからリファクタリング
いざ作って見るとなんか違うというのは、いくら経験を積んでもあります。
なんだかこのインターフェースは使いづらいな…など違和感ある部分は直したほうがいいですね。
違和感は経験からくるものですので、「まあいっか」はあとで間違いなく燃え上がります。  
いきなり完璧というのはなかなか難しいですので、リファクタリングは最初に必ず実施するべきと考えています。
リファクタリングを一度もかけなかったプログラムというのは自分の場合はないぐらいの感じです。
(まあいっかで放置したインターフェースで、後に続々インターフェース実装が増えると辛いことになったりします。)  
アジャイル開発な発想に近いですね。
## クローンコードは悪
まずは作ってみてからリファクタリングと関連しますが、作りながら似たコードを2度書いたなと思ったらすぐに関数化します。
見通しは悪くなるわ、直すときには複数修正＋複数テストになるのでまったくいいことはないです。  
世の中にはクローンコード解析といった内容をしてくれる診断サービスなどもありますが
それだけ百害あって一利なしな内容になります。

## 既存のプログラムで近いものがあるのなら拡張して対応する
「何の影響があるかわからないし」「自分の良く知っているやりかたじゃないし」
といった理由で機能拡張せずに似たコードができると「クローンコードは悪」な状態になります。  
デグレが絶対に許されない環境でどうしても…といった場合はもちろんあると思いますが、
後々面倒ごとが発生するので苦しいながらも直すことにしています。
（近年のユニットテスト書くのはこれをサポートしてくれるよい方法だと考えてはいます。）

## アーキテクチャは必然がない限り統一する
CySharpのneueccさんのC#大統一理論信者です。笑
C#大統一理論は主にサーバサイドとクライアントサイドの話が語られていますが、
自分としては業務的なシステムの担当が多いため、これに加えて定期、非定期なバッチ処理等も含めて
同じ言語とアーキテクチャで統一することがが良いこと思っています。
(最近バッチフレームワークもリリースしてくださったので、また使わないと！と思っています)  
必然性もなくコロコロとアーキテクチャを混ぜていると保守性が超ダウンします。超です。
何故なら同じことをやる関数でも、言語が異なることによってマージできない「クローンコードは悪」が必ず発生します。  
他にはよく言われていますが言語理解度が全て高い人員など稀なため、人が減る保守時に大きなインパクトがあります。 
担当が作りやすいといった理由で異なるアーキテクチャを使うのは絶対にNGにすべきでしょう。
(恐ろしいことに現実にはこういうのがあったりします。そして保守が面倒で泣きます）
何かの言語や場所に限らず統一するのはいいことです。java1.4あたりの古くから画面と合わせて遅いながらもバッチはjavaで書いてました。
## シンプルイズベスト
趣味開発ではトリックコードは好きだったりするのですが、複数人の開発では保守性の悪さに繋がります。
少々のパフォーマンスの遅さや、多少行数が増えてもシンプルに書きます。
他でも言われていたりしますが自分のコードも数年後に自分にとっては「なんやねんこのコード」だったりします。
極力シンプルにしておくことが未来の自分のためでもあるでしょう。

## コードの適度な分割
すごく大きいクラス、大きい関数というのは保守性が著しく悪くなります。  
プログラミングだけではなく人に伝えること(プレゼンなど)全般にいえると思うのですが、
大きな概念、全体図などから小さな物事へ説明すると、どこの部分か把握しやすく伝わりやすいです。
分類もなくだらっと多くのものを説明されると理解できません。
コードにも言えることで、ある程度分割しておくのは人間の理解しやすい形にすることと言えるでしょう。  
このため処理のステップ単位ぐらいでは関数化しておき、コールされる関数を見ていくこと
で内容が想像できるような作りにしておくことが良いと思います。
関連性があるし・・で長くすると後から見通しが悪くて見るのが大変といった保守性の悪いものになりがちです。  
# まとめ
書き方にフォーカスしたお話になりましたが、いかがだったでしょうか。
ユニットテストも組み込むべしなど別の観点含めみなさんいろいろ思っていることがあるかと思います。
皆さんの意見を聞かせてください！  
今回は自分の考える保守性の高いコードの作り方ということで今回は記事を書いてみました。
何かの参考になることがもしもあればいいなと思っています。
※一旦書いてみましたがもう少し加筆するかも
curl で Cloud Firestore のデータを作成

Cloud Firestore の RestAPI を使ってデータを作成します。

```json:in01.json
{
      "fields": {
        "name": { "stringValue": "宇都宮" },
        "population": { "integerValue": "7592100" },
        "date_mod": { "stringValue": "2020-01-27" }
      }
}
```

```json:in02.json
{
      "fields": {
        "name": { "stringValue": "小山" },
        "population": { "integerValue": "3592100" },
        "date_mod": { "stringValue": "2020-01-27" }
      }
}
```

```json:in03.json
{
      "fields": {
        "name": { "stringValue": "佐野" },
        "population": { "integerValue": "9214600" },
        "date_mod": { "stringValue": "2020-01-27" }
      }
}
```
GOOGLE_APPLICATION_CREDENTIALS で定義されている project の cities に書き込み

```sh:firestore_create.sh
#
export GOOGLE_APPLICATION_CREDENTIALS="***.json"
#
ACCESS_TOKEN=`gcloud auth application-default print-access-token`
#
project_id=`jq .project_id $GOOGLE_APPLICATION_CREDENTIALS | sed "s/\"//g"`
echo $project_id
URL='https://firestore.googleapis.com/v1/projects/'$project_id'/databases/(default)/documents/cities?documentId='
#
curl -H "Authorization: Bearer $ACCESS_TOKEN" \
	-H 'Content-Type: application/json' \
	 -X POST -d@in01.json $URL"t0921"
#
curl -H "Authorization: Bearer $ACCESS_TOKEN" \
	-H 'Content-Type: application/json' \
	 -X POST -d@in02.json $URL"t0922"
#
curl -H "Authorization: Bearer $ACCESS_TOKEN" \
	-H 'Content-Type: application/json' \
	 -X POST -d@in03.json $URL"t0923"
#
```
「コミットメッセージ間違えた！」って時はこれを使うぜ


よくコミットメッセージを間違えてしまうので、教えていただいた方法をまとめておきます:ear:

#4ステップでコミットメッセを直すぜ
1.間違えてしまったコミットメッセを選択。
2.右クリックをし、7c52f31の子を対話形式でリベースを選択。
![スクリーンショット 2020-01-29 17.26.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524422/ddb59001-1679-83bf-1b73-d739e387b9d8.png)

3.今回は一つしかたまたま出て来なかったが、編集したいコミットメッセージを選択。
![スクリーンショット 2020-01-29 17.27.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524422/1f910f31-053c-5118-781f-0e2d98222fc1.png)

4.直したいコミットメッセの文章の上でダブルクリックすると、コミットメッセージが編集できる。
![スクリーンショット 2020-01-29 17.28.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524422/48ed61c8-6395-2784-cd0b-f26627ab9184.png)
RDB脳が理解するDynamoDBのテーブルの設計方法

## はじめに

普段RDB(MySQL、PostgreSQLなど)を使っていて、DynamoDBのテーブルを初めて作ったときに`別物過ぎて全然手出しができなかったので`考え方・設計の方針を書こうと思います。

### 対象読者
DynamoDBのテーブルを初めて作るそこのあなた:baby:

## サンプルケース

ユーザが購入した本を登録するテーブル(`OrderHistories`)を考える。

カラムとしては、

- UserId
- CreateAt
- BookId

何も考えずUserIdをプライマリパーティションキー（RDBの主キー相当）として設定した場合、

- CreateAtで範囲検索
- 特定のBookIdがどれくらい売れたか

が検索できません！（スキャンと呼ばれる全文検索になるので現実的ではなくなる）

:flushed:ってなりますよね？

## DynamoDBのテーブルは辞書型だと考える。

DynamoDBはRDBのテーブルではなく`プログラミングのよくある辞書型`と捉えると理解が早い気がします。

UserIDを主キーにした場合は１レコードが主キーをキーとしたキーバリュー型のデータ、

```json
{ "UserId" : {その他いろいろ} }
```

になっています。

`その他いろいろ`の部分にCreateAtやBookIdがあり、要素（レコード）によってはそのカラムがあるかどうかすら保証されていません。

一応`スキャン`という検索方法で探せなくもないですが、これはテーブルの全データをひっくり返して総当りで見つける方法なのでおすすめできません。

## アクセスパターンを考える

DynamoDBではカラムで気軽に検索できません。

なのでどのカラムで検索を行うかをしっかり想定する必要があります。

今回は
- ユーザのある時刻の範囲で購入した本を表示したい
- ある本の販売数を調べたい
でしたね。

これを実現するために２つの設定が必要です。

## 1.ユーザのある時刻の範囲で購入した本を表示したい

**やること：プライマリソートキーにCreateAtを設定する**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107119/5d9af1e5-bbee-f436-cede-f0fdb77258c1.png)


そのままではUserIdでしか検索できませんが、`プライマリソートキー`を設定することで
UserIdで絞った中で`プライマリソートキー`での範囲検索ができるようになります。


## 2.ある本の販売数を調べたい

**やること：インデックスにBookIdを設定する**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107119/2829bdd3-d152-27df-4252-1b61150dd492.png)

ここはSQLのインデックスに近いものです。

DynamoDBの裏側的にはBookIdをキーにした新しいテーブルができるようです。

```json
{ BookId : {その他いろいろ} }
```

インデックスを作成する際に`その他いろいろ`の中で必要なカラムを選択することができます。

絞れば検索するときに読み込むデータ量が少なくなるため`読み込みキャパシティ消費による`料金が安くなります。



## 困っていること

ある時間範囲で検索したい。SQLで言えばこんな感じ。

```sql

select 
    BookId
from 
    OrderHistories
where 
    CreateAt between timeFrom and timeTo

```

これが難しい。RDBのオートインクリメントされた主キーと違ってバラバラの場所に収まっているため範囲検索しづらい。

苦肉の策として、日別で検索したい場合は、新しい`CreateDate`を作って`YYYY-MM-DD`形式で登録する。

インデックスのパーティションキーとして`CreateDate`、ソートキーとして`CreateAt`を設定する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107119/dc52ca1f-fc89-7e3e-d399-d9764dd16c08.png)


これでYYYY-MM-DD当日中の範囲で検索できる。

その月内で検索する場合はパーティションキーを`CreateMonth`にする。これしかないのか:cold_sweat:

もしこの辺の知見（裏技）がある人は教えてほしいです。:confounded:

## まとめ

1. 検索するパターンを考える。
1. 1.のパターンで使う検索キーに対してインデックスないしパーティションキーを設定する。

です。

RDBがうまいことやってくれていたことを自分で考えて設定しないといけないのでかなりしんどいです。

反面、レコード数無制限、インスタンス管理不要でオートスケール機能、同時接続数の制限がなくなったりとインフラ側の手間が取り払えるのはかなりメリットだと思います。

まだまだ使いこなしているとは言い難いですが、早くその辺の運用上のメリットを感じたいところです。

## 参考文献（いいのがあったら教えてほしい:pray:)

[こまったときの公式ドキュメント](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/Introduction.html)
redux-formでどうやって値を更新するのか躓いた

## 概要
本記事で扱う内容

- 注目しているフォーム(FirstName or LastName or Email)が変更されれば、注目していないフォーム(check box)の値を更新する方法。（以下参照）

![ezgif.com-video-to-gif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395817/b8f7d1ed-121e-9f61-c0b1-ad9543a7a2ab.gif)


## 実装
### Redux-formの最小構成を作成
1. ベースとなるReactアプリを作成する。

最初に`create-react-app your-app-name`コマンドを実行して、ベースとなるreactアプリを作成する。
また、`yarn add redux react-redux redux-form`コマンドを実行し、必要な物をインストールします。
　
2. ここからは、[Redux-form](https://redux-form.com/8.2.2/docs/gettingstarted.md/)公式に記載されている、手順通りに4つのステップを踏みます。

(公式通りなので省略。ベースとなるReactアプリソースコード[Github](https://github.com/tatsuyaHello/redux-form-handson/commit/c5a448de7c29466fee59d9769b72ef15a32cf589))
　
### 注目しているフォーム(FirstName or LastName or Email)が変更されれば、注目していないフォーム(check box)の値を更新
#### 失敗
- 悩んだ点
    - どうやってformからの入力以外でRedux-formで管理している値を変更するのだろう
        - 注目しているフォームの値が変更されたかどうかを検知する方法はどうするの？
            - touched? active? visited?とか使う？
            - 内容が書き換わっているかを比較する？
- 考えた案
    - Redux-formがいい感じにラップしてくれているAction Creatorなどを書いて、それを無理やり適用する？

#### 解決策
私が抱えている問題について検索をかけてもヒットしない。
そのため、最初は上記の案でゴリゴリ実装してました。一応動く状態は作れたけど、***汚い***、***Redux-form使う意味あるのか、、、***などと色々思いました。
公式を見直すと、redux-formのpropsとして、なんか***change function***と書かれた良い感じのものがありました。（[公式](https://redux-form.com/8.1.0/docs/api/props.md/#-code-change-field-string-value-any-function-code-)）

<img width="981" alt="スクリーンショット 2020-01-29 17.02.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395817/92ba2fd5-8718-5b37-151c-e9fff720b1e8.png">

これ使えば、Redux-formとかが良い感じにラップしてくれたまま、Action Creatorとかを使わずにいけるのでは？と思い、使ってみると、以下のように、onChange・・・と、3行追加するだけで、実現したかったことが実現できました。(ソースコード[Github](https://github.com/tatsuyaHello/redux-form-handson/commit/82b873587143ff84f2143441c5be90bcbfc78537)))

```js

        <Field
          name="firstName"
          component="input"
          type="text"
          onChange={(event, field) => {
            props.change('check', false);
          }}
        />

```


![ezgif.com-video-to-gif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395817/b8f7d1ed-121e-9f61-c0b1-ad9543a7a2ab.gif)

## 結論
Redux-formは今もなお、メンテナンスされているので、やりたいことは公式を読み進めると大方実現できる。
Redux-formを使えば、そんなに頑張らなくても良くなる。
Swaggerことはじめ

# 概要
RESTfulAPIを実装する機会ができ、その際にAPIの仕様をコードで管理したく、よく聞くSwaggerについて調べたのでそのまとめです。

# Swagger について
SwaggerはSmarter Bear社が開発するRESTful APIを構築するためのオープンソースフレームワークです。
RESTful APIのインターフェースを表現するための標準フォーマットがSwaggerです。
Version Preffixがついている場合はこのフォーマットを指します。

Smarter Bear社は同時に、Swaggerの標準フォーマットに則ったドキュメントと、そのドキュメントを記述するエディタと、ドキュメントからHTMLや実装の雛形を生成するツールをSwagger Toolsとして開発しています。

| Tool | description |
| ---- | ----------- |
| Swagger Spec | Swaggerの標準フォーマットに則ったドキュメント(JSON/YAML) |
| Swagger Editor | Swagger Specを記述するためのエディタ |
| Swagger UI | Swagger SpecからHTMLを自動生成するツール |
| Swagger Codegen | Swagger Specから実装の雛形を自動生成するツール |
| Swagger Hub | Swagger UIのホスティングサービス |

# Open API Specification 3.0 について
Swaggerは2017年に、Smarter Bear社からOpen API Initiativeに寄贈されて、名称がOpen API Specificationに変更になりました。
これまで標準仕様を指す時はVersion Preffixを付けてSwagger2.0と表現されることが多かったですが、バージョン3.0からはOpen API Specification 3.0 (OAS3.0)と表現されます。

ややこしいですが、寄贈されたのはあくまで標準仕様だけで、Swagger Tool群はSmarter Bear社が引き続き開発を継続しているので、こちらの名称はOpen API Specification Specみたいなことにはならず、Swagger Specのままです。

# Swagger Spec 記法について
## root階層の項目
### openapi
セマンティックなVersionを指定します。2.0までは`swagger`でした。
### security
認証がある場合はここに記述します。[公式ドキュメント](https://swagger.io/docs/specification/authentication/)
### info
API全体の情報について記載します。
### servers
接続先情報です。
### paths
APIのURL情報について記載します。パラメーターやレスポンスはcomponentに用意し、`"#/components/parameters/***"`や`"#/components/schemas/***"`等の形で指定。
### components
`parameters`, `schemas`, `responses`の３項目が基本。APIサーバーのリクエストパラメータは`parameters`、レスポンスJSON/XMLは`schemas`、サーバーエラー等の共通レスポンスは`responses`に定義します。
componentにパラメータやレスポンスなどの情報をモデル化してまとめて記載することで、再利用可能で、Swagger Spec全体の見通しもよくなります。

# まとめ
公式ドキュメントの[パラメータの基本情報](https://swagger.io/docs/specification/describing-parameters/)と[Exampleの指定](https://swagger.io/docs/specification/adding-examples/)については、SwaggerSpecを記載していく上でかなり助けになりました。
リポジトリでファイル管理できて、コマンド一つで仕様書として吐き出せるのでSwagger、便利です。
[ Android ] AlertDialogにListViewを表示する2（完成）

前回の記事ではエラーが発生してListViewを表示できなかった。
https://qiita.com/QiitaD/items/0713d7565ada707133e5

##起こったエラー
「java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.」が発生した。

このエラーの意味（参考URL参照）は
>「親Viewが子Viewを管理しています！
それに反することをすると、当然動かなくなるよ！(=＿=メ)」

らしい…

##コードをチェック
自分のコードを見てみると親クラス（MainActivity）がもつリストビューの用語IDを取得して、それをAlertDialogにセットしようとしていた。これが原因であった。

~~~java
listViewFruits_ = findViewById(R.id.listView);//親クラスのレイアウトからListView取得
//
//アダプターやリストの作成・・・
//
listViewFruits_.setAdapter(myAdapter);

AlertDialog alertDialog = new AlertDialog.Builder(MainActivity.this)
        .setTitle("タイトル")
        .setView(listViewFruits_)//親クラスのレイアウトセットできない
        .create();
alertDialog.show();

~~~

そこで
>listViewFruits_ = findViewById(R.id.listView);

の行を以下のようにnewすることで解決できた。

~~~java
listViewFruits_ = new ListView(this);
~~~

##感想
今回はListViewとAlertDialogであったが、調査したところ他にも起こる事例があったので、ぜひ参考にしていただきたい。

##参考URL
・エラーの意味
http://www.sumahodays.sblo.jp/article/105586834.html
terraformで死活監視(ALBのhalthyhostsを監視)

トピックをChatbotでサブスクライブすれば、いい感じのグラフと一緒にslack通知されます。

```
resource "aws_sns_topic" "cloudwatch_topic" {
  name = "${var.app_name}-${var.env}-cloudwatch-topic"
}

resource "aws_cloudwatch_metric_alarm" "alb_healthyhosts" {
  alarm_name          = "${var.app_name}-${var.env}-alb-healthyhosts"
  namespace           = "AWS/ApplicationELB"
  metric_name         = "HealthyHostCount"
  comparison_operator = "LessThanThreshold"
  evaluation_periods  = 2
  period              = 60
  statistic           = "Average"
  threshold           = 1
  alarm_actions       = [aws_sns_topic.cloudwatch_topic.arn]
  ok_actions          = [aws_sns_topic.cloudwatch_topic.arn]
  dimensions = {
    TargetGroup  = aws_lb_target_group.xxx..arn_suffix
    LoadBalancer = aws_alb.xxx.arn_suffix
  }
}
```
v-forの中で.sync修飾子を使いたい


# 困っていたこと
以下のような状況でitemの名前が変わらなかった

```Vue:parent.vue
<child
  v-for="item in items"
  :key="item.id"
  :item.sync="item"
/>
```
```Vue:child.vue
<template>
  <div>
    <span>{{ syncedItem.name }}</span>
    <button @click="syncedItem.name = 'hoge'">Change</button>
  </div>
</template>
<script lang="ts">
import { Vue, Component, PropSync } from "nuxt-property-decorator"
@Component
export default class Child extends Vue {
  @PropSync('item') syncedItem!: Item
}
</script>
```

# 解決策
以下のようにしたら動いた

```Vue:parent.vue
<child
  v-for="item in items"
  :key="item.id"
  :item.sync="items[i]"
/>
```
Rails5 devise twitterソーシャルログイン ローカル環境でのエラー解消

# ローカル環境でツイッターのソーシャルログインを試したい

以下を参考に実装。
[[Rails] Facebook/Twitter/Googleでのユーザー登録をDevise & Omniauthを使って爆速で実装する
](https://qiita.com/kazuooooo/items/47e7d426cbb33355590e)

## サインアップページでトリのボタンを押すとサインインページに遷移する謎

初回登録ページでトリを押すと。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533120/24b11def-3e00-1d97-0c00-d94f34f0d6c1.png)

ログインページに遷移する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533120/828d0678-21e0-d18d-0caa-6cba7ccbd440.png)

## 答えはコンソールに出力されていた。

```
web | I, [2020-01-29T16:56:34.815302 #7]  INFO -- omniauth: (twitter) Request phase initiated.
web | E, [2020-01-29T16:56:35.089161 #7] ERROR -- omniauth: (twitter) Authentication failure! service_unavailable: OpenSSL::SSL::SSLError, SSL_connect returned=1 errno=0 state=error: certificate verify failed (self signed certificate in certificate chain)
```

SSL認証でエラーになっていた模様。当然だ。localhostだもの。

## 修正

こちらを参考に。[OpenSSL::SSL::SSLError using Twitter #404
](https://github.com/omniauth/omniauth/issues/404)


```rb:config/initailizers/devise.rb
  config.omniauth :twitter, ENV['TWITTER_APP_ID'], ENV['TWITTER_APP_SECRET']
  OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE if Rails.env.development?
```

Development環境のときだけ、 `OpenSSL::SSL::VERIFY_NONE`する。
無事、ツイッターログインできました。
FileMaker Server SSL 設定

FIleMaker Server に　カスタムSSL証明書をインポートする内容です。

###SSL証明書取得
Godaddyで取得しました。

###FileMaker Server 側での設定
Windows Server 2016にホストしているので、コマンドプロンプトから

`fmsadmin certificate create xxx.xxx(ドメイン名） --keyfilepass password`

username とパスワードを入力して生成。

すると、Cstoreフォルダ内に
`serverRequest.pem`
`serverKey.pem`
が出来上がる。

`serverRequest.pem`をテキストエディタで開いて全てをコピーする。

###Godaddyでの設定
上記でコピーした内容をGodaddyのSSL証明書管理画面で設定する。
![スクリーンショット 2020-01-29 16.39.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146151/e72a43f5-7f5a-5a6f-cfe3-dd7534587653.png)

貼り付けて保存する。最後に保存されたすべての変更を送信する。
しばらくすると証明書がダウンロードできる様になる。

###FileMakerServerでの証明書インポート
![スクリーンショット 2020-01-29 16.42.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146151/4e564074-3efc-4180-8c62-23bd2d2b139a.png)


著名済みの証明書ファイルにダウンロードした、`xxxxxxxx.crt`をインポート
プライベートキーファイルにCstoreフォルダ内の、`serverKey.pem`をインポート
中間証明書ファイルにダウンロードした、`gd_bundlexxxxxx.crt`をインポート
プライベートキーパスワードに一番最初に発行したコマンドで設定したパスワードを設定

最後にインポートボタンを押して完了。

お疲れさまでした。
【Rails】link_toいろいろ

## アンカーリンク
```erb
<%= link_to 'サンプル', sample_path(anchor: 'hogehoge') %>

<%= link_to(sample_path(anchor: 'hogehoge')) do %>
  <p>サンプルテキスト</p>
  <p>Hello World!</p>
<% end %>
```

## パラメーター
```erb
<%= link_to 'サンプル', sample_path(id: user.id) %>
<%= link_to(sample_path(text: 'hogehoge')) do %>
  <p>サンプルテキスト</p>
  <p>Hello World!</p>
<% end %>
```

id付きのパスにパラメーター

```erb
<%= link_to 'サンプル', edit_sample_path($user, item: 'hoge') %>
```

## URLを直書き
```erb
<%= link_to 'サンプル', 'https://google.com' %>
<%= link_to '/hoge' do %>
  <p>サンプルテキスト</p>
  <p>Hello World!</p>
<% end %>
```

## Formatを指定
```erb
<%= link_to '見積書PDFを表示する', quotation_path(@order, format: :pdf) %>

<%= link_to(quotation_path(@order, format: :pdf) do %>
  <span>サンプルテキスト</span>
  <span>見積書PDFを表示する</span>
<% end %>
```

## classやstyle等を記述
```erb
<%= link_to 'サンプル', sample_path, { class: 'mb-2', style: 'font-size: 20px;', method: :post} %>
```

## 戻るボタン
```erb
<%= link_to '戻る', 'javascript:history.back()' %>
```

## 参考
[Rails でアンカー付きのリンクの書き方](https://machida.github.io/articles/20160712-anchorlink/)
[【Rails】戻るボタンの実装方法【複数ページ戻ることも可能】](https://qiita.com/nekojoker/items/cb662de7cbb65e438985)
発音にちょっと戸惑う英単語 - アプリ開発編 -

## はじめに
未経験から先月エンジニア就職したばかりのひよっこが初めて記事を書きます🐣
先輩エンジニア🐓にインプットだけじゃ勉強って言えないよって言われたので、なるべくアウトプットしていくようにがんばります🙋‍♀️

### 書くこと
先日、こちらのLTに参加し初登壇させていただきました。
[_あるあるLT〜 お正月だよ！Android & iOS合同 大LT大会 〜 Vol.10_](https://andfactory.connpass.com/event/160747/)
そのときの発表内容です💁‍♀️

# ゆえるようでゆえない
普段からカタカナ語で慣れ親しんでいる単語って、実際に海外エンジニアと英語で話そうとすると、あれ…？発音これでいいのか…な…？と不安になったり戸惑ったりする英単語ってありますよね。
今回はそんなあるあるについて、自身の留学の経験をもとに発表させていただきました。

|発表資料|
|---|
|<a href="https://docs.google.com/presentation/d/e/2PACX-1vRlZwXTwvWW7pJFQSPJ_QpGqxBqEPifCldGp6WzC1rrqOHnUf62c5l_2yiwdDg3DYmTY5tI4KesmKRi/pub?start=false&loop=false&delayms=3000"><img width="480" alt="Screen Shot 2020-01-29 at 11.21.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542937/09569da2-11ca-af53-1687-54ed66465638.png"></a>|

### 発表で紹介した単語
- Warning
- Kotlin
- Label
- Async
- SQL
- Width

発表の持ち時間が5分だったので少なめです。

### 日本人の読み方と、実際の英語での発音に近い読み方
|単語|ジャパニーズっぽい読み方|イングリッシュっぽい読み方|
|:---:|:---:|:---:|
|Warning|ワーニング|ウォーニング|
|Kotlin|コトリン|カッッリン|
|Label|ラベル|レイボー|
|Async|アシンク|エイスィンク|
|SQL|エスキューエル|スィークォー|
|Width|ウィズス|ウィッズ|

※発音はアメリカ英語の場合なので、その他の地域で話される英語の発音とは異なる可能性があります。

## おわりに
🐣の拙い発表にも関わらず温かく見守っていただけて感謝でいっぱいです。
意外な読み方をするなって思うもの、ありましたか？
まだまだ勉強中ですが、今度は技術的な発表ができるようになれたらいいですね💪