OmniAICreator/Qiita-1.07M huggingface dataset:
「データ指向アプリケーションデザイン」読書メモ

# 「データ指向アプリケーションデザイン」読書メモ

個人的に気になったポイント抜粋。

## 1章 信頼性、スケーラビリティ、メンテナンス性に優れたアプリケーション
### パフォーマンスの表現
* p15 レイテンシとレスポンスタイム。レイテンシはリクエストが処理を待っている時間
* p15 レスポンスタイムの計測には平均値を用いるのは良くない。より良いのはパーセンタイルを使うこと。中央値は50パーセンタイル。略してp50。
* p16 外れ値がどれほど悪いかを知るには最も大きなパーセンタイル値を見ること。一般的には95、99、99.9（略してp95 p99 p999）、大きなパーセンタイルのレスポンス値はテイルレイテンシとも呼ばれる　
* p17 **パーセンタイル値の実際、レスポンスタイムのデータを集計するための正しい方法は、ヒストグラム同士を加算すること**
### メンテナンス性
* 運用性、単純性、進化性（拡張性、修正の容易性、プラスティシティ）
### 進化性 変更への配慮


## 2章 データモデル とクエリ言語

### 2.1.1 オブジェクトとリレーショナルのミスマッチ

### 2.1.3 多対一と多対多の関係

### 2.1.5 今日のリレーショナルデータベースとドキュメントデータベース
* p42 データ間の関係性が強い場合、ドキュメントモデルは扱いにくい×、リレーショナルモデルは許容範囲△、グラフモデルが最前○
* p45 CoddもJSON概念。非単純ドメインと呼称
* p45 宣言型と命令型。関係代数（relational algebra）
* p48 CSSは宣言型、JavaScriptは命令型
* p49 Map Reduceは宣言型と命令型の中間のどこかに位置する


### グラフ型のデータモデル
* p52 プロパティグラフモデルとトリプルストアモデル

### 2.3.1 プロパティグラフ

### 2.3.2 Cypherクエリ言語

### SQLでのグラフクエリ
ファイル名で検索した時にファイル内の行数を取得しソートして表示する

```bash
find ファイルパス -name "ファイル名" |  xargs wc -l | sort
```

- `find ファイルパス -name "ファイル名"` ファイルパス配下に合致するファイル名を検索する
- `wc -l` 改行数
- `sort`  入力内容をソートして出力

### 例
テストファイルの行数を昇順に出力する

```bash
find ./ -name "*.test.ts" | xargs wc -l | sort
```

```bash:出力例
25 ./backend/src/utils/__test__/objects.test.ts
26 ./backend/src/utils/__test__/logger.test.ts
```
Laravelにstylelint導入

### 前提
* Laravelのプロジェクトに`stylelint`を導入する
* プロジェクトのCSSはSCSSで書かれている
→ LaravelにSCSSを導入する方法はこちらの記事を参考にしてください。<br>
[LaravelにSCSSを導入する方法](https://qiita.com/mk185/items/1508ac6172c73db7808b)

### stylelintでできること
コードの一貫性を保ち、エラーを減らすことが可能になる
*** 
構文エラーチェックの例だと

```
.sample {
  background-color: #fffffff;
  disply: block;
}
```
無効な16進数のカラーコードとdisplayのスペルミスがあります。stylelintの`color-no-invalid-hex`ルールと`property-no-unknown`ルールでエラーを発見することができます。

その他にもスタイルの重複を避けることができたり、書き方を統一できたり、stylelintを導入すると様々なメリットがあります。

[stylelintのルールについて](https://github.com/stylelint/stylelint/blob/master/docs/user-guide/about-rules.md)

### stylelintの導入
一番簡単な方法は、プロジェクトのルートディレクトリに`.stylelintrc`ファイルを作ることです。
作成した`.stylelintrc`にルールを設定していきます。

例)

```json
{
  "rules": {
    "color-named": "never",
    "declaration-no-important": true,
    "function-url-quotes": "never",
    "number-leading-zero": "never",
    "property-no-vendor-prefix": true,
    "selector-max-type": 0,
    "selector-no-qualifying-type": true,
    "string-quotes": "single"
  }
}
```

### git commit時にstylelintのルールを適用する
ルートディレクトリの`package.json`にコードを追加していく。

```json:package.json
{
  "scripts": {
    "stylelint": "node ./node_modules/stylelint/bin/stylelint.js  resources/assets/sass/*.scss",
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "resources/assets/sass/*.scss": [
      "npm run stylelint",
      "git add"
    ]
  }
}
```

`husky`と`lint-staged`のパッケージをインストールするのを忘れないでくださいね＾＾

### 参考記事
[チームで美しくメンテナブルなCSSを書くための 「Stylelint」導入のすすめ](https://www.webprofessional.jp/taking-css-linting-next-level-stylelint/)
PHP HTMLのformから飛ばされた内容を受け取って表示する

# 目的

- HTMLのformタグ内でのinputとtextareaでの入力を受け取って出力する方法をまとめる。

# 具体的な例

- 下記にformタグの部分を抜粋したHTMLの内容を記載する。

```html
<form method="post" action="sent.php">
  <input type="text" name="name">
  <textarea name="body"></textarea>
</form>
```

- 下記に前述のformタグから送られてきたデータを受け取り表示するPHPの内容を記載する。

```php
echo $_POST["name"];
echo $_POST["body"];
```
MacのBashでReadlineのキーバインド`operate-and-get-next`(Ctrl-O)がきかなかった話

# まえおき

数ヶ月前にMacBook Airを購入しましたが、シェルはBashを使っています。

Bashに対するキー入力は、[Readline](https://tiswww.case.edu/php/chet/readline/rltop.html)が解釈してコマンドラインに反映します。
ある日、Readlineの数あるキーバインドのうち<kbd>Ctrl-O</kbd>が動いていないことに気づき、一時しのぎで<kbd>Esc-O</kbd>に割当ててしばらく使っていたんですが、やっぱり使いにくかったので調査して直した記録になります。


# 環境

- MacBook Air (macOS Catalina)
- GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin19)
- GNU Readline version 8.0 (たぶん)

普段使っている端末はiTerm2ですが、Mac標準の端末で確かめてもやはり同じように動きませんでした。


# 期待する本来の動き

<kbd>Ctrl-O</kbd>には、既定ではReadlineの`operate-and-get-next`が割当てられています。`man bash`に、`operate-and-get-next`についての次のような説明が見られます。

> operate-and-get-next (C-o)
>
>   Accept the current line for execution and fetch the next line relative to the current line from the history for editing.  Any argument is ignored.
>

実際の挙動としては、本来は↓のような動きになります。

![expected_behaviour.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149217/12c6e7bf-9eba-0e57-1252-925696296a62.gif)


入力した`ls -a`がまず実行され、実行後のプロンプトに最後に実行したコマンド(つまり`ls -a`)を最初から表示した状態で待機します。


場面としては、似たようなコマンドを続けて実行する場合や、正しく動くことを都度確認しながら少しずつコマンドを打ちこんでいきたい場合(長い`sed`やちょっと複雑めなfor文など)に使うと便利です。

これをやりたくて<kbd>Ctrl-O</kbd>を何回入力しても、端末はうんともすんとも言わず、困ったわけです。

# 原因

普段仕事で使っているWSLやUbuntuのBashでは問題なく動いているので、Mac特有の問題か…？とか思っていたんですが、どうやら原因は、`stty`が<kbd>Ctrl-O</kbd>の入力をReadlineに届く前に奪い取ってしまっているためのようでした。

`stty`には現在の設定を表示する`--all`(`-a`)オプションがあります。これを実行すると、次のように出力されました(今回の内容と直接関係がない部分は省略しています)。

```sh:出力
# all current settings in human-readable form
$ stty --all
# (省略...)
werase = ^W; lnext = ^V; discard = ^O; status = ^T; min = 1; time = 0;
# (省略...)
```

↑の`discard = ^O`が悪さをしている箇所です。

Readlineが<kbd>Ctrl-O</kbd>を`operate-and-get-next`として解釈する前に、`stty`が入力を受け取って`discord`として解釈してしまっている、という機序のようです。


# 解決

`stty`の`discard`が何をするのかはよくわかりませんが、とりあえず直します。

`~/.bashrc`に次のように追記し、<kbd>Ctrl-O</kbd>を送っても`stty discard`で邪魔されないようにします。

```sh:~/.bashrc
stty discard undef
```

これで動くようになりました。めでたし。


# 参考

今回の不具合について調べていたら、Bashで履歴のインクリメンタルサーチがきかない不具合を直す記事を見かけ、「もしかしたら今回の不具合も…」と思ったらドンピシャでした。

- [bashのキーバインド(キーボードショートカット) まとめ - readlineとbind、ついでにstty編 - うまいぼうぶろぐ](https://hogem.hatenablog.com/entry/20090411/1239451878#f-2585238a)
- [bashショートカットキー備忘録 - Qiita](https://qiita.com/facel/items/d42e4159ff7d1220713d#%E3%82%AD%E3%83%BC%E3%83%90%E3%82%A4%E3%83%B3%E3%83%89%E5%A4%89%E6%9B%B4%E8%A8%AD%E5%AE%9A)
Flutterウィークリー #87

# Flutterウィークリーとは？
FlutterファンによるFlutterファンのためのニュースレター
https://flutterweekly.net/

この記事は#87の日本語訳です
https://mailchi.mp/flutterweekly/flutter-weekly-87

※Google翻訳を使って自動翻訳を行っています。翻訳に問題がある箇所を発見しましたら編集リクエストを送っていただければ幸いです。


# 読み物＆チュートリアル

### 競合するフレームワーク：AlibabaがSDK Flutterをテストします
https://hackernoon.com/competing-frameworks-alibaba-puts-sdk-flutter-to-the-test-88eb8cf1f35a?gi=1c0291fc55a3

FlutterとReact Nativeを比較するためにAlibabaチームが実行したパフォーマンステストに関する興味深い記事。


### Flutterアプリを設計するための初心者向けガイド
https://medium.com/swlh/a-beginners-guide-to-architecting-a-flutter-app-1e9053211a74?

プロバイダーを使用してアプリを構成する方法に関する提案。


### Flutter Webのカスタムカーソル
https://medium.com/flutter-community/customcursor-for-flutter-b6f252c0dcbb

Constantin StanのFlutter Webでマウスカーソルをカスタマイズできるウィジェットを作成する簡単なトリック。


### DartのFlutterの拡張方法を簡単に理解する
https://medium.com/aubergine-solutions/easily-understand-darts-extension-methods-for-flutter-2b3d3d3c698f

拡張メソッドを初めて使用する場合は、Pinkesh Darjiによるこの記事は非常に優れた入門書です。


### スライバーの作成方法：SliverFillRemaining
https://medium.com/flutter-community/how-slivers-are-made-sliverfillremaining-abab6b251930

TomekPolańskiは、SliverFillRemainingの仕組みと使用方法を分析します。


### GitHubアクションでFlutterアプリの正常性をエンドFlutterエンドで監視
https://medium.com/better-programming/monitor-your-flutter-apps-health-end-to-end-with-github-actions-8a9fb1889c6a

GitHub Actionを使用したFlutterアプリのデバイス上でのエンドツーエンドテストの実行に関するチュートリアル。


### SharedPreferences（Android、iOS、およびWeb）を使用したテーマの永続化
https://medium.com/flutterpub/persisting-theme-using-sharedpreferences-android-ios-and-web-1f4431d9dbcd

Tyagi Priyankaによるこのチュートリアルでは、アプリのテーマを変更し、次の実行のためにテーマを保持する方法を示します。


# ビデオ＆メディア

### Flutter ＆Firebaseアプリのビルド
https://www.youtube.com/playlist?list=PL4cUxeGkcC9j--TKIdkb3ISfRbJeJYQwC

Firebase Firestore（リアルタイムデータベース）とFirebase認証を使用して、 Flutterアプリをゼロから構築する方法に関するチュートリアルを含む完全なビデオセット。


### Flutter Web：Firestore CRUD
https://www.youtube.com/watch?time_continue=334&v=VCOH5QWpfpc&feature=emb_title

Flutter WebでのFirestore機能（CRUD）の使用に関するクイックガイド。


### Flutterリキッドスワイプアニメーションを作成する方法
https://www.youtube.com/watch?v=mtgsjGts5SM&feature=youtu.be

Flutterよりオーガニックなスワイプアニメーションを作成する方法に関するチュートリアル。


### Flutter開発者向けの簡単で便利なヒント
https://www.youtube.com/watch?v=bUJEfxUobw4

Flutter開発者向けの興味深いヒントの束。


# ライブラリ＆コード

### excogitatr / pagination_view
https://github.com/excogitatr/pagination_view

インターネットからのアイテムのリストのページ分割を簡素化するFlutterパッケージ。


### MohamedSayed95 / localize_and_translate
https://github.com/MohamedSayed95/localize_and_translate

Flutterアプリを簡単にローカライズおよび翻訳するFlutterプラグイン


### PatilShreyas / Flutter 2GoogleSheets-Demo
https://github.com/PatilShreyas/Flutter2GoogleSheets-Demo

Google AppScriptを使用して、 FlutterアプリケーションからのユーザーフィードバックをGoogleスプレッドシートに保存するデモアプリケーション。


### zonble / flutter_turtle
https://github.com/zonble/flutter_turtle

ロゴを覚えていますか？このライブラリを使用すると、 Flutterタートルグラフィックを作成できます。
「規模あたりのテストケース数はもはや意味をなさない」という問いに対する考え


# 背景
にしさんの以下のツイートをきっかけに、「規模あたりのテストケース数」というメトリクスについて考えてみた。
https://mobile.twitter.com/YasuharuNishi/status/1203344174864453634
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">規模あたりのテストケース数はもはや意味をなさないという意見に賛成する人は、その理由を最低2つと、じゃあ何をするかを答えられるようにしておくこと。ここ試験に出すからな。</p>&mdash; Yasuharu NISHI (@YasuharuNishi) <a href="https://twitter.com/YasuharuNishi/status/1203344174864453634?ref_src=twsrc%5Etfw">December 7, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

(注意)
規模はソースコードの規模であることを前提とする。
"もはや"ではなく、"以前から"意味をなさない理由とした。

# 問いに対する考え

## 「規模あたりのテストケース数」が意味をなさない理由
### その1：有効なアクションを起こしにくい
* 前提：しっかりテスト設計をしている
  * テスト観点ツリーを作成し、テスト観点の不足がないか検証している
  * デシジョンテーブルを作成し、テストケースに不足がないか検証している
  * 状態遷移表を作成し、テストケースに不足がないか検証している
  * 同値分割と境界値分析の方針を決め、方針に従ってテストケースが抽出されているかを検証している
* 「規模あたりのテストケース数」が過去の案件と比べて少ないと判断されたとしても、具体的にどのようなテストケースが不足しているか不明。「規模あたりのテストケース数」のデータだけでは、どのようなテストケースを追加すればよいか判断できない。
* 同じようなテストケースを無駄に追加し、「規模あたりのテストケース数」が過去の案件と比べて同等にすることができてしまう。
* 人は、認知バイアスにより、データの傾向が把握しにくいと、自分の都合のよいほうにデータ分析してしまいがちである。
  * 感情バイアス：好ましくない，精神的苦痛を与えるような厳しい事実を受け入れたがらない人の特性
  * 正常性バイアス：自分にとって都合の悪い情報を無視したり，過小評価したりしてしまう人の特性

### その2：規模の算出が難しい
* 前提：派生開発
  * 変更箇所とその影響箇所に対するテストをする
  * ソースコードを変更してない影響箇所に対するテストも実施する
* 影響箇所も含めた規模を算出することが難しい
* 変更していないところ、つまり変更規模0のところで、変更漏れというバグが発生していることもある。規模0の場合、1件でもテストを実施していれば、規模あたりのテストケース数が∞となってしまう。

※オープンソースを使う、ライブラリを使う、再利用資産を使うなど、自分でソースコードを作成せず、大きな価値を生み出す開発では、規模の計測の仕方が更に難しくなるはず。

## じゃぁ何をするか
### テストカバレッジを活用する
単純にテストが不足しているという情報ではなく、ソースコードのどの箇所に対するテストが不足しているかの情報があれば、テストケースを追加するアクションが起こしやすい。
#### 影響波及パス分析法
影響波及パス分析法によりテストケースの不足箇所を特定し、テストケースの追加要否判断をする
#### Difference Statement Covarage分析法
Difference Statement Covarage分析法によりテストケースの不足箇所を特定し、テストケースの追加要否判断をする

## 意味をなさせるための工夫
### 小さい単位でたくさんのデータを収集し分析する
* 規模あたりのテストケース数は、単体テストでのみ活用する
* 関数単体テストで、テスト設計のルールに従っているかを確認するために、活用する。
* 関数毎に、規模あたりのテストケース数を算出する。
* 規模あたりのテストケース数が、基準値を大幅に上回る/下回る関数を特定し、テスト設計のルールに従っているか確認する。
* 実開発で適用してみた結果、無駄にテストケースを増やしていた関数を特定することができた。ただし、テストケースの不足は、レビューをしていたこともあり、検出できなかった。
* 全体を集計したデータではなく、小さい単位でたくさんのデータを収集すれば、傾向が分析しやすい。異常がある箇所を特定しやすい。

# 参考文献
ゴールに繋がるアクションを生み出すデータ分析活動の事例
http://www.jaspic.org/event/2019/SPIJapan/session3C/3C3_ID019.pdf

統合テストにおいて影響範囲に対するテスト漏れを防止する「影響波及パス分析法」の提案
https://www.juse.jp/sqip/library/shousai/?id=346
https://www.ipa.go.jp/archive/files/000064283.pdf
https://researchmap.jp/reve/presentations/33922777

派生開発におけるテスト漏れを防止するDifference Statement Coverage分析法の提案
https://www.juse.jp/sqip/symposium/archive/2019/day2/files/A3-1_ronbun.pdf
https://www.juse.jp/sqip/symposium/archive/2019/day2/files/A3-1_happyou.pdf

データ指向のソフトウェア品質マネジメント
https://www.juse-p.co.jp/products/view/442
【GAS】問題集を解いた学習記録をGASで管理する

# SpreadSheet+GASで問題集の学習記録を管理

![スクリーンショット 2020-01-07 23.53.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251749/eff791aa-21c8-ae98-ee34-335a0b2d1a3b.png)

以下、スプレッドシートとGASです。
(GASで管理と言っていますが、ほぼスプレッドシートで操作します。)

スプレッドシート
https://docs.google.com/spreadsheets/d/1S8epUJekwi3-K9QUUsAP7RY8Mki2bUKKkcqFYnO9kI4/edit?usp=sharing

GAS
https://github.com/ymmmtym/study-log

## 作ったきっかけ・GASで作った理由

「ベッドの上で寝ながら学習ができる」

[Ping-T](https://ping-t.com/)や[基本情報技術者試験ドットコム](https://www.fe-siken.com/fekakomon.php)にはかなりお世話になりました。
普段はベッドの上でスマホをいじることが多い私ですが、その状態でも学習ができる環境というのは素晴らしいことだと思っています。
「学習=机に向かう」ではなく、「学習=いつどんな環境でも学びたい」という思いでこのスクリプトを書きました。

GASで作った理由としては、主に以下の理由があります。

- 当時はexcelの操作に慣れていた(excelライクで使用できる)
- webアプリ(railsとかdjango)で開発するには大変そう
- ローカルで管理する(公開する必要がない)ので無料でできる

作った当初は特にwebアプリ開発経験もなく、「とりあえず使えればいい」という思いでした。
なので、少し触ったことのあるjsのように扱えるGASだけで作れるということもありGASにしました。

# 使い方

ソースコードはgithubで管理して、chrome拡張機能を使ってGASと連携しています。
詳しくは以下のサイトが参考になるかと思います。
https://qiita.com/tanabee/items/2c51681396fe12b6a0e4

## 問題集シートの作成

![スクリーンショット 2020-01-07 23.39.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251749/5aa40b17-b6b7-96c7-abbf-66256f5963de.png)


まずはツールバーの「scripts」から問題集用のシートを作成してください。
ポップアップが表示されるので、シートの名前を入力してください。
templateシートから問題集用のシートがコピーされます。

## 問題を解く

初回に解く問題の解答はF列の「1回目」に記載してください。
2回目以降は2回目と書かれている列に記載しましょう。
木になる問題はE列にチェックを入れておきましょう。

問題が解き終わったら(余った行があったら)「不要行削除」を実行してください。
要らない行が削除されます。

## 解答を記入する

※初回のみ(2回目以降はA列に解答を記入する必要はありません。既にA列に解答が記載されて入れば正誤判定されます。)

A列に解答を記載してください。
スプレッドシートの関数によって、x回目の解答を記載した右側に正誤判定(◯ or ×)が表示されます。
B列(赤いシート)には正解した回数、C列(青いシート)には不正解の回数が自動的にカウントされます。

## チェックをつけた問題の確認

確認したいシートに移動し「このシートのチェック問題を表示」を実行してください。
チェックをつけた問題の番号がポップアップで表示されます。

## graphシートで正答率を確認

graphシートを確認する前に、「scripts」から「graphシートに移動して全シートのリンクを取得」を実行してください。
チェック数、3回(不)正解、正解率がシートに反映されてグラフにも表示されます。

![スクリーンショット 2020-01-07 23.42.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251749/ff95bf52-5bbd-fd10-242c-e0b3fd075f95.png)

## 解答表示

![スクリーンショット 2020-01-07 23.40.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251749/cf045f16-b7f9-3b46-b4e6-8000528ae13f.png)

1:1セルにチェックをつけるとA列が黒くなり解答が見れなくなります。
問題を解くときはこのモードにして解答が見えないようにしましょう。

また「解答(非)表示」を実行すると、全シートの解答と過去に解いた問題が(非)表示になります。

![スクリーンショット 2020-01-07 23.40.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251749/824eede3-082c-fa06-48b1-2d8850b1de90.png)


# 最後に

大手の問題集サイトには劣りますが、GASを使って簡単に学習記録をすることが出来ました。
今後はWeb公開やRestAPIなどと連携して、幅広く活用出来ればいいなと考えております。

(もし使用してみたい方がいらっしゃいましたら、ご連絡いただければ嬉しいです。)
Arthas Java 診断ツール

# Arthasとは何でしょう？ 
Arthas（読み方：アーサス）はAlibabaがオープンソースとして公開したJava診断ツールです。
開発環境、試験環境、本番環境で、JVMの状態をモニターしたり、障害が発生した時に、JVMを落とさず簡単に診断ができる。jconsole jmap jstackなどJDKツールより強力で、使いやすくできている。

#どういう問題を解決できるのか？
・このクラスはどのJarからロードされているか確認したい！なぜ例外が発生したか？
・私がコミットしたコードが実行されてなかった気がするけど。。。コミットし忘れ？もしかしてブランチを間違った？
・オンラインでデバッグできないので、ログを仕込んで再配備するしかない？
・本番のあるユーザのデータ処理に問題あったが、本番ではデバッグできないし、ローカルでは再現しない！どうしよう？
・今JVMってどういう状況なの？
・リアルタイムでJVMの状況を把握したい！
・FlameGraphを描画してボトルネックを見つけたい！
など様々なシーンで活用できると思います。

#ライセンス
Apache-2.0

#環境
JDK 6以上
Linux/Mac/Windows

#インストールと実行
Linux環境：
```wget https://alibaba.github.io/arthas/arthas-boot.jar
java -jar arthas-boot.jar
```

実行中のJavaプロセスが存在する場合、起動できる。
特定のJavaプロセスを監視したい場合は
jpsで現在実行中プロセスを確認し、そのPIDをパラメータとして渡せばいい。
例：

```
jps
341 Bootstrap

java -jar arthas-boot.jar 341
```
以下のような画面が表示され、シェルのようにarthasの各種コマンドを実行することができます。

![p1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83580/e24e8b50-6f67-5242-e63f-d4f93441499d.jpeg)


オフィシャルサイトでは以下のコマンドで現在のパスにインストールし、実行ファイルas.shも自動で生成するらしい。普段診断ツールとして使うならこちらがおすすめです。

```
curl -L https://alibaba.github.io/arthas/install.sh | sh
./as.sh
```

#Arthasコマンド

##dashboard
![dashboard.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83580/9ea1be8e-6af0-95ac-9e40-43400e2109bd.png)

シェル環境でこんな画面が表示できちゃうと正直すこし感動しますね。
上は現在JVMインスタンス内のスレッド一覧、真ん中の左側はメモリ状況、その右側はGC情報、一番下はOS、JVMのバージョン情報など。Tomcatの場合は性能の概要が見えます。

##thread

現在のJVMプロセス内のスレッド一覧とそれぞれの状態を表示できます。

![thread.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83580/61baabd3-447f-1696-7823-3217aedc253a.png)

さらにスレッド番号指定するとスタックトレースが表示できていまどこのメソッドで止まっているか見えます。

![thread1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83580/318305be-d5c4-d307-6a6c-587f6192bea6.png)

##jad

現在実行中のクラスに対してデコンパイルができます。バグ対応のため、コードを修正したが、本当に修正版が動いているかどうか確認することができます。また、ミスって同じJarモジュールの異なるバージョンを両方ともクラスパスに入っちゃった場合、どれが実際ロードされているか確認できます。

![jad1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83580/31449fee-ccb0-58ee-ef58-dac1a4ce4252.jpeg)
![p2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83580/235ab0e7-14ac-bdc3-688a-948999ba30ca.jpeg)

##redefine 

外部の.classフアイルを読み込み、現在実行中のJVM内のクラスを差し替えることができる。
制限：クラスのフィールドの新規、メソッドの新規はできない。変更は可能。
JVMを再起動せず、Tomcatの場合は、再起動、再ロードせず、クラスのロジックを変更することが来ます。おお～

```
redefine /tmp/Test.class
redefine -c 327a647b /tmp/Test.class /tmp/Test\$Inner.class
```

##sc

現在JVMにロードされたクラスの情報を表示。

![sc.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83580/e32f62a3-03a9-6b73-2c8f-12bb3e2dcb3f.png)

##stack

スタックトトレースの確認

以下test.arthas.TestStack#doGetのスタックトレースを確認する場合

![stack.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83580/b8c55085-5db3-1cc8-487d-0c63ff63db04.jpeg)


##trace

どのメソッドが遅いか。ボトルネック、性能調査で使えそうですね。

![trace.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83580/a34be976-2c9c-b5e8-6086-2de9c8c8e8aa.jpeg)

#その他
web console機能があってWebでarthasのコマンドを実行できるので、複数サーバを診断するときに使えそうですね。
他にもいろいろ使えそうなコマンドがたくさんありますので、詳しくは
こちらを参考してください。
https://github.com/alibaba/arthas
Excelでプルアップを作成

#はじめに
備忘録用です．
Excelってこんなこともできるんですね．

#プルアップのメリット
1.想定したデータを入力してもらえる．
2.入力するべきキーワードを覚えなくてもよい．
3.統一した書式で入力してもらえる．

#手順
1)「データ」選択
2)「入力規則」選択
3)「設定」選択
4)条件の設定を「すべての値」→ 「リスト」に変更
5)元の値で入力項目のセルを指定
Chrome Dev Toolでブックマークレットを実行する

#この記事は
ブックマークレットの作成中にChrome Dev Toolが使えることが分かったので紹介する記事です。
今まで自分は何をやっていたんだ。。と思わされる2019年の年末でした:angel:

タイトルはブックマークレットと書いてありますが、ブックマークレット限定のことではなく、開いているページで追加のJavaScriptをアドホックに実行する方法です。

##サンプルで使うコード

ブラウザで現在表示しているページで実行すると、そのページのタイトルとカノニカルURLをアラートで表示するjavascriptです。コード自体は簡単なものです。


```javascript
javascript:(
    function(){
      const title = document.title;
      var href = document.location.href;
      var canonical = get_canonical();
      console.log('ページタイトル=%s \n href=%s \n カノニカルURL=%s', title, href, canonical);
      alert('ページタイトル：'+title +"\n現在のURL："+href + "\nカノニカルURL：" + canonical);
  
      function get_canonical(){
        var links = document.getElementsByTagName("link");
        for ( i in links) {
            if (links[i].rel) {
                if (links[i].rel.toLowerCase() == "canonical") {
                    return links[i].href;
                }
            }
        }
        return "";
      }
    }
)();
```

さて、Closure compilerを使わずに、こいつを動かしてみます。

##Chrome Dev Toolからjavascriptを動かす
ブックマークレットを動かすページを開き、`F12`キーを押して`Chrome Dev Tool`を起動します。起動したら`Console`パネルを開きます。ログが出ていたら消しておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168315/0ce63b89-d9b2-1e46-7578-b7a00c56b9b2.png)

Chrome Dev Toolのコンソールタブの一番下に入力欄があるので、そこにブックマークレット用のjavascriptのコードをそのまんま貼り付けします。改行したままでOKです。日本語が入っていてもOKです。

**コードをコピー**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168315/edbf2a18-c3d7-e257-325f-9ce3456f9883.png)


あとは、エンターキーを押すだけです。:arrow_down:

**実行！**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168315/67728a79-b762-0595-7bef-1bee8f14ce96.png)

プログラムが実行され、Consoleにlogが出ています。もちろんアラートも表示されます。

コードを書いて、Closure Compilerで短縮化し、ブラウザのアドレスバーに入れて実行し、修正してはClosure Compilerで・・・という手順を踏まずに実行できます。いままでの苦労は本当に何だったのだ。。。


##デバッガーでデバッグする
今まで、ブックマークレット開発で使いたくても使いにくかった`Chrome Dev Tool`のデバッガーも使えます。

実行でブックマークレットのコードで`console.log()`を実行しておくと、ログと一緒に行番号`VM92:6`が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168315/4afb7560-8750-50ed-88d4-a385d076674c.png)

これをクリックすると、Chrome Dev Tool のSourceパネル開き、さきほどConsoleパネルに入力したjavascriptのコードが表示されます。行番号をクリックしてブレークポイントを設定してから再実行すると、ブレークポイントでコードが停止します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168315/829e9c4b-eda3-02fc-7fe7-c97c13377947.png)

scopeパネルで変数の内容を確認できます。変数の値を無理やり書き換えることもできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168315/a625fb84-149c-eb2f-c996-377f3be581f3.png)

~~デバッガーでブレークポイントを設定するのにスクリプトを2回実行する方法を紹介しましたが、1回目の実行で使う方法があれば教えてください。~~

###デバッガーを使う方法
コード内に`debugger`ステートメントを入れておくと、そこで必ずブレークします。Developer Toolのデバッガーが立ち上がるので、そこで確認できます。


#まとめ
:sunflower:ブックマークレットの開発段階では`Chrome Dev Tool`のコンソールから実行するのが一番効率がよさそうです。この作業を繰り返し開発完成したソースコードを、最後に1回だけ`Closure Compiler`でコンパイルしてブラウザにセットするようにしましょう。


#参考資料
Chrome DevTools で JavaScript をデバッグする
https://developers.google.com/web/tools/chrome-devtools/javascript

MDN debugger
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/debugger
Selenium InvalidSelectorExceptionエラーの対処法

# Seleniumを使っていて、InvalidSelectorException エラーが出た場合の対処法

エラーの原因の１つにクラス名にスペースが入っている状態で要素取得しようとする場合に出ます。
例えば、クラス名が"class name"となっている要素の取得をしようと下記のように記述したとします。

```Java:
driver.findElements(By.className("class name"));
```
Seleniumでは、クラスやidなどの属性値にスペースが入っているため
このままだとエラーになるので、
少し記述方法を変えてcssSelector要素を指定して、要素が取得できるようになります。
記述形式は


##### driver.findElement(By.cssSelector("{`タグ名`}[{`属性名`}='{`属性値`}']");

```Java:
driver.findElement(By.cssSelector("div[class='class name']"));
```
というように、cssSelectorを使ってタグ名と属性名、属性値を記述すれば要素を取得できます。

以上です。
UE4後でまとめる個人的なメモ

[CameraBoom] カメラ酔い防止
CameraBoom びCameraSettingsの UsePwanControl Rotatetion をチェックを外すとカメラの回転が絶対座標に固定され　このクラスをアタッチしているキャラの向きに連動されなくなる

BP
-----
AddMovement Input 
Scale Value 1.0以上の値を入れても変化なし

Is Valid
・Input Object に繋げたノードが有効か無効か (アクターが止まっているか動いているかなど)判定して有効なら　IsValid　無効なら IsNotValid へ進む

Get All Actors of Class
指定したクラスの数が取得できる

ブランチノード　
if文

DoOnce　
これ以降の処理は一度しか呼ばれない。　当たった時などにおすすめ

CharacterMovement
-------------
Get Movement Component 
・CharacterMovementコンポーネントにアクセスできる
 
【CharacterMovement】
・IsFalling 地面に着地しているか

Box Collision
----------
Rendering
Hidden in Game -> ゲーム中当たり判定を確認できる 


レベルブループリントの特徴（ステージ固有のルールなどに）
-------------------------
アウトライナーから直接イベントグラフにドラッグ＆ドロップすることが出来る

AI
------------------------
1.まずナビメッシュバウンスボリュームでステージを囲む
2.それからビヘイビアツリー・ブラックボード(黒板)のハッピーセットをコンテンツブラウザで生成
3.ビヘイビアツリーにブラックボードを設定
4.ブラックボードでキー（変数）を作る　例えばプレイヤーなら　Objyect型でActorを後で選択する
5．ビヘイビアツリーでシーケンス作成　（Selectorがどれか　Sequenceが左から全て　Decolatorがその二つに乗せる条件）

6.これが終わればAiControllerを継承したBPを作成してそのBPを適応させたいキャラのBPのPwanの中で変更する

これであとはAIControllerを継承したBPのイベントグラフのBeginplayでRunBehaviorTreeを付けてBTAssetに作ったビヘイビアツリーを入れてあげればビヘイビアツリーのAIによって制御可能になる


タグの場所
----------
![actor.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/497331/96dcdde9-ffd5-8fcf-6a63-e80e0d21710d.png)
TSでClassベースのMixinするときは、constructorをコピーしないように注意する

下記のようなコードで、Mixinをしようとしていた。

```ts
class Loggable {
  get loggerName() {
    return `${this.constructor.name}: `;
  }
}

function applyMixins(derivedCtor: any, baseCtors: any[]): any {
  baseCtors.forEach(baseCtor => {
    Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
      const propertyDescriptor = Object.getOwnPropertyDescriptor(baseCtor.prototype, name);
      Object.defineProperty(derivedCtor.prototype, name, propertyDescriptor);
    });
  });
  return derivedCtor;
}

interface Component extends Loggable {}
class Component {
  exec() {
    console.log(this.loggerName + 'exec anything');
  }
}
applyMixins(Component, [Loggable]);

const c = new Component();
c.exec(); // => `Loggable: exec anything`
```

本来は、`Component: exec anything`と出て欲しいのに`Loggable: exec anything`と出てしまう。

小一時間悩んだ後、Loggableクラスのコンストラクタがコピーされていることに気付いた。なので、`applyMixins`を下記のようにすれば想定通り動いた。

```ts
function applyMixins(derivedCtor: any, baseCtors: any[]): any {
  baseCtors.forEach(baseCtor => {
    Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
      if (name === 'constructor') return;
      const propertyDescriptor = Object.getOwnPropertyDescriptor(baseCtor.prototype, name);
      Object.defineProperty(derivedCtor.prototype, name, propertyDescriptor);
    });
  });
  return derivedCtor;
}
```

TS HandbookのMixinsの項目だと触れていないので注意。
https://www.typescriptlang.org/docs/handbook/mixins.html
【bundler】MacOSX(Mojave)でbundle installで死ぬほどはまった話

# 概要
タイトルの通りなんですが、 `bundle install` 打つと

```shell
$ bundle install
Fetching gem metadata from https://rubygems.org/........
Using CFPropertyList 3.0.1
Following files may not be writable, so sudo is needed:
  /Library/Ruby/Gems/2.3.0
  /Library/Ruby/Gems/2.3.0/build_info
.
.
.
Fetching json 2.2.0


Your user account isnt allowed to install to the system RubyGems.
  You can cancel this installation and run:

      bundle install --path vendor/bundle

  to install the gems into ./vendor/bundle/, or you can enter your password
  and install the bundled gems to RubyGems using sudo.

  Password:
```

と出てpasswordを打っても出来なかった話。

めちゃくちゃはまった...。

# 解決策

https://qiita.com/showylee/items/29220a8bd43fd76474d7

この記事に載っている通り、

```
$ sudo installer -pkg /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg -target /
Password:
installer: Package name is macOS_SDK_headers_for_macOS_10.14
installer: Installing at base path /
installer: The install was successful.
```

このコマンドを叩いて数分待てばいけました。

誰かのお役に立てば。
システムのスピードと品質を両立する為のエラーバジェットとSLI/SLOという考え方

# システムのスピードと品質を両立する為のエラーバジェットとSLI/SLOという考え方

システムの可用性と機能のイテレーションスピードや市場投入までの時間はトレードオフ
(GoogleのGCPは機能のイテレーションスピードや市場投入までの時間を重要視している)

機能のイテレーションスピードを最大化した上で、システム可用性を担保する為にどうすれば良いか？

その最適解の1つがエラーバジェットという考え方

## エラーバジェットとは？
エラー予算
損失可能なシステムの信頼性
許容できる可用性低下の妥協点とも言えます。

開発チームはこのエラーバジェットが基準値を下回ったタイミングでイテレーションは停止して以下を行います。

* システム信頼性の獲得
* エラーバジェットの消費状況の分析/原因特定/対処を行います。

システム信頼性はどう計測し、基準値はどうすれば良いか？
これがSLI/SLOです。

## SLI/SLOとは？

### SLI
システムの信頼性/安定稼働というものをどう計測するかの指標です。
例えば、リクエスト成功率、レイテンシなどを選定します。

シンプルに以下の様な感覚です。

* エラーがたくさん出たら安定稼働できていない
* レスポンスタイム低下していたら安定稼働できていない

### SLO

SLIの数値をモニタリングして、何をもってシステムの信頼性が高いと言えるか、安定稼働しているといえるかの基準値がSLOです。

# この運用によって生まれる開発風景

* エラーバジェットが尽きるまでは、機能のイテレーションスピードや市場投入までの時間を重要視する事ができる
* エラーバジェットが尽きた後は、新機能の優先度を下げ以下を行います。

* システム信頼性の獲得
* エラーバジェットの消費状況の分析/原因特定/対処を行います。

## エラーバジェット消費の対応例

* QA環境や試験セットを改善し、本番環境への移行前に多くのリリースエラーを見つけ出す。
* ロールアウトの自動化
* モニタリング改善
* 不具合のあるリリースをより迅速に発見しロールバックする方法を開発する。

この結果、リリースの頻度が減ったり、リリースごとの変更点が減少してエラーバジェットへの影響が小さくなったりすることもあります。
しかし、一時的にリリースのスピードを落とす事は、将来的に元のスピードで安全にリリースできるようにするためです。
Terraformでも複数条件の三項演算子は使える

# Terraformでも複数条件の三項演算子は使える

## やりたかったこと

AWSのオートスケーリンググループで条件によってオートスケーリングサイズを変更したかった。

* 条件1・条件2が両方trueならサイズを0
* 条件1がtrueならサイズを2倍
* それ以外はデフォルト値

## 実際やったコード

```shell

local {
  test_min     = 2
}

variable "ALLDOWN" {
  default = ""
}
variable "TEST" {
  default = ""
}

resource "aws_autoscaling_group" "test" {
  min_size           = var.TEST == "test" ? var.ALLDOWN == "alldown" ? 0 : local.test_min * 2 : local.test_min

~~~ 略 ~~~

}
```

上記のterraformのコードをapply済みとする。

### 条件1・条件2が両方true

`terraform plan -target=aws_autoscaling_group.test -var TEST="test" -var ALLDOWN="alldown"`

```
~ min_size                  = 2 -> 0
```

### 条件1がtrue

`terraform plan -target=aws_autoscaling_group.test -var TEST="test"`

```
~ min_size                  = 2 -> 4
```

### それ以外

`terraform plan -target=aws_autoscaling_group.test`

```
No changes. Infrastructure is up-to-date.
```

## 解説

```
条件1 ? 条件2 ? "A" : "B" : "C"
```

このような式があった場合、どうなるかというと以下のようになるためである。

| 条件1 | 条件2 | 結果 |
|:--|:--|:--|
| true | true | A |
| true | false | B |
| false | false | C |
| false | true | C |
Rails　道場コース1　エンジニア戦記#6

Progate先生のRuby on Railsの道場コース１にチャレンジ


基本的には先週末に学習した内容を仕様書とちょっとしたヒントのみで
書いていくような内容。


●Railsコマンドによるファイル構成とサーバー構築
●ルーティング、ビュー、モデル、コントローラーを思い出しながら
　ページ表示に必要な記述を行う

●共通のTOPページへのリンクの貼り方、CSS
●投稿一覧ページの作成
　→投稿の一覧を表示するコマンドをわすれたので要復習
●個別の投稿ページは未着手　明日以降


【感想】

何度もやって覚えてしまったからできるようになるのではなくて
想定通りに実現したいためにはなぜこの記述が必要なのかを意識しながら
また記述したあとは訳しながら自分に説明できるようになりたい。
Vagrantでユーザー名が日本語の場合に出るエラー対処

#Vagrantが動かねぇ…
簡単にセットアップできると噂のVagrant。
でもなぜかMyPCでは動かない…
Vagrantのpluginのインストールは出来るんだけど…

#もしかしてユーザー名が日本語なのが原因？
`vagrant box add`が通らない…
なんだかファイルが無いとか、そんなエラーログが出てる気がする…

```bash
Vagrant failed to initialize at a very early stage:

The plugins failed to load properly. The error message given is
shown below.

cannot load such file -- vagrant/vbguest
```

でもファイルはあるし…
もしかしてファイルを探せてない…？

どうやら調べてみると、環境変数を追加すると直るみたい。

変数名 VAGRANT_HOME
変数値 c:\.vagrant.d

という内容でMyPCを再起動。

#さぁvagrant upだ…？
無事`vagrant box add`できたし
`vagrant init`もできてVagrantfileも生成できた。
いざ`vagrant up`だ！！！

…ん？

```bash
VBoxManage.exe: error: Context: "enum RTEXITCODE __cdecl handleImportAppliance(struct HandlerArg *)" at line 957 of file VBoxManageAppliance.cpp
```

なんかまたエラーが出てる…
今度はVagrantというよりは、VirtualBoxがエラー出してるみたい。

まさか！と思ったらやっぱり日本語ユーザー名が邪魔していた…。
VirtualBoxの`環境設定`より`デフォルトの仮想マシンフォルダー`を
c:\VirtualBox VMs
に変更すると無事起動！

#まとめ
日本語ユーザーでプログラミングするべきじゃない（真理
でも変更できないしなぁ…
[Rails]本日のエラー


今度作業する時に、あれ?過去にも同じエラーが起こったことあるぞ!!となった時用に記事として保管しておくのが目的です。
なので、個人的に使用する記事なので投稿内容は大雑把にまとめます。

記事の流れ
1.なんの作業中にエラーが起きたのか
2.エラーの内容
3.対処法
4.原因

以上の流れで書いていきます。


#1.dbをリセットしようとした時

```ターミナル.
rake db:migrate:reset
```

#2.エラー内容

```
ActiveRecord::NoEnvironmentInSchemaError: 

Environment data not found in the schema. To resolve this issue, run: 

        bin/rails db:environment:set RAILS_ENV=development


Tasks: TOP => db:migrate:reset => db:drop => db:check_protected_environments
(See full trace by running task with --trace)

```

#3.対処法

```
rake db:migrate:status
```
上記のコマンドでdbのステータスを確認します。
⬇︎実行内容

```
   up     20191223083031  Create articles
   up     20191223091431  Devise create users
   up     20191225043801  Add name to user
  down    20191225083536  Add frequency to habits
```
どうやら、一番下のマイグレーションファイルが怪しい。。。
確認したところ
habitsテーブルにfrequencyカラムを二回作成していました。。
なので、一番下のマイグレーションファイルを削除してみます。
※downの状態だったら、手動でファイルを削除しても問題ない
⬇︎実行結果

```
== 20191225234523 CreateHabits: migrating =====================================
-- create_table(:habits)
   -> 0.0302s
== 20191225234523 CreateHabits: migrated (0.0302s) ============================

== 20191229141445 AddImageToHabits: migrating =================================
-- add_column(:habits, :image, :string)
   -> 0.0195s
== 20191229141445 AddImageToHabits: migrated (0.0195s) ========================

== 20200101140707 AddDateAtToHabits: migrating ================================
-- add_column(:habits, :date_at, :date)
   -> 0.0231s
== 20200101140707 AddDateAtToHabits: migrated (0.0232s) =======================

== 20200103135302 CreateLikes: migrating ======================================
-- create_table(:likes)
   -> 0.0157s
== 20200103135302 CreateLikes: migrated (0.0158s) =============================

== 20200107020748 AddLikesCountToHabits: migrating ============================
-- add_column(:habits, :likes_count, :integer)
   -> 0.0174s
== 20200107020748 AddLikesCountToHabits: migrated (0.0174s) ===================
```
問題なくできました。

#4.原因
1つのテーブルに同じカラム名のカラムを追加、作成するマイグレーションファイルが重複していたため、migrateコマンドが実行できなかったと思われる。
なぜ二つ追加、作成したかは謎。
参考記事
https://blog.freedom-man.com/no-environment-in-schema-error
WSL1 (Windows Subsystem for Linux) で mDNS な `.local` アドレスを解決する

それは、一通の Slack メッセージが始まりでした。
> WSL(Ubuntu 18.04) で .local を解決できるようにするのってどうすればいいんですかね

## 結論

`powershell.exe` を WSL 内の bash から呼んでしまえばいい。

```console
$ powershell.exe "Resolve-DnsName raspberrypi.local"

Name                                           Type   TTL   Section    IPAddress
----                                           ----   ---   -------    ---------
raspberrypi.local                              A      120   Answer     192.168.1.116

```

## 環境

Windows 10 Pro
バージョン 1909 (November 2019 Update)
ビルド 18363.535
WSL: Version 1 (WSL2 の足音が聞こえているので明確に 1 としました)

## Windows 10 で mDNS (.local アドレス) の名前解決は可能です

[mDNSを使ってローカルDNSサーバーを廃止する](https://qiita.com/maccadoo/items/48ace84f8aca030a12f1#%E3%82%AF%E3%83%A9%E3%82%A4%E3%82%A2%E3%83%B3%E3%83%88%E3%81%8Cwindows10%E3%81%AE%E5%A0%B4%E5%90%88) によると、バージョン 1909(= November 2019 Update)で mDNS 周りの不具合がかなり解消されており、 PowerShell の `Resolve-DnsName` や cmd.exe での ping で `.local` アドレスが発見できるようになりました。

さて、 WSL1 にインストールした Ubuntu 等の `ping` を始めとしたコマンドは、 `libresolv.so.2` [^1] から `nsswitch.conf` を経由して [^2] 名前解決が行われます。
要するに Windows 側の名前解決の仕組みは一切使われません。2016 年から話題になってたみたいですね。 [Can't resolve ".local" (mDNS) hosnames](https://github.com/microsoft/WSL/issues/384)

[^1]: `ldd /bin/ping` でリンク先ライブラリが確認できます。
[^2]: `sudo strace ping raspberrypi.local` でトレースできます。

この時 mDNS なアドレスを解決するアプローチは2つあります。

1. `libnss-mdns` を入れて Linux 上での名前解決ができるようにする
2. なんとかして Windows 側で名前解決する

###  libnss-mdns は討ち死にする

libnss-mdns は avahi-daemon を必要とし、そして avahi-daemon は dbus を必要としますが、 dbus が WSL1 で動きません。討ち死にです。

参考: [Need help making mDNS work](https://github.com/microsoft/WSL/issues/2664#)

### Windows 側で名前解決する

今回の TIPS のメインです。
PowerShell の `Resolv-DnsName`は Windows 側の名前解決を利用します(するようです)。
WSL の bash といっても所詮 `cmd.exe` の代わりに `bash.exe` が動いているだけなので、 **bash 上で Windows の .exe も実行できちゃいます。**

以上のことから `powershell.exe` を bash シェルから呼び出すという今回の TIPS が成立したのです。

## シェル芸、やりたい放題

PowerShell からの出力は bash の STDOUT に流れてくるため、パイプでつなげたい放題です。
PowerShell からは JSON で出力しつつ jq で受けるといったこともできます。

```console
$ powershell.exe "Resolve-DnsName raspberrypi.local | ConvertTo-Json"
{
    "IP4Address":  "192.168.1.116",
    "Name":  "raspberrypi.local",
    "Type":  1,
    "CharacterSet":  1,
    "Section":  1,
    "DataLength":  4,
    "TTL":  120,
    "Address":  "192.168.1.116",
    "IPAddress":  "192.168.1.116",
    "QueryType":  1
}
$ powershell.exe "Resolve-DnsName raspberrypi.local | ConvertTo-Json" | jq -r .IPAddress
192.168.1.116
```

function を定義すればコマンド化も可能です。

```bash
nsfind() {
    powershell.exe "Resolve-DnsName $1 | ConvertTo-Json" | jq -r .IPAddress
}
```

```console
$ ssh pi@`nsfind raspberrypi.local`
```

※ ちょっと微妙な感じですが、とりあえず動く！

## 注意点

もちろん Windows 10 バージョン 1909 の話です。それ以前の方は、まず Windows 10 を最新にしましょう。話はそれからです。

WSL2 になったら Hyper-V 上の VM になるそうなので、たぶん dbus とか動くから avahi-daemon 経由で mDNS が解決できるような気がする。

## あとがき

この方法を見つける前までは

> なのでcmd.exeかPowerShellで解決したIPv4 or IPv6アドレスをコピペするという雑な解決方法

こんな事してたんですけど、自分の書込みをみて思ったわけです。「あれ？WSL から powershell 呼べればいいんじゃね？」と。

さて、、、、仕事しよう。暇じゃないよ。

EoT
ブラウザのユーザーエージェントを表示するブックマークレット

## ブックマークレット

### ダイアログで表示

`window.prompt`メソッドを利用してダイアログで表示する。

```js
javascript:(function() { window.prompt('userAgent', window.navigator.userAgent); })();
```

### コンソールに表示

`console.log`メソッドを利用して Web コンソールに表示する。

```js
javascript:(function() { console.log(window.navigator.userAgent); })();
```

## window.navigator.userAgent

`window.navigator.userAgent`プロパティは、ブラウザのユーザーエージェントを表す文字列を返す。
webpackで複数のエントリーとアウトプットの設定で引っかかったこと

ElectronとTypeScriptを使うためにwebpackを使った。

設定は以下ファイル。

```webpack.config.js
const path = require('path');

module.exports = {
    mode: 'development',
    target: 'electron-main',
    entry: './src/ts/index.ts',
    output: {
        path: path.join(__dirname, "dist"),
        filename: "main.js"
    },
    module: {
        rules: [{
        test: /\.ts$/,
        use: 'ts-loader'
        }]
    },
    resolve: {
        modules: [
        "node_modules",
        ],
        extensions: [
        '.ts',
        '.js'
        ]
    },
    node: {
        __dirname: false,
        __filename: false
    },
};

module.exports = {
    mode: 'development',
    target: 'electron-renderer',
    entry: path.join(__dirname, 'src', 'ts', 'renderer', 'index'),
    output: {
      filename: 'index.js',
      path: path.resolve(__dirname, 'dist', 'scripts')
    },
    resolve: {
      extensions: ['.json', '.js', '.ts']
    },
    module: {
      rules: [{
        test: /\.(tsx|ts)$/,
        use: [
          'ts-loader'
        ],
        include: [
          path.resolve(__dirname, 'src'),
          path.resolve(__dirname, 'node_modules'),
        ],
      }]
    },
  };
```

この状態で、

```shell

webpack --watch
```
を実行しても、２つ目のmodule.exportsしか実行されていない問題に遭遇。

## 解決策
```webpack.config.js
const path = require('path');

const main = {
    mode: 'development',
    target: 'electron-main',
    entry: './src/ts/index.ts',
    output: {
        path: path.join(__dirname, "dist"),
        filename: "main.js"
    },
    module: {
        rules: [{
        test: /\.ts$/,
        use: 'ts-loader'
        }]
    },
    resolve: {
        modules: [
        "node_modules",
        ],
        extensions: [
        '.ts',
        '.js'
        ]
    },
    node: {
        __dirname: false,
        __filename: false
    },
};

const renderer = {
    mode: 'development',
    target: 'electron-renderer',
    entry: path.join(__dirname, 'src', 'ts', 'renderer', 'index'),
    output: {
      filename: 'index.js',
      path: path.resolve(__dirname, 'dist', 'scripts')
    },
    resolve: {
      extensions: ['.json', '.js', '.ts']
    },
    module: {
      rules: [{
        test: /\.(tsx|ts)$/,
        use: [
          'ts-loader'
        ],
        include: [
          path.resolve(__dirname, 'src'),
          path.resolve(__dirname, 'node_modules'),
        ],
      }]
    },
  };

  module.exports = [
      main, renderer
  ];
```
ふりかえりのアクティビティ紹介：DPA

# この記事について

ふりかえりの手法を1つずつ紹介していきます。
ふりかえりをより楽しくしていくためにお使いください。

# DPA（Design the Partnership Alliance）

出典：リーダー塾
 
## 目的

- チームにとって望ましい場または雰囲気を意識的・意図的にデザインします。
- 責任を分かち合う状態を作り出します。
- 関係を維持する上で必要な、目に見える行動基準を作ります。

## 所要時間

５～１５分

## ステップ

導入として、今回（以降）のふりかえりをどんな雰囲気で行っていきたいか、みんなで話し合ってから進めるということを宣言しましょう。
以下の問いについて自由に発言してもらいます。問いは多くても３つほどで、問い１つに対して３～５分です。また、問いの内容について全員で合意できるものを全員で選びましょう。

- どんな雰囲気を作り出したいか？
- その雰囲気を作りだすためにどんなことをしますか？
- 困難なときお互いにどのようにありたいか？
- この関係にどのようなものが持ち込まれると、さらに豊かになるか？
- あなたは個人として、この関係にどんな貢献をしますか？

メンバーが多い場合は、賛成・反対により全体での合意をとってもよいです。全員が賛成のものを選びましょう。全員で合意した内容は、毎回ふりかえりの前に確認するなど、定期的に確認し、アップデートしましょう。

## 事前準備・道具

意見を書き出すための付箋を用意します。問いの数だけ、付箋の色を用意しましょう。また、付箋に意見を書くためのペンを人数分用意します。また、意見を掲示するためのホワイトボードを準備します。
ホワイトボードには、あらかじめ問いの内容を記載しておき、問いの数だけホワイトボードに線を引いてセクションを作ります。

## ファシリテーションのポイント

チームで合意した内容は、全員の目に付く場所においておき、誰かが合意事項を破っている人がいたら、チームのメンバー同士で注意しあいましょう。注意するときには、口頭で叱るのではなく、無言で合意事項を指差したり、笑いながら指摘するなど、チームの関係性を崩さないような注意の仕方を心がけましょう。

# 進め方の例

[#ふりかえりam #1](https://anchor.fm/furikaerisuruo/episodes/ep-1-amPodcast---viva_tweet_xhiguyume-Podcast-ea1lk9)で実践しています。
ngrok と Python で 単に webhook を受け取ってみる

## tl;dr
* botの作成などに webhookにより送られてくるtoken が必要な場合がある
* webhook には外部に公開するサーバーが必要であるが、極力かんたんに webhook を受け取ってみる
* 単に listen するだけでなく、 200 OK を返すだけのサーバーなどは Python を使えば簡単に作ることができた

## 題材
* LINE の Messaging API の Webhook を題材にします。
* これは、JSON形式のデータが POST で送信されます。
* 今回は LINE 側へ Webhook が受信できると申告できるよう 200 OK を返します。

## 流れ
1. Python で 何を受けても 200 OK を返すようなサーバーを作る
1. ngrok で 外部からのアクセスを受け取れる環境を作る
1. ngrok に付属している Inspectツールで 受け取った Webhookの中身を見てみる

## Python で 何を受けても 200 OK を返すようなサーバーを作る
* GETやPOSTに応じて振る舞いを変更したいので、 http.server の BaseHTTPRequestHandler を使います。
    * https://docs.python.org/ja/3/library/http.server.html

* 今回は 80 port で listen し, POST を受け取ったら とりあえず 200 OK だけを返すようにします。

``` python

import http.server
import socketserver
import json

class MyHandler(http.server.BaseHTTPRequestHandler):
    def do_POST(self):
        self.send_response(200)
        self.end_headers()

with socketserver.TCPServer(("", 80), MyHandler) as httpd:
    httpd.serve_forever()
```
* 作成したら実行しておいてください。
```
serving at port 80
```
と表示されていればOKです。


##  ngrok で 外部からのアクセスを受け取れる環境を作る
* ngrok は ローカルホストを かんたんに インターネットに公開することができるサービスです。
    * https://ngrok.com/
    * https://qiita.com/mininobu/items/b45dbc70faedf30f484e
* サインアップしたら 以下のような 画面になるのでガイドに従っていきましょう

|Guide|
|:-:|
|<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32855/7ac862a0-8c39-af8e-5e40-a1708fd1e032.png">|

* コマンドプロンプトで authtoken の登録や http tunnel の起動をしても良いですが、batファイルを使っても便利です。
  * ダウンロードした zip を展開すると ngrok.exe があります。
  * 同じ場所に 以下のような内容の ファイルを作成します。

``` auth.bat
ngrok authtoken 1UFVG5sdtzGXXXXXXXXX
```

``` 80listen.bat
ngrok http 80
```

* それぞれ ダブルクリックで実行してください。
  * auth.bat は一瞬で閉じます。
  * 80listen.bat は 以下のようになるはずです。

|ngrok|
|:-:|
|<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32855/e3cdba94-dbd5-03b4-7db8-14f0dbfb6936.png" width=70%>|

* このウインドウで表示されている Forwarding 欄の ngrok.io で終わるアドレスが、あなたのアドレスです。

## ngrok に付属している Inspectツールで 受け取った Webhookの中身を見てみる
* 試しに 外部からこの ngrok.io のアドレスへ POSTすると
* ngrok の画面 では / へ POST が来たことが表示され

|ngrok|
|:-:|
|<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32855/b4349fbc-52c9-4a78-c25a-4b16e54477eb.png" width=50%>|

* python 製のサーバーの画面では リクエストの中身が表示されます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32855/47a0b703-c68b-7ea0-0b71-653c0fbaddba.png" >

* ブラウザで http://localhost:4040/inspect/http へアクセスするとよりわかりやすく見ることができます。
  * https://ngrok.com/docs#getting-started-inspect

|inspect画面例|
|:-:|
|<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32855/6159c7a4-8076-18f7-c6a0-e12ebd277a4e.png">|
Lambda＋API GatewayのレスポンスをJSONとしてパース出来ない

# はじめに

「[内閣府の祝日CSV](https://www8.cao.go.jp/chosei/shukujitsu/gaiyou.html)をLambda上でJSON形式に加工して、API Gateway経由で使えるようにする」というプログラムを考えたのですが、API GatewayのレスポンスがJSONとして正しくパース出来ないことが分かりました。

Lambda上で動いているRubyプログラムは単体のスクリプトとして問題なく動作することを既に確認していましたが、原因が分かるまで少し時間がかかったので、その記録をまとめてみました。

# 使用した環境

* Lambda（Ruby）
* API Gateway

# 正しく動作しなかったコード

* `JSON.pretty_generate`や`JSON.generate`、`JSON.dump`などでシリアライズした結果を返すと、**API Gatewayを通して取得したレスポンスの前後に不要なダブルクォート（"）が付いてしまい、JSONとしてパース出来ませんでした。**
 * その後にさらに調べてみると、API Gatewayを通さずにLambda単体の状態でもレスポンスの前後に不要なダブルクォートが付いていたため、この現象がAPI Gatewayによるものではないと分かりました。

```ruby:lambda_function.rb
require 'json'
require 'open-uri'

def lambda_handler(event:, context:)
    csv = OpenURI.open_uri('https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv') {|io|
        io.read
    }
    csv = csv.force_encoding("sjis")
    
    array = []
    csv.split(/\r\n|\r|\n/).each_with_index {|row, i|
        next if (i==0) # ヘッダ行は読み飛ばす
        buffs = row.split(",")
        hash = {"date": buffs[0], "name": buffs[1]}
        array.push(hash)
    }
    return JSON.pretty_generate(array)  # この行をJSON.generate()やJSON.dump()に変えても結果は変わらず...
end
```

```text:出力結果の例
"[\n  {\n    \"date\": \"1955/1/1\",\n    \"name\": \"元日\"\n  },...,\n  {\n    \"date\": \"2020/11/23\",\n    \"name\": \"勤労感謝の日\"\n  }\n]"
```

# 正しく動作したコード

* [こちらのページ](https://kingyo-bachi.blogspot.com/2017/10/awslambdaapi-gateway.html)に書かれているように、シリアライズせずにオブジェクトをそのまま返す形にコードを直したところ、正しいJSONをレスポンスとして受け取れるようになりました。
* どうやら、 **「Lambdaの関数の戻り値として文字列のJSONを指定すると、JSONとして二重にシリアライズされてしまう」** ことが今回の問題の原因のようです。

```ruby:lambda_function.rb
require 'json'
require 'open-uri'
​
def lambda_handler(event:, context:)
    csv = OpenURI.open_uri('https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv') {|io|
        io.read
    }
    csv = csv.force_encoding("sjis")
    
    array = []
    csv.split(/\r\n|\r|\n/).each_with_index {|row, i|
        next if (i==0) # ヘッダ行は読み飛ばす
        buffs = row.split(",")
        hash = {"date": buffs[0], "name": buffs[1]}
        array.push(hash)
    }
    return array  # ArrayやHashなどのオブジェクトをそのまま返せばOK！
end
```

```text:出力結果の例
[{"date":"1955/1/1","name":"元日"},...,{"date":"2020/11/23","name":"勤労感謝の日"}]
```

# まとめ

* ある程度調べたところでLambdaの仕様による現象だと分かっていたものの、中々解決策が見つからずに苦労しました。
* 上記の仕様について、AWS公式ページのどこかに記載されているのかもしれませんが、大事な事なのでもう少し分かりやすく書いて欲しかったです。
 * もしかしたら私が気付かなかっただけで、どこかに明記されていたのかもしれません。
 * あるいは私がLambda初心者で知らなかっただけで、暗黙知だったのかもしれませんが...
VueとFlaskでITイベント情報を地図表示するウェブアプリを作った

## はじめに
ネットサーフィンをしていると、[ITイベントポータルサイトのconnpass](https://connpass.com/)がイベント情報を提供するWebAPIを配信している事を知り、開催地などを地図上で表示するアプリがあれば便利なのではないかと思い制作、年始の3日間を生贄に捧げ完成。

## 成果物
[Signpost for connpass](https://signpost4c.herokuapp.com/)
[GitHub](https://github.com/Kanahiro/signpost4connpass)
![スクリーンショット 2020-01-07 21.57.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73197/eaa2e25a-ac60-a687-c3f4-0c24479d5dda.png)


いわゆるSPAアプリケーションで、非同期通信で得たレスポンスを動的に地図表示します。

## フレームワーク・ライブラリと選定理由
- Flask：後述
- Vue.js (Vue CLI)：勉強中であるため、Reactよりしっくり来るため
- Mapbox GL JS (+VueMapbox)：多数の地物を表示するため動作パフォーマンスを重視した
- BootstrapVue：神
- OpenStreetMap（背景地図）：国土地理院の基本地図よりも建物名などが見やすいから

## 各種ポイント
### CORS制限
CORSとは、オリジン間リソース共有(Cross-Origin Resource Sharing)のこと。
簡単には、「許可を得ていない他人のウェブサイトのデータを非同期通信で持ってくるのはダメよ」、と理解している。
今回のケースでは、connpassAPIのレスポンスは、CORS制限のためフロント側で取得する事が出来ない。一度自らのサーバで受けておけばCORS制限には引っかからない。という訳で、当初はfirebaseのhostingやfunctionで対応しようと考えていたが、connpassAPIにアクセスしレスポンスを受け取るサーバをFlaskで構築する事とした。Flaskはとてもシンプルなので、今回のようになんでも良いからサーバが必要な場合に最適だと思うし、個人的に好きだから採用。

### FlaskとVue.jsの環境構築
Vue.jsはnode.jsと組み合わせて使う事が多いと思います。色々調べた結果、Flaskと共存して開発出来る構成に至りました。
<img width="399" alt="スクリーンショット 2020-01-07 21.51.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73197/91a6f0e8-69a1-2072-3546-ea74f6e4eb08.png">

ルートにPythonスクリプトやherokuサーバ用ファイルを配置し、フロント側はvueディレクトリに納めてあります。以下のとおり設定する事で、Flaskは、vue/distをtemplateフォルダとして参照するようになります。

```python

from flask import Flask, render_template, request, jsonify, make_response, send_file, redirect, url_for

app = Flask(__name__, static_folder='./vue/dist/static', template_folder='./vue/dist')


#以下ルーティング…
```

### APIサーバの構築
[connpassAPIの仕様](https://connpass.com/about/api/)に沿ってアクセスし、得たレスポンスをフロントへ返すAPIサーバを以下のようにつくりました。

```python
import urllib.request, urllib.parse
import json
@app.route('/api/')
def getApi():
    keyword_or = request.args.get('keyword_or')
    ym = request.args.get('ym')
    ymd = request.args.get('ymd')
    owner_nickname = request.args.get('owner_nickname')
    start = request.args.get('start')
    order = request.args.get('order')
    count = request.args.get('count')
    all_params = {
        "keyword_or": keyword_or,
        "ym":ym,
        "ymd":ymd,
        "owner_nickname":owner_nickname,
        "start":start,
        "order":order,
        "count":100
    }

    params = {}
    #値がNoneとなっている要素はパラメータから削除する
    for key in all_params:
        if all_params[key] != None:
            params[key] = all_params[key]


    p = urllib.parse.urlencode(params)
    url = "https://connpass.com/api/v1/event/?" + p

    with urllib.request.urlopen(url) as res:
        html = res.read().decode().replace(r"\n","")
        jsonData = json.loads(html)
        return jsonify(jsonData)
```

connpassAPIと同じパラメータを受け、そのままconnpassAPIに投げ、レスポンスをデコードし、jsonとして返しています。完全なる中継サーバという事です。

## 参考サイト
[Vue.js(vue-cli)とFlaskを使って簡易アプリを作成する【後半 - サーバーサイド編】](https://qiita.com/mitch0807/items/c2e84beee6c9a61e86cd)
[BootstrapVue](https://bootstrap-vue.js.org/)
[VueMapbox](https://soal.github.io/vue-mapbox/)
perlなどのsprintf()で整数のゼロ埋めと少数の有効数字の設定を同時にしたい

## 実現したいこと
3.5を003.500のように設定したい

```perl
# 答え
my $text = sprintf("%07.3f", 3.5); # -> 003.500となる
```

## 1. 整数のゼロ埋め
例）3を003のようにゼロ埋めしたい

```perl 
my $text = sprintf("%03d", 3);
```

## 2. 少数の有効数字の設定
例）3.5を3.500のようにしたい

```perl
my $text = sprintf("%.3f", 3.5);
```

## 3. 1と2を組み合わせたい
例）3.5を003.500のように表現したい
以下のように1と2の書式を単純に組み合わせた場合、意図した形式にならない。

```perl
# 意図した形式にならない例
my $text = sprintf("%03.3f\n", 3.5); # -> 3.500となる
```
以下のように設定することで意図した形式になる。

```perl
# 意図した形式になる例
my $text = sprintf("%07.3f", 3.5); # -> 003.500となる
```
少数以下の桁数 + コンマの数（1個）+ ゼロ埋め対象の桁数を```%```と```.```の間に記入する。
例では、```3+1+3=7```なので```07```と記入する。

***
### 参考
[https://stackoverflow.com/questions/28739818/php-how-to-add-leading-zeros-zero-padding-to-float-via-sprintf](https://stackoverflow.com/questions/28739818/php-how-to-add-leading-zeros-zero-padding-to-float-via-sprintf)
初心者によるプログラミング学習ログ 206日目

#100日チャレンジの206日目

twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。

100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。

206日目は

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">おはようございます<br>206日目<br><br>息抜きにprogateでjqueryとcss上級編、あとRuby<a href="https://twitter.com/hashtag/100DaysOfCode?src=hash&amp;ref_src=twsrc%5Etfw">#100DaysOfCode</a> <a href="https://twitter.com/hashtag/%E9%A7%86%E3%81%91%E5%87%BA%E3%81%97%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%A8%E7%B9%8B%E3%81%8C%E3%82%8A%E3%81%9F%E3%81%84?src=hash&amp;ref_src=twsrc%5Etfw">#駆け出しエンジニアと繋がりたい</a> <a href="https://twitter.com/hashtag/%E6%97%A9%E8%B5%B7%E3%81%8D%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8?src=hash&amp;ref_src=twsrc%5Etfw">#早起きチャレンジ</a></p>&mdash; ぱぺまぺ@webエンジニアを目指したい社畜 (@yudapinokio) <a href="https://twitter.com/yudapinokio/status/1214277141807788032?ref_src=twsrc%5Etfw">January 6, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
作業効率アップにポモドーロ・テクニックが有効だったのでChromeのアドインを紹介する

# 作業効率アップにポモドーロ・テクニックが有効だったのでChromeのアドインを紹介する

omoiyari.fmでkakakakakkuさんがポモドーロテクニックを紹介していたので試してみた。
結果的にかなり作業効率の向上が認められたので、技術系ユーザの多いQiitaでも紹介してみようと思う。

## はじめに「ポモドーロ・テクニックとは」

ポモドーロ・テクニックとは1990年代にイタリアの企業家兼作家のフランチェスコ・シリロ氏によって開発されたメソッド。
ポモドーロとはイタリア語でトマトという意味で、トマト型のキッチンタイマーから名づけられた。

基本的には25分作業＋5分の休憩を繰り返すことで、集中力の持続を長く保つという時間管理術。

これがやってみると自分に合っていたのか、目に見えて集中力が上がった。
プログラミングの勉強や、実務にもかなり取り入れたいテクニックだ。

## Strict Workflowというchromeのアドインが便利

ただ、実際にトマト型のキッチンタイマーでポモドーロを実施するのはやや恥ずかしい。
そこでChromeのアドインでポモドーロが使える便利なものを紹介する。

※[Strict Workflow](https://chrome.google.com/webstore/detail/strict-workflow/cgmnfnmlficgeijcalkgnnkigkefkbhd)というアドインです。

## Strict Workflowの主な特徴
Strict Workflowで最も便利なのが

「タイマー起動中はYoutubeやツイッターなどが閲覧不可になること」。
これを使うことで飛躍的にコーディングやブログの執筆作業が捗る。
コーディングは当然PCで行うが、SNSなどの誘惑と常に戦い続ける必要がある。

そこで、このアドインを使うことで25分間の作業中は強制的にSNSや動画サイトの閲覧を禁止する。

自分はこれでかなり集中力・生産性がUPしました（マジでオススメです）


## まとめ
ポモドーロ・テクニックは手軽に出来る効率化ライフハックなのでぜひ挑戦して欲しい。
本投稿で紹介したアドイン以外にも物理的なタイマーやWindowsアプリなど沢山あるのでご自身に合ったものを。

これにプラスしてタスク管理ツールのTrelloも併用するとさらに効率上がるよね。ぜひぜひ。


## 参考

・omoiyari.fm
[https://lean-agile.fm/episode/22](https://lean-agile.fm/episode/22)

・my weblog.
[https://mitsu-kiyo.com/pomodoro-technique-strict-workflow/](https://mitsu-kiyo.com/pomodoro-technique-strict-workflow/)