OmniAICreator/Qiita-1.07M huggingface dataset:
ゲーム開発とアジャイルQA

## はじめに
この記事はグリー品質管理 Advent Calendar 2021の16日目になります。

昨年までは自動化などについて実装例を踏まえて技術的な記事を書いていましたが、今年は自身の担当領域の変化などがあったため、ゲーム開発プロジェクトの中でのアジャイルテスト担当者の心構え、アプローチなどを備忘録的に綴ります。

アジャイル開発自体の手法やチーム全体としてのアプローチの話ではなく、あくまでテスト担当者がどう向き合うかにフォーカスしています。

アジャイル開発と一口に言っても、採用しているアプローチや体制はチームにより様々かと思いますので、一つの参考として頂ければ幸いです。


## どんなチームか
モバイルゲームアプリの開発プロジェクトです。エンジンはUnityを使っています。
自分はα開発が終わりβ開発が始まるころに、数名のテスト担当者のリーダーとしてジョインしました。

アジャイル方法論としてどの様なアプローチを行っているかなどは記載しませんが、アジャイル開発宣言にある以下の価値観を共有しているチーム、としておきます。

> プロセスやツールよりも**個人と対話**を、
> 包括的な**ドキュメントよりも動くソフトウェア**を、
> 契約交渉よりも**顧客との協調**を、
> 計画に従うことよりも**変化への対応**を、
> 価値とする。すなわち、左記のことがらに価値があることを
> 認めながらも、私たちは右記のことがらにより価値をおく。

このアジャイル宣言ですが、従来型の開発サイクルのQAの考え方だと
>**ドキュメントよりも動くソフトウェア**を
>計画に従うことよりも**変化への対応**を

この文が特に気になるのではないでしょうか。
自分も実際にジョインした時には仕様書がほとんど無く、スケジュールも厳密には管理されていない状況に面食らいました。

また、チームは基本リモートでの開発体制になっていて、週に1，2回オフィスに集まる様な状況でした。

## アプローチ
#### リモートでのコミュニケーション
コミュニケーションは基本的にSlack, Zoomを使って行っています。
Slackでのやり取りで済むことも多いですが、ちょっとでも込み入った話であれば会話した方が圧倒的にスムーズに進みます。Zoomは画面共有もできるので話しながら不具合の再現などを見せるのにも便利でした。
また、通話に気軽に参加できるようにするのもポイントです。

- 常に開いているZoomミーティングを準備する
- Slackのハドルミーティングを使う  など

#### BTSの活用
ツールよりも対話を重視するとありますが、BTSは活用すべきです。
それまではあまり使用されておらず、チャットやスプレッドシートなどでも不具合が報告されていましたが、BTSで一元管理するように働きかけました。
あたりまえですがBTSの方が不具合の検索やトラッキングがしやすいです。
また、元々チャットで報告する文化だったため、SlackからBTSに起票できる仕組みを導入し、チームメンバーが不具合チケットを作成しやすくしました。

#### テスト、品質意識の啓蒙
プランナーやエンジニアが自身の実装をテストする文化は根付いていましたが、アプリ全体の品質に関してはなんとなくしか把握できない状況でした。
テスト担当者としては、各自の実装に責任を持ってもらうことは維持しつつ、機能ごとのテスト状況、不具合状況などと共にアプリの品質状況をチームに随時フィードバックし、品質とリスクを正確に把握できるようにすることが大事です。


#### 開発環境の導入
弊社の前例ではQAが開発環境を用意することはなかったのですが、ドキュメントがない場合成果物であるソースコード、スクリプト、アセットなどを直接確認する必要があるのと、速いイテレーションに対応するためにQAも開発環境を導入しました。
基本的にはテストは実機上でビルドされたアプリに対して行いますが、リーダーやテスト設計者はUnityで最新の実装状況の確認ができればビルドを待つ必要がなく、テスト工程が効率化できます。

#### テストツール、テストデータの作成
また、テストツール、デバッグ機能、テストデータを作成する際にも開発環境は必須です。これらは要件を伝えて作成を依頼するよりも使用者であるテスト担当者が作成することで、要望通りのものが作れ、ウェイトタイムも無くなります。

#### 探索的テスト
ゲームのストーリーパートは選択肢によるフラグ分岐などもあるためスクリプトで作成されているのですが、仕様書は一切ありませんでした。
そこでスクリプトからフラグと分岐を抜き出すスクリプトを用意し、それらの一覧と必要なテスト観点をまとめたテストチャータを用意して探索的テストを行いました。

#### テストベースとトレーサビリティ
イテレーションの中で実装を確認して仕様の修正が入ることも多かったため、各機能毎のテストスイートには必ずテストベースを記録して紐付けて管理するようにしました。
仕様書がある場合は仕様書を、仕様質問したチャットのログやmtgの議事録、スクリプトなどをテストベースとしています。
どの情報を元にテストケースが作成されたのかを明確にすることで、仕様変更への対応ができているか把握しやすくなります。



## まとめ
アジャイルQAではテスト担当者は従来よりも開発チームの一員としての立ち回りが求められると思います。また、テストツールの作成やテスト自動化の導入など技術的なスキルも大いに求められるでしょう。
現状でQA体制の構築とイテレーションを回すことはできているので、今後は実機での自動テストの導入などでより効率化を図っていきたいと思います。
お名前.comのメールは、デフォルト設定では、Herokuを使っていると届かないかも？

# 結論

お名前.comのコントロールパネルから、海外からの送信制限をoffにしよう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35462/c0560158-7621-832a-a129-7585f280021e.png)

# はじめに

Railsで作ったDMシステムからメールが送れなくなってた。

大きな事件があって、メールシステム自体を構築し直したタイミングで、上記のDMシステムからもメールが送れないようになっていた様子。

色々試行錯誤したけど、原因はシンプルなものだったので共有しておきます。

# システムの構成

- Heroku
- Ruby on rails
- ActionMailer
- お名前メール

# お名前.comのデフォルト設定

お名前.comのメールは、デフォルトで「海外からの送信制限」がオンになっている。

そのため、海外サーバーであるHerokuで運用していると、IP制限で送信が実行されないようになっている様子。

# 対策

一番上の結論にも書いてあるように、海外からの送信制限をオフにするのが良さそうです。

ただ、セキュリティ上の機能をオフにすることになるので、その辺り注意は必要です。

# 感想

手元で環境再現とかでとっても困ったので、同じことで困っている誰かの時間を、この記事が救っていてほしい。。。
情報システム部とデータ分析


##情報システム部に転職するきっかけ

IT企業で自社開発業務に関わっていたけど、
データ分析やりたい！と以前から思っていたのと
パワハラに疲れたという理由から転職を考えました。

某eエージェントに相談し、社内SEのほうがデータ関われるよ！
データって社外に持ち出せないからね！！と強く言われ、最終的に事業会社の社内SEを選びました。

##実際の業務
・たまーにデータ分析？というかデータの可視化のお仕事
　→しかし、実際はExcelでどうにかできることのほうが多いです。
・ISMSの維持活動のお仕事
　コンサル、審査会社、社内の日程調整等
　標的型攻撃メール関連の計画と実施
・ちょっとしたソフトウェアの導入
　ライセンス更新とか面倒な仕事を自動化するために
　バッチを作成し社内に配布する等
・予算策定、契約関連処理
・社内の人からの問い合わせ対応
・システム側からの業務改善支援

##事業会社の社内SE事情
・たまーにデータ分析？というかデータの可視化のお仕事
ついてフォーカスを当て、記載します。


###データ分析のお仕事例
データをExcelに手入力してるんだけど、自動化したい！
もっと綺麗なグラフにしたい。という依頼が多いです。

Excelで何とかできることも多いですが、やはりBIツールを導入したほうが良いなと思った事例が
あったので紹介します。
(結局のところ、BIツール導入には至りませんでした)

####依頼元の作業フローの確認

１．システムに製品の検査データを入力する
２．システムから、検査データをcsv出力する
３．csvからExcel(マクロや関数が組み込まれている)シートにデータを手作業でコピーする
４．３のデータを利用し、別シートにグラフを作成する

グラフに関しては、以下のようなグラフになります。

https://sakumizu.com/easy-to-understand-3-sigma-management-and-spc-for-beginners/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1189695/ad0967e6-93b1-8a52-fbdf-ff90d33c18c7.png)


1～3の手順をしっかりヒアリングしたうえで、これは直接DBからデータを持ってこれそうだなと思いました。
4については、ExcelでもBIツールでもどちらでも良いと思っていました。ここまでは。

####DBのデータの確認
次にDBのデータの確認をしました。

DBのどのカラムを参照すれば良いかを調査しました。
しかし、ここで驚いたのですが、

DBのテーブル設計書も、システムの仕様書もない！！！
DBのテーブルから、それっぽいデータを持ってきて、これですかね？と聞いても
データに詳しい人がおらず、そうっぽいねという返答しか出てこない…！

システムの管理番号に文字や数字、日付らしきものが入力されていたり
(システム側で制御ができていないこと、部署と担当者により、入力規則がそれぞれだったことが原因)

最終的に、それっぽいデータを抽出することができたので
100％の保証はできないことは伝え、抽出したデータを使用し、データを可視化することにしました。

####グラフを作成する上での要望

・12/1からのデータを10個見たい
・USL(上限・下限)、UCL(Ave＋3σ)、LCL(Ave-3σ)から外れているロットナンバーを確認できるようにして欲しい
・横軸：ロットナンバー
・縦軸：検査データ

####ツールの選定

せっかくなので、BIツールでプロトタイプ作成をし、見ていただきました。
用いたBIツールは以下2つ。あと、Excelです。
・PowerBIで作ったグラフ
・Tableauで作ったグラフ
・Excelで作ったグラフ


####プレゼン結果

結果、惨敗でした。

特に「12/1からのデータを10個見たい」という要望は、BIツールのほうが可動性をもって
グラフに反映できるのでは？？と考えてBIツールの導入を強く勧めていましたが
やっぱり、使い慣れているBIツールが良いとのことでした。

私も上手く、BIツールの良さを説明できなかったことが敗因でした。


###事業会社の情報システム部のデータ分析事情

社内にデータがあるからと言って、データ分析し放題なわけではない。
・仕様書がない場合も多い
・システムやDBのテーブルの理解を自身で突き詰めなければならない

近い距離にいる分、ユーザーからの要望が多い。
・なので、一旦確認したことが覆り、改修、改修の繰り返し

Excelから抜け出せないことが多い
・親しみ慣れている、費用も掛からないExcelが一番だと思っている人が多い

社内SEは営業の側面もある
・ユーザーの信用を得ていないと(あなたは信用できないから)要らないと言われる
・コストがかかるなら要らないと言われる

###来年の目標として

> Excelから抜け出せないことが多い
> ・親しみ慣れている、費用も掛からないExcelが一番だと思っている人が多い

BIツール導入がベストだと思った場合、情シス負担でとにかく推し進めても良い
ということになりました。(上司と相談済み)
「結局使ってもらわないと、良さも分からないから。新しいものに変わっていくときは必ず来るから」というのが理由です。
来年は、チャンス！が来たら、BIツール導入を推進していこうと思います。
OutlookVBAの事前準備

ひょんなことからoutlookVBAを使うことになったので、備忘録もかねて記載

やることは２つ
- タブに【開発】を表示する
- マクロのセキュリティの設定変更

#注意点
- VBAの設定は各PC毎に設定が必要になる為、複数台でoutlookを使用している場合にVBAのコードは同期されない<br>
※コードは同期されないが実行内容自体は同期される
- Excelマクロのように配布は行う事はできません。　モジュールをExportして受け手側importをする方法となる


#設定詳細
###タブに【開発】を表示する

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391923/40ce303d-22f2-ad71-eded-5d4b8c2049f4.png" width=700">


手順1：タブの[ファイル]⇒[オプション]
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391923/f9833f88-78e7-754b-914a-f22ed18ae0ce.png" width="700">

手順2：[リボンのユーザー設定]⇒[開発]にチェック
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391923/d922f968-3bb2-4aa9-5d2a-3728889bfd4c.png" width="700">


###マクロのセキュリティの設定変更

手順1：[開発]⇒[マクロのセキュリティ]
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391923/ad988aeb-ef72-096c-6d26-8e80d6f345c1.png" width="700">

手順2：[マクロの設定]⇒すべてのマクロに対して警告を表示する（すべてのマクロを有効にするでもよいが非推奨）
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391923/7c23c117-66c2-2d24-ba78-167068efbf3a.png" width="700">

手順3：Outlook再起動⇒マクロ有効化（一度有効化すればOK）
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391923/9bdb2b55-80ab-8d1c-e393-df30a59a5a20.png" width="700">
テスト自動化に関心なかった私が、テスト自動化を進める理由

1年くらい前までは、テスト自動化にはそれほど関心がありませんでした。

ただ、自チームの方針で「自動化をやっていくぞ！」というのが決まり、テストベンダーさんやツールベンダーさんが開催するウェビナーを聞いていくうちに、「こりゃ、やったほうが良いな」と思うようになりました。
この記事では、その理由を3つ書きたいと思います。

## 資産になる
一番影響を受けた言葉は「自動テストは資産になる」です。

自動テストは、一度、テストを作ってしまえば、いつでもローコストでテストを実行し、品質を担保することができます。自動テストのカバレッジを増やすほど、プロダクトの品質は高まり、人間はより難しい課題に注力することができます。つまり、増やすほどに豊かになっていきます。

まぁ、そのサイクルを回すためには、初期投資と継続的な投資が必要なのですが。正しい努力をしないと、資産どころか負債になってしまうかもしれません。


## テストしたい項目は、すべてテストすることができる
マニュアルテストの場合、テスト項目のボリュームに対してリソース(人の数や期間など)が足りないときは、テスト項目を枝刈りします(余談ですが、この枝刈りのセンスがQAの良し悪しを分けると言ってもいいかもしれません)。しかし、自動テストの場合、枝刈りをしなくてよく、検証したい項目をすべて検証することができます。コンピュータは疲れませんし、増やすことも容易なためです。

## 退屈しない
回帰テストはバグもあまり出ないし、繰り返しのテストになるので、正直、私はやってると眠くなります。しかし、自動テストを書いてる間は、時間を忘れるほど夢中になれました。マニュアルで回帰テストやるよりは、自動テストで回帰テストを書いた方が楽しい！というのも、「自動化良いな」と思うことの一つです

## おまけ：自動化の課題
ウェビナーでは、よく失敗談が語られてました。ここでは、自動化の課題やよくある誤解を書いておきます

・自動化はコストがかかる。コストカットのために自動化をやるのは、割と無理筋。あくまで開発速度の向上や、品質向上の一環としてやるべき

・バグを検出するのには向いてない。あくまで「ちゃんと動く」ことを確認するのに使うべき。品質が安定していない機能に自動化を導入するのは控えたほうが良い。

・二要素認証に弱い。

・ブラウザの自動化と比べると、アプリはまだ発展途上な印象。できないことが多い。
[py2rb] @staticmethod

# はじめに
移植やってます。
# `@staticmethod` (Python)
```python
    @staticmethod
    def _get_time(scan):
        raise NotImplementedError
```
`Python`のデコレーターは便利そうですが、移植は厄介。

こちらに、[Pythonで classmethod、staticmethod を使う - Qiita](https://qiita.com/msrks/items/fdc9afd12effc2cba1bc)詳しい解説があります。

こちらは、[クラスメソッドとスタティックメソッドについて - Qiita](https://qiita.com/1plus4/items/b37ec6ea90569ffdebfe) `Python`と`Ruby`と`Java`を比較されています。
# どうする？ (Ruby)
```ruby
  #staticmethod
  def _get_time(scan)
    raise NotImplementedError
  end
```
まあ、`@`を`#`に変えて、頑張れ俺。
# メモ
+ Python の `@staticmethod` を学習した
+ 道のりは遠そう
ターミナルの文字の色を変更する

ターミナルの%より左側にある文字列の色を変更する手順を紹介します。

```
username@Macbook-Pro ~ %
```

今回の説明は `Zsh` が設定されている人が対象で、 `Bash` を使用している人は少しやり方が違いますので注意してください。
 macOS の Catalina からデフォルトシェルが `Bash` から `Zsh` に変更されました。
なので Catalina 以上、もしくは `Bash` から `Zsh` に変更された方が対象です。
`echo $SHELL`を行うと現在のシェルを確認できます。

```:実行結果
/bin/zsh
```

#現在設定されているPS1を確認する
 PS1 とは環境変数のことで、この値が%より左の文字列を表現します。
現在の値が知りたい場合は、`echo $PS1`を実行してください。

%は変数を認識するキーワードとなっており、% + 文字で構成されます。
例えば今回の実行結果を例に取ると`%n` はユーザ名を表し、 `%m` はホスト名を表しています。
詳しく知りたい方は[こちらの記事](https://tegetegekibaru.blogspot.com/2012/08/zsh_2.html)を参照してください。

```:実行結果
%n@%m %1~ %# 
```



#文字列の色を変える

ルートディレクトリにある`.zshrc`を編集します。
ターミナルから行う場合は、`vi .zshrc`を、 finder から行いたい方は`⌘ + shift + .`で隠しフォルダを表示し、編集してください。

##色の指定方法
下記の表の名前か数字を使用することで、色を指定することができます。
%Fと%fで挟まれた文字列が指定された色に変更されます。
こちらがフォーマットとなります。

```
%F{名前 or 数字} 色変更したい文字列　%f
```

| 名前| 数字 |
|:---|----:|
|black|0|
|red|1|
|green|2|
|yellow|3|
|blue|4|
|magenta|5|
|cyan|6|
|white|7|

```:追加内容
export PS1='%F{6}%n@%m %1~ %f%# '
```

ターミナルを閉じて、起動すると色が変更されていると思います。

<font color="DarkTurquoise">username@Macbook-Pro ~</font> %

#ミスしたと思ったら
export PS1='文字列'が変な文字列になってしまって元に戻せなくなっても問題ありません。
`.zshrc`ファイルに追加した`export PS1=任意の文字列の設定`を削除し、ターミナルを再起動すると初期状態に戻ります。

```:ページトップの表記
username@Macbook-Pro ~ %
```


#参照

https://qiita.com/mollifier/items/40d57e1da1b325903659

https://tegetegekibaru.blogspot.com/2012/08/zsh_2.html
Tweepyでの検索まとめ

#Tweepy　検索まとめ
1.ユーザのアカウント名の取得
**tweet.user.name**

2.ユーザのアカウント名の取得
**tweet.user.screen_name**

3.ツイートのリツイート数の取得
**tweet.retweet_count**

4.ツイートのいいね数の取得
**tweet.favorite_count**

5.ツイートの日時の取得(datetimeオブジェクト)
**tweet.created_at**

6.ツイートの本文を取得
**tweet.full_text**

7.ユーザが今までにいいねした数を取得
**tweet.user.favourites_count**

8.ユーザのフォロワー数を取得
**tweet.user.followers_count**

9.ユーザのリストの数を取得
**tweet.user.listed_count**
Macでgitが使えなくなった

Macをアップデートしたら、下のようなgitが使えなくなる場合があります。

```
xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
```

そんな時はターミナルで下記のコマンドを実行してxcodeをインストールしてください。

```bash
xcode-select --install
```
Next.jsでpropsを使ってテキスト情報を渡す


Next.jsでpropsを使ってテキスト情報を渡す方法です。
test.jsでtitleという変数にテキスト情報を詰め込んで、test2.jsに渡します。


```JavaScript
test.js

import React from 'react';
import Test2 from './test2';

function  Test() {
  return (
    <div style={{ textAlign: 'center' }}>
      <h1>Test1</h1>
      <Test2 title="from test1 to test2"/>
    </div>
  );
}

export default Test;
```

title="from test1 to test2"
のところで設定。


```JavaScript
test2.js

import React from 'react'

const Test2 = (props) => {

    let title = props.title;

    return (
        <div>
            <p>Test2</p>
            <p>{title}</p>
        </div>
    )
}

export default Test2
```

###結果
![スクリーンショット 2021-12-14 14.36.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1942691/564e3b22-84f6-105b-5211-c05bd54d3085.png)

無事テキスト情報が渡りました！
ただ、残念ながら値情報は渡せないようです。

値を渡したい場合は、useContextを使用します。
https://qiita.com/Pirosiki_/items/c8648bca23d4dc72287d

###参考にさせていただいたサイト様
https://qiita.com/rio_threehouse/items/7632f5a593cf218b9504
ターミナルでGitHubのSSH接続 from MacBook(備忘録)

[環境]
MacBook Pro


#１.SSH鍵を確認する

```
[ターミナル]
$ ls -al ~/.ssh
```
#2.身に覚えがないので、リセットする

```
[ターミナル]
$ rm -rf ~/.ssh
```
#3.SSH鍵がリセットされたことを確認

```
[ターミナル]
$ ls -al ~/.ssh
ls: /Users/{ユーザー名}/.ssh: No such file or directory
```
(※No such file or directory：　訳) 必要とされるファイルもしくはディレクトリがありません。 )

#4.新しくSSH鍵を作る

```
[ターミナル]
$ ssh-keygen -t rsa
```
#5.質問にEnterで答える

```
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/{ユーザー名}/.ssh/id_rsa): 
```
"訳)公開/秘密rsaキーペアを生成します。
キーを保存するファイルを入力してください"

`Enterキー`を押す

####2個目の質問をされる

```
Created directory '/Users/{ユーザー名}/.ssh'.
Enter passphrase (empty for no passphrase): 
```
"訳) ディレクトリ '/Users/{ユーザー名}/.ssh'を作成しました。
     パスフレーズを入力します（パスフレーズがない場合は空）："

`Enterキー`を押す

####3個目の質問をされる

```
Enter same passphrase again:
```
"訳) 同じパスフレーズをもう一度入力します。"

`Enterキー`を押す

#6.SSH鍵が作られる。

```
Your identification has been saved in /Users/{ユーザー名}/.ssh/id_rsa.
Your public key has been saved in /Users/{ユーザー名}/.ssh/id_rsa.pub.
~省略~
```
"訳) IDは/Users/{ユーザー名}/.ssh/id_rsaに保存されています。
    公開鍵は/Users/{ユーザー名}/.ssh/id_rsa.pubに保存されています。"

#7.作った鍵の内容をコピーする

```
[ターミナル]
$ pbcopy < ~/.ssh/id_rsa.pub
```

#8.git hubのサイトへ移動する
自分のアイコンを選択
↓
**[setting]**を選択
↓
**[SSH and GPG Keys]** を選択

![SSH keys.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388076/71f64af8-3390-a9f9-4b5e-55b14972b38b.png)


#9.SSH接続をする
**[New SSH key]** ボタンを選択
↓
鍵をgithubと接続する

:::note info
・Titleに自分がわかりやすい名前を記入
・keyのところへさっきコピペした内容を貼り付ける
:::

**[add SSH Key]** を押す
↓
鍵がGitHubと接続できた！

![スクリーンショット 2021-12-14 14.21.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388076/d7bf761d-17d2-a6ab-b53b-835546dd9fe6.png)

#10.ターミナルで作った鍵と、GitHubが接続されているか確認する

```
[ターミナル]
$ ssh -T git@github.com
```

```
Hi{ユーザー名}! You've successfully authenticated, but GitHub does not provide shell access.
```
訳)こんにちは{ユーザー名}！認証に成功しましたが、GitHubはシェルアクセスを提供していません。

#####"接続完了"
【Vue.Router】404ページへの遷移


# 404ページへの遷移
urlに存在しないページへのpathをリクエストした場合の404ページの表示方法

## 環境
@vue/cli 4.5.12

## 手順

ルーテイングを管理する`router/index.js`で以下のように設定。

```js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
//NotFoundコンポーネントをimport
import NotFound from '@/someDir/NotFound.vue'

Vue.use(VueRouter)

const routes = [
 
  {
    path: '*', //設定したurlにいずれもマッチしない場合
    // redirect: '/', ※redirectオプションは任意で設定
    component: NotFound //NotFoundコンポーネントに遷移

  }
]

const router = new VueRouter({ //routerインスタンスを作成
  mode: 'history',
  base: process.env.BASE_URL,
  routes 
})

export default router

```


* NotFound.vue
    * 表示させる内容は任意


``` someDir/NotFound.vue

<template>
  <div>
      <h1>404 ページが存在しません。</h1>
      <button @click="goHome">ホームに戻る</button>
  </div>
</template>

<script>
export default {
    methods:{
        goHome(){
            this.$router.push('/') //ボタンを押した時の遷移先
        }
    }
}
</script>


<style>

</style>
AssistiveSignalsを加えたデータで学習したDNNはどうなるか

# 概要

敵対的攻撃を応用し、モデルの精度を向上させるAssistive Signalsという摂動を提案。

[Physical world assistive signals for deep neural network classifiers -- neither defense nor attack](https://arxiv.org/abs/2105.00622)

# 敵対的攻撃

DNNは敵対的摂動と呼ばれる小さなノイズによって簡単に騙されることがわかっています。

![adv_sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/422144/fd4c9043-03a1-5548-c7ce-8889d6bc5d26.png)

敵対的攻撃は、具体的には、以下のような最適化問題を解くことで敵対的摂動を生成します。

$$\underset{\delta\in S}{max}\ L(\theta,x+\delta,y)$$

$\delta$が求めるノイズ、$x$が入力データ、$y$が入力データに対応する正解ラベル、$L$が損失関数。

攻撃者は正しいラベルに分類した時に損失が大きくなるような$\delta$(ノイズ)を求めます。

# Assistive Signals

では逆に、次のような最適化問題を解くとどうなるか。

$$\underset{\delta\in S}{min}\ L(\theta,x+\delta,y)$$

この最適化問題の意味としては、「正解ラベル$y$に対する損失関数$L$の値が最小になるような$\delta$を求める」となります。すなわち、モデルが**正しく**分類しやすくなるような$\delta$(ノイズ)を求める事になります。この$\delta$をAssistive Signalsと呼びます。

## 注意点

Assistive Signalsは、入力データが正しく分類されるようなノイズを乗せるため、分類前からその入力データの正しいクラスが分かっている必要があります。そのため、未知のデータというものを用意することができません。

## 利用場面

物体検出をしたい時、その物体全体に対してノイズを張り巡らせることは現実的ではありません。そこで著者らは、パッチと呼ばれる小領域に対してのみノイズを加えることを提案しています。このようにすることで、シールのようなものでノイズを再現することができます。

# 実験

気になった点があったので、実験（検証）してみました。

疑問点「Assistive Signalsで学習したモデルはどう変わるのか」

## 方法

**標的型攻撃としてのFGSM**を利用して、各入力画像に対して、それぞれの正解ラベルに対する損失を小さくするような摂動を生成しました。この摂動をAssistive Signalsとします。また、クリーン画像のみで学習したモデルを基にAssistive Signalsを生成しました。

画像データセット：Fashion MNIST

eps = 0.10

各trainデータは60000枚、各testデータは10000枚。

## ソースコード

[Google Colaboratory](https://colab.research.google.com/drive/1owSRFj-bNM6Gehb4Zqn6mG4gHbHO-5Fx?usp=sharing)

## 結果

「クリーン画像のみで学習したモデル」をモデルA

「Assistive Signals入りの画像のみで学習したモデル」をモデルB

「Assistive Signals入り画像とクリーン画像を5:5で学習したモデル」をモデルC

とします。

以下の表の数値は各Accuracyの値です。

|Input imgs|モデルA|モデルB|モデルC|
|:-:|:-:|:-:|:-:|
|assisitive train|N/A|0.9935|0.9930|
|clean test|0.8765|0.4291|0.8626|
|assistive test|0.9447|0.8995|0.9943|
|attacked test|0.1588|0.303|0.1412|


Assitive Signals入りの画像で学習させると**精度が下がりました**。

また、確かにAssistive Signalsを含む画像に対するaccuracyは**cleanに比べて高かったです**。

ちなみに、今回Assistive Signalsを生成するのにartのFGSMを使いましたが、仕様上Classifierの精度が高いことを前提として摂動を生成しているので、モデルBの攻撃成功率が低いのは当然です。

# 追加実験
Assistive Signals入りの画像は「正解ラベルに誘導するようなノイズの入った画像」と言えます。つまり、そのノイズ自体に画像を識別するような特徴量が含まれていると考えられます。

そこで、「Assistive Signals入りの画像が識別に必要な特徴量を含んでいるなら、少数のデータでも十分な精度を得られるのではないか」と考えました。

## 方法
いざ実験です。trainデータを上の実験の半分である30000枚にします。そして、clean trainだけで学習したモデル(A')と、assistive trainだけで学習したモデル(B')を比較してみます。

## ソースコード

[Google Colaboratory](https://colab.research.google.com/drive/1owSRFj-bNM6Gehb4Zqn6mG4gHbHO-5Fx?usp=sharing)（上と同じ）

## 結果
以下の表の数値は各Accuracyの値です。

|Input imgs|モデルA'|モデルB'|
|:-:|:-:|:-:|
|train|0.8345|0.9762|
|clean test|0.8182|0.4441|

そう上手くはいきませんでした。むしろ下がってしまいました。ただ、trainに対してはすごい精度です。

この結果と上の実験のモデルB・Cの結果から、Assistive Signals入り画像を教師データとした学習はよろしくないことがわかりました。おそらく、モデルが獲得する特徴量が限定的になってしまうのがAccuracyの低下につながっているのではないかと考えます。過学習にもなりやすそうですね。
dbt + BigQueryで出力するデータセットを変更する

# 背景

dbtでモデル定義すると基本的には接続時に指定した、デフオルトのデータセットにモデルが出力されます。モデルの出力先を別のデータセットにしたい場合のメモです。

# 実装

以下のようなdir構成を想定。

- first_table -> first_dataset
- second_table -> second_dataset 

に出力したいとします。

```.
├── README.md
├── dbt_project.yml
├── macros
│   └── get_custom_schema.sql
├── models
│   ├── first_dir
│   │   └── first_table.sql
│   └── second_dir
│       └── second_table.sql
~略~
```

dbt-project.ymlに以下のようカスタムスキーマを定義します。

```yaml:dbt-project.yml
name: 'my_new_project'
version: '1.0.0'
config-version: 2

profile: 'my-profile'

source-paths: ["models"]
analysis-paths: ["analysis"]
test-paths: ["tests"]
data-paths: ["data"]
macro-paths: ["macros"]
snapshot-paths: ["snapshots"]

target-path: "target"  
clean-targets:         
  - "target"
  - "dbt_modules"

models:
  my_new_project:
   first_dir:
      schema: first_dataset
      +materialized: table
    second_dir:
      schema: second_dataset
      +materialized: table
```

上記定義のみだと `<target_schema>_<custom_schema>` のdatasetに吐かれてしまうので、 `macros/get_custom_schema.sql` を変更して、custom_schemaのロジックを変更します。

```jinja:macros/get_custom_schema.sql
{% macro generate_schema_name(custom_schema_name, node) -%}
  {%- set default_schema = target.schema -%}
  {%- if custome_schema_name is none -%}
    {{ default_schema }}
  {%- else -%}
    {{ custom_schema_name | trim }}
  {%- endif -%}
{%- endmacro %}
```

これで、first_dir以下のsqlファイルの出力はfirst_datasetに、second_dir以下のsqlファイルの出力はsecond_datasetになります。

# 参考

- Twitter で @takimo さんに教えていただいたやり方です(感謝)
- [dbt#Using custom schemas
](https://docs.getdbt.com/docs/building-a-dbt-project/building-models/using-custom-schemas)
- [DevelopersIO#[dbt] custom schemaを使って普段とは別のスキーマ下にデータモデルを作成する](https://dev.classmethod.jp/articles/dbt-custom-schema/#toc-6)
バージョン不一致でdockerのpostgresqlに接続できなくなった件

###gitリポジトリを更新したらローカルDBに接続できなくなった
表題の件解決にいたるまでの覚書です。

プロジェクトのphpのバージョンが8.1になったということなので
git pullしてローカルをアップデートしたら
dockerのコンテナの1つが立ち上がらなくなってDBに接続できなくなった。

とりあえずdockerのログを確認する。

```
The data directory was initialized by PostgreSQL version 13, which is not compatible with this version 14.1.
```
![docker.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2216616/43c1dab6-fa71-bb6b-2f84-75d3746ab6e3.png)


バージョンの不一致らしい。phpのバージョンアップと共にpostgresのバージョンも上げたようだ。
なのでpostgresqlのバージョンを13.5→14.1に上げた・・・が立ち上げなおしても上記のエラーが出続ける。
ネットで上記のエラーログを検索してもバージョンアップorダウンで対応しているものが多数で自分のケースにそのまま当てはめるのが難しそう。


###最終的に解決した方法
色々試したが今回は最終的にdockerのvolumeを削除して立ち上げなおすことでなおった
![docker2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2216616/a25f65b0-f330-7757-3453-ae086f395535.png)



###解決するまでに試した方法
・docker compose rm -f コンテナ名
・コンテナを全て削除してビルドしなおす
・コンテナ、イメージを全て削除してビルドしなおす
・Dockerfileの修正
（修正前）yum install -y postgresql13 && \
（修正後）yum install -y postgresql14 && \

解決法がわかっていれば作業自体は一瞬で終わるのだが
そもそもdockerをよく理解してないものだからこの程度でも原因を探すのに苦労するのである。
1個ずつ覚えていきたい。
sedを実践的に使う

## 概要
sedを使っていろんな場面を想定して、例題を交えて書いていこうと思います
記事も少しずつ付け加えていく予定です

## 使い方例

### logから特定の文字を抜き出す

想定 10-1.log.7.gzなどを検索して、`200`を含むかつaaaのパラメータの値を取得したいと思います

grep結果がこんな感じだとします

```
10-1.log.7.gz:2021-12-10T22:51:20+09:00{message:200.201.111.222 - - [10/Dec/2021:13:51:20 +0000] \"GET /show/data.html?aaa=11345&bbb=4577&ccc=5&dd=hoirjl56na HTTP/1.1\" 200 2 \"-\" \"-\" \"-\" \"1.061\" \"-\" \"-\"}
```


順番がしっかりしていれば以下でとれますが

```
zgrep "message" 10-* | grep " 200 " | awk -F'[=& ]' '{print $8}'
```

aaaがどこにあるかわからないので正規表現で取得したいと思います

```
 zgrep "message" 10-* | grep " 200 " | sed -e "s/^.*aaa=\([^&]*\)\&.*$/\1/"
```

結果：`11345`が取れます

### point
- `\(` `\)` で囲まれた部分が抜き出せます
-  `\1`を置き換え文字部分に設定すると上記で括弧に囲まれた部分が抽出できます
-  `[^&]`この部分ですが、一番初めに&を出現する以外の全てとなるためaaaの値を取ることができるようになります



### 参考

https://www.techscore.com/blog/2016/03/14/%E3%81%82%E3%81%88%E3%81%A6%E3%81%84%E3%81%86%E3%81%BB%E3%81%A9%E3%81%A7%E3%82%82%E3%81%AA%E3%81%84sed%E5%85%A5%E9%96%80/
どうしても忘れてしまうショートカット集

どうしても忘れてしまうショートカットをメモしておきます。

---
# Xcode

## Find
* shift + Cmd + F：プロジェクト全体を検索する
* control + Cmd + G：検索後、次の検索結果に移動
* control + shift + Cmd + G：検索後、前の検索結果に移動

* control + shift + Cmd + F：Find Selected symbol in Project
* control + shift + Cmd + H：Find Call Hierarchy

* Cmd + F：ファイル内の検索
* Cmd + G：検索後、次の検索結果に移動
* shift + Cmd + G：検索後、前の検索結果に移動

## Editor
* control + shift + Cmd + A：Authorsの表示、非表示切り替え

* control + Cmd + E：選択した変数をまとめて変更

* control + Cmd + 0：フォントサイズのリセット
* Cmd + +：フォント拡大
* Cmd + -：フォント縮小

## Product
* Product/Show Build Folder in Finder

## Debug
* Cmd + ¥：Break Point の追加・削除
* Cmd + K：Clear Console
* Option + Cmd + K：Reload Console

* Cmd + コード内のクラス・メソッド・変数をクリック：Create Column Breakpoint


---
# テキスト操作

## 選択系
* トリプルクリック：1段落をクリック
* option + shift + 矢印キー：左右の単語を選択する

## 移動系
* option + →：右に一単語移動
* option + ←：左に一単語移動

* control + F：右矢印と同じ
* control + B：左矢印と同じ
* control + P：上矢印と同じ
* control + N：下矢印と同じ

* fn + 上矢印：page upキーと同じ (画面を上にスクロールする)
* fn + 下矢印：page downキーと同じ (画面を下にスクロールする)
* fn + 左矢印：homeキーと同じ (画面最上部までスクロールする)
* fn + 右矢印：endキーと同じ (画面最下部までスクロールする)

## 編集系
* control + H：deleteキーと同じ
* control + D：カーソルの右の文字を削除する
* control + K：行または段落の末尾までのテキストを削除する

* control + T：カーソルの左右の文字を入れ替える


---
# Finder

## 表示系
* F11：デスクトップの表示／非表示を切り替える
* スペースキー：Finderでファイルをプレビューする
* control + F2：メニューバーを操作対象にする
* control + Cmd + F：フルスクリーン表示にする
* Cmd + M：ウインドウを最小化してDockにしまう
* Cmd + ,：環境設定を開く
* Cmd + /：ステータスバーを表示

## スクリーンショット
* shift + Cmd + 5：スクリーンショットまたは録画

## パス
* option + Cmd + C：パスをコピー
* option + Cmd + P：パスバーの表示／非表示を切り替える


---
# 参考サイト
[MacのDockやメニューバーをキーボードで操作する方法まとめ | ゴリミー](https://gori.me/mac/mac-tips/70156)

[知らないと損！Macでコピペが劇的に捗る5つのテクニック | ゴリミー](https://gori.me/mac/mac-tips/70021)

[Macのショートカットキー早見表92個｜効かないときの対処法も紹介します | 侍エンジニアブログ](https://www.sejuku.net/blog/124447)

[【完全網羅】Xcodeのショートカットまとめ【2020年版】｜Hiromiick Tech Blog](https://hiromiick.com/xcode-shortcut/)
Apple Silicon M1でMacOSDnsServerAddressStreamProviderがロードできずエラーとなる

# はじめに
KINTOテクノロジーズでは開発端末としてWindows、Macを選択することができ
Macに関してはIntelチップ搭載のMacBook Proが貸与されます。

２０２１年はApple M1 Pro、Maxチップ搭載のMacBook Proが発売されたこともあり
開発端末にApple Silicon M1が増えることに開発者一同熱い眼差しを向けています。

今回は開発端末の選択肢に増えるであろうApple Silicon M1の技術検証時に発生したエラーのお話です。

# 事象
KINTOテクノロジーズのいくつかのシステムではSpring Boot 2.5.0が利用されています。
今回技術検証をしたシステムは、テストコード内で外部サービスのAPIを利用する部分でテスト効率化のために
Spring WebFluxを利用していました。

Spring WebFluxではデフォルトでNettyが利用されますが、Spring Boot 2.5.0ではバージョンを指定しない場合、
io.netty:netty-resolver-dns-native-macos:4.1.63.Final
が依存関係として利用されます。
このバージョンがApple Silicon M1に対応していなかったため
io.netty.resolver.dns.macos.MacOSDnsServerAddressStreamProviderがロードできないエラーが発生しました。

```
ERROR io.netty.resolver.dns.DnsServerAddressStreamProviders - Unable to load io.netty.resolver.dns.macos.MacOSDnsServerAddressStreamProvider, fallback to system defaults. This may result in incorrect DNS resolutions on MacOS.
```

# 対応

１．Spring Bootを最新バージョンに上げましょう。
2021/11/19にSpring　Boot 2.6がリリースされましたが、依存バージョンを確認すると netty-resolver-dns-native-macos は 4.1.70.Finalとなっており、Apple Silicon M1に対応したものがデフォルトで利用されます。

https://spring.io/blog/2021/11/19/spring-boot-2-6-is-now-available

https://spring.pleiades.io/spring-boot/docs/current/reference/html/dependency-versions.html


２．　依存バージョンを指定しましょう。
プロダクション環境で運用されているシステムの場合、バージョンアップは計画的に実施されるケースが多いため
すぐにSpring Bootの最新バージョンに上げるのは難しいと思います。
その場合はnetty-resolver-dns-native-macosの依存バージョンを指定しましょう。

```
dependencies {
    testImplementation 'io.netty:netty-resolver-dns-native-macos:4.1.70.Final:osx-aarch_64'
}
```

# 最後に
ミドルウェアのバージョンアップは計画的に。

# 参考
https://github.com/netty/netty/issues/11020#issue-806940633
AWS IoTに圧縮済みのデータを送信してAWS側で解凍する

PythonからAWS IoTに送るデータを圧縮して、AWS IoT Rule Actions側(+Lambda連携)で解凍する方法を書きます。


# データ送信スクリプト
以下のPythonスクリプトを使ってデータを送信します。




```python
import sys
import json
import bz2
import boto3

# 適当なデータを準備
data = {
    "int": 1,
    "float": 1.1,
    "str": "abcdefghijklmnopqrstuvwxyz",
    "japanese": "あいうえおかきくけこさしすせそたちつてと",
}

# Bytes形式に変換しサイズ確認
json_data = bytes(json.dumps(data),"utf-8")
print(f"original size -> {sys.getsizeof(json_data)} bytes") # -> 230bytes

# bz2で圧縮しサイズ確認
json_data_bz2 = bz2.compress(json_data)
print(f"bz2 compressed size -> {sys.getsizeof(json_data_bz2)} bytes") # -> 184bytes

# AWS IoTに圧縮済みデータをPublish
client = boto3.client("iot-data")
topic_name = "my/topic"
client.publish(topic=topic_name, payload=json_data_bz2)
```
注釈は以下の通りです。

- 上記のテスト用のデータだと圧縮率低いです。IoTを通すような小さいデータだと圧縮かけた方が大きくなる場合もあるので注意してください。
- bz2を使っていますが、zlibやgzipなど他の圧縮形式の方がサイズが小さくなる場合もあるので、サンプルデータ等でサイズを確認してみることをお勧めします


AWS側のMQTTテストクライアントで確認してみると、圧縮済みのバイナリデータが飛んできていることがわかります。このままだと使えないので、こちらを解凍して元のJSONデータを復元します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116068/b8f8cb00-99b9-bde4-c414-9f8486c57255.png)


# 解凍用のLambdaを準備
Lambdaを準備します。こちらもPythonで作成しました。今回の処理はARMアーキテクチャでも動きますので、安価なARMを選択しています。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116068/c57d4089-04dd-c39c-e2ff-e2fe0220d20d.png)

コードは以下の通りです。
先程のAWS IoTに渡ってきたバイナリデータを `event["payload"]` に渡します。この際にAWS IoTからLambdaへはByteをそのまま渡せないので、base64エンコードして渡してくるので、base64でデコードもしています。

```python
import json
import base64
import bz2

def lambda_handler(event, context):
    decompressed_data = json.loads(bz2.decompress(base64.b64decode(event["payload"])).decode("utf-8"))
    return decompressed_data
```


# AWS IoT Rule作成
上で作成したLambdaにデータを渡すためのAWS IoTルールを作成します。

`my/topic` のトピックから取得したバイナリデータを `encode(*,"base64")` でbase64エンコードして、JSON形式でLambdaにインプットします。

返り値は `as payload` として返すようにします。



```sql
SELECT 
aws_lambda("arn:aws:lambda:ap-northeast-1:xxxxxx:function:xxxxxx",{"payload":encode(*,"base64")}) as payload
FROM 'my/topic'
```

アクションに再パブリッシュで `my/topic/decompressed` のトピックに投げるように設定しておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116068/5d8ac82c-c406-68e7-a6d4-a66ac72074ac.png)

# Lambdaのトリガー登録
先程作成したLambdaに、先程作成したAWS IoTルールをトリガーとして設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116068/02537f21-75e4-a546-b9ae-ec27726d4b1b.png)



# 結果確認
上手く設定できていれば解凍されたデータが `my/topic/decompressed` のトピックで受信できることが確認できると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116068/dc5f0a26-97fd-9ac8-3df9-e1d4efdbda05.png)






# 最後に
扱うデータに対して圧縮の効果がどれくらいあるのか、通信量の削減が、Lambda等のAWSコスト増加と比較してコストメリットがあるのかなどなど、確認が必要な項目はありますが、役立つ場面もありそうな気がしています。

# 参考URL

https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/iot-sql-functions.html
[py2rb] __getitem__

# はじめに
移植やってます。
# `__getitem__` (Python)
```python
    def __getitem__(self, key):
        if isinstance(key, (int, float)):
        if isinstance(key, Sequence):
        if isinstance(key, slice):
```
`__getitem__`についての詳しい解説は、こちらの　[Pythonの __getitem__ に与える引数やスライスについて調べてみた - Qiita](https://qiita.com/gyu-don/items/bde192b129a7b1b8c532) にあります。

誰だっ、`Python`が初心者向けって言ったの！
# どうする？ (Ruby)
```ruby
class Getitem
  def [](*args)
    if args.size > 1
      puts args.class
    else
      puts args[0].class
    end
  end
end

g = Getitem.new()
g[1, 2]
g[1..2]
g[1]
g['1']

# Array
# Range  
# Integer
# String
```
むしろこういうのは、`Ruby`の方が得意に思えます。
# メモ
+ Python の `__getitem__` を学習した
+ 道のりは遠そう
AWS SAMのデプロイ時に不要な「Stage」が作成されてしまう問題について


ちょっとハマったので解決策を残しておきます。

cloudformationでテンプレートからAPI gatewayをデプロイした際に、
以下の様に、意図しない「Stage」が作成されてしまうバグがあるようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392337/2638daa0-9ee6-4171-7fcc-6b26f861bfb5.png)

調べたところ、githubのissuesに解決策が記載されていました。
OpenApiVersionにバージョンを指定すれば回避できるそう。

https://github.com/aws/serverless-application-model/issues/191#:~:text=%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3%EF%BC%9A%0A%20%20%20OpenApiVersion%EF%BC%9A3.0.3

##解決策

templateに以下を記載する。

```yaml
Globals:
  Api:
    OpenApiVersion: 3.0.3
```

##参考

https://github.com/aws/serverless-application-model/issues/191
MySQLのINSERT SELECTでロックを回避する方法

## INSERT INTO SELECT FROM構文とは？
任意の条件でSELECTした結果を別のテーブルにINSERTする構文です。

複数レコードを一括で挿入するため、1レコードずつ処理するより高速に動作し
SQLで完結するためアプリケーションサーバのメモリにも優しいです。

各種サマリー作成の他、単純なテーブルのコピーにも便利です。

## INSERT INTO SELECT FROMのロック
高速に動作し、日常的に書くことの多い構文ですが、ロックが設定されるため注意が必要です。
以下、MySQLのデフォルトであるREPEATABLE READのトランザクション分離レベルを利用した場合です。

### INSERT側テーブルはロックなし
公式ドキュメントにauto incrementが指定されている場合、
更新用の特殊な排他ロックが設定される記載がありますが
読み込み、書き込みともにスムーズに流れます。

### SELECT側テーブルは共有ネクストキーロック
共有ロックのため読み込みは流れますが、書き込みは待ち状態になります。
ロック対象はSELECTの探査と共に増加し、INSERTの完了まで解除されないため
書き込み頻度の高いテーブルから大量のデータを移動する用途では
高確率でタイムアウトが発生します。


## ロックを回避するためには？
```
INSERT INTO B SELECT * FROM A;
```
単純なテーブルコピーを行う場合の回避策の検討です。

### 方法1. トランザクション分離レベルの変更
```
# トランザクション分離レベルの変更
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

INSERT INTO B SELECT * FROM A;
```
トランザクション分離レベルを変更してSELECT側のロックを回避します。

ファントムリードなどが発生する可能性がありますが、
修正が容易で対応工数は少なくすみます。

### 方法2. TEMPテーブルにスナップショットを退避
```
# トランザクション分離レベルの変更
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

# 中間テーブルを作成
CREATE TEMPORARY TABLE C AS SELECT * FROM A;

# 中間テーブルからコピー
INSERT INTO B SELECT * FROM C;
```
SELECT側のロックを回避した状態で、
セッション内でしか読み書きされない中間テーブルを作成しています。

中間テーブルのロックを気にする必要がなく、
途中からトランザクションを開始することも可能です。

データの整形やINSERT前の検証が必要な場合に便利な折衷案ですが
データコピーが2回走るため、実行時間は2倍に伸びます。

### 方法3. LOAD DATA IN (LOCAL) FILEの利用
```
# ファイル作成
SELECT * FROM A INTO OUTFILE '/tmp/a.tsv';

# ファイル読み込み
LOAD DATA LOCAL INFILE '/tmp/a.tsv' INTO TABLE B;
```
同じく複数レコードを一括挿入する目的の構文です。
INSERT文より高速に動作し、SELECTのロックはFOR UPDATEなどで任意に指定可能です。

ローカルにファイルが作成されるため、
多重実行時の保存場所やセキュリティ、ディスク容量など考えることが多くなります。

エスケープや区切り文字にも気をつかう必要があり、
必然的に対応工数は肥大化しがちです。

## まとめ
書き込み頻度が少ないマスタデータなどでは
そもそも共有ロックの影響を気にする必要はありません。

LOAD DATA IN FILEは優れた代替案ですが、
精度が求められない、内部向けデータ集計などのオペレーションでは、
トランザクション分離レベルの変更は便利な選択肢です。

一長一短あるので、用途に応じて使い分けができると幸せになれます。

# 採用PR
弊社で一緒に働く仲間を募集しています。
全てのオタクを幸せにしたい方、是非ご覧ください！

https://hrmos.co/pages/vivion/jobs/0000191
CS50のぼかし機能で、画像がぼかされているにも関わらず、check50を通過しない

##概要

[CS50 week4 ps4 Filter (less comfortable)](https://cs50.jp/x/2021/week4/problem-set/filter-less-comfortable/)の課題に取り組んでいるのですが、フィルター加工の1つ、**「ぼかし」**にて、画像がぼかされているにも関わらずcheck50を通過しませんでした。

見た目上だと原因もわからず、私の行ったテストでは網羅性に欠けており原因を突き止めることが出来ませんでした。

途方に暮れそうになり、以下の該当エラーを検索すると同じような問題がstack overflowにありました。

■**参考文献**
[CS50 blur function does not pass check50, even though image is being blurred](https://stackoverflow.com/questions/62209966/cs50-blur-function-does-not-pass-check50-even-though-image-is-being-blurred)

日本語での記事が少なかったため、上記記事を参考文献として、Qiitaに残します。

##実際のエラー文言

```terminal
:( blur correctly filters middle pixel
    expected "127 140 149\n", not "145 160 169\n"
:( blur correctly filters pixel on edge
    expected "80 95 105\n", not "90 106 116\n"
:) blur correctly filters pixel in corner
:( blur correctly filters 3x3 image
    expected "70 85 95\n80 9...", not "70 85 95\n90 1..."
:( blur correctly filters 4x4 image
    expected "70 85 95\n80 9...", not "70 85 95\n90 1..."
```
コーナーのピクセルを正しくフィルタリングするぼかしのみ成功し、その他は失敗しています。

##原因
結論は、**計算元と計算結果の配列を同じもの**にしていたことです。

今回課題のぼかし処理で使用したのは、**隣接するピクセルを参照するボックスブラー**という手法でした。

check50が通らなかった時の実装では、メモリ上にロードされた画像に対して直接ぼかしの処理を加えており、
それだと状況によっては既にぼかしたピクセルをボックスブラーの処理で参照してしまい、期待していた計算と差が出るピクセルがありました。

ぼかしを計算するために参照する画像とぼかしを施された画像の変数を分けることで、ぼかしを施す画像に対して正しいぼかし処理ができ、check50が通りました。

修正としては、最初に画像のコピー(今回はtemp変数)を作成し、ピクセルの値が変更されていないtemp画像内からピクセル値を取得してすべての計算を行いました。

```c
// ぼかしを計算するために参照する画像temp変数を作成し、メモリを確保
RGBTRIPLE(*temp)[width] = malloc(height * width * sizeof(RGBTRIPLE));

// temp変数に対して、元の画像をコピー
memcpy(temp, image, height * width * sizeof(RGBTRIPLE));
```
[npm]npm run prodに失敗する

# はじめに
現在、Web系自社開発企業への転職を目標にポートフォリオを作成中。
Dockerを活用してLEMP環境を構築し、Laravel+VuejsでWebアプリケーションの開発を行っております。

今回は、npm run prodでJavaScriptのトランスパイルを実行するまでの流れを記録として残します。

# 目次
<!-- タイトルとアンカー名を編集 -->
1. [やりたいこと](#Chapter1)
1. [トランスパイル実行したときに発生したエラー](#Chapter2)
1. [調査](#Chapter3)
1. [原因](#Chapter4)
1. [解決策](#Chapter5)
1. [参考文献](#reference)

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# やりたいこと
npm run prodを実行してJavaScriptのトランスパイルを行いたい


```
npm run prod
```

<a id="#Chapter2"></a>
# トランスパイル実行したときに発生したエラー
エラー内容

```
[webapp@ip-10-0-10-10 laravel-vue-app]$ npm run prod

> prod
> npm run production


> production
> cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --config=node_modules/laravel-mix/setup/webpack.config.js

[webpack-cli] Error: Unknown option '--no-progress'
[webpack-cli] Run 'webpack --help' to see available commands and options
```

<a id="#Chapter3"></a>
# 調査
『Unknown option '--no-progress'』でググる

https://namespaceit.com/blog/npm-run-production-error-unknown-option-no-progress

https://stackoverflow.com/questions/65976497/npm-run-production-error-unknown-option-no-progress

<a id="#Chapter4"></a>
# 原因
Laravel Mix 6は、CLIからいくつかのオプションが削除されました。
それに応じてscriptsてpackage.jsonファイルのセクションを更新する必要があります。

<a id="#Chapter5"></a>
# 解決策
package.jsonを編集

Before

```
"scripts": {
        "dev": "npm run development",
        "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --config=node_modules/laravel-mix/setup/webpack.config.js",
        "watch": "npm run development -- --watch",
        "watch-poll": "npm run watch -- --watch-poll",
        "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
        "prod": "npm run production",
        "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --config=node_modules/laravel-mix/setup/webpack.config.js"
},
```


After

```
"scripts": {
				"dev": "npm run development",
		    "development": "mix",
		    "watch": "mix watch",
		    "watch-poll": "mix watch -- --watch-options-poll=1000",
		    "hot": "mix watch --hot",
		    "prod": "npm run production",
		    "production": "mix --production"
}
```

<a id="#reference"></a>
# 参考文献
- [[Solved] npm run production error : "unknown option no-progress"](https://namespaceit.com/blog/npm-run-production-error-unknown-option-no-progress)
- [npm run production error : "unknown option no-progress"](https://stackoverflow.com/questions/65976497/npm-run-production-error-unknown-option-no-progress)
数万通のアラートメールを関係者全員に送りつけてしまった件

# なにがおきたのか

※スマートフォンがまだないガラケー時代の昔話です。

Apache + Tomcat + Java + MySQLで動くWebサービスを新規で開発し、無事リリースすることができました。
本番でも問題なく稼働していて安心して迎えた初めての週末で事件は起きました。

土曜日の早朝から鳴り続ける会社ケータイ・・・。
数百件のメールの受信中画面　→　メールの中身を確認しようとするとまた数百件のメールの受信中画面、が延々と繰り返し続き、メールの中身を確認することもできなかったものの、一瞬見えるタイトルからアラートメールっぽいことを推測。

※そのガラケーの仕様で、メール受信はバックグラウンドではなく、割り込みでフォアグラウンドでメール受信中画面を出すため、メールを送られ続けるとメールボックスが空になるまで何も操作できなかった。また、メールを自動受信しないという設定もなかったため、電波が届く状態で起動すると絶対にメールを取りいくようになっていた。

送られ続けるメールで会社ケータイで通話することもできず、プライベートケータイで関係者に電話したところ、どうもバッチ処理のアラートが大量に送られ続けている模様とのこと。

ちなみに、アラート通知用のMLにはエンジニア全メンバーと偉い人々が入っていました。

# どうしてそうなった

結局開発担当者が土日につかまらず、影響範囲もバッチによる集計処理で実サービスに影響なかったので、月曜日まで放置することになりました（ケータイの電源はもうOFFにしていました）。

月曜日に状況を確認したところ、集計用DBがダウンしていてそこへのアクセスする処理が全てエラーになっていたのですが、そのエラーの通知が**ループ内で行われていました**。

```error.java
while(/*数万件のループ*/) {
  try {
    /* 1件ごとの集計処理 */
  } catch(Exception e) {
    /* アラートメールを送る処理 */
  }
}
```

その結果、毎ループでDBアクセスできないアラートメールが送られることになりました。

結局アラートメールは数万通送られ、月曜日に1日かけて全てのメールを受信しました。

# どうすればよかったのか

- １回でもエラーが起きたらバッチを終了するようにする
    - それが無理なら、全エラーの内容をまとめて１回のアラートメールで送るようにする
- アラートメールの送り先はレベルに応じてわける
【Jbuilder】DBに直接紐付かないモデルクラスのjbuilderの書き方


##今まで
partialでファイル指定

```user_infos/show.json.jbuilder
json.user_info do
  json.partial! 'user_infos/user_info', user_info: @user_info
end
```

```user_infos/_user_info.json.jbuilder
json.extract! user_info, :id, :name
```

##これから
DBに直接紐付かないモデルクラスに```ActiveModel::Model```を```include```する。
>ActiveModel::Modelをincludeすると、以下のような機能を使えるようになります。

>- モデル名の調査
- 変換
- 翻訳
- バリデーション

今回は```ActiveModel::Model```がモデル名の調査をしてくれるのでファイル名を指定しなくてもよくなる。

```models/user_info.rb
class UserInfo
  include ActiveModel::Model
...
end
```

```user_infos/show.json.jbuilder
json.user_info do
  json.partial! @user_info #省略できる
end
```

```user_infos/_user_info.json.jbuilder
json.extract! user_info, :id, :name
```

##参考

https://railsguides.jp/active_model_basics.html#model%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB
1on1っていうのやってみた

# 概要
**[グレンジ Advent Calendar 2021](https://qiita.com/advent-calendar/2021/grenge)** 13日め担当の、mikuri8です。
グレンジではUIの設計、基盤実装などをメインに担当しているエンジニアで、いわゆるアウトゲームと呼ばれている分野のエキスパートとして業務を行っています。

今回は最近良く聞く1on1についての記事になります。
本記事では私が行っている1on1手法を紹介します。
この記事を読むことで「 **1on1って何？** 」「 **1on1ってどんな効果があるの？** 」が少しでも伝われば幸いです！

ヤフーでの導入事例が紹介されている以下の本が参考になります。
[ヤフーの１ｏｎ１―――部下を成長させるコミュニケーションの技法](https://www.amazon.co.jp/dp/B0716B52LP/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)

# 1on1とは
1on1とは一言で表すと**人材育成のためのミーティングメソッド**です。
上司（する側）と部下（される側）が1対1で行う定期的な面談で、対話を繰り返すことで問題解決や気付きによる部下の成長を促進させます。（便宜上、する側される側を上司部下と表記します）

「通常行われているような面談やミーティングと何が違うの？」というところが気になるポイントですが、1on1は「**部下の内省力を上げるためのもの**」という点が大きく違ってくるところになります。

ヤフー本でもしつこいくらいに書かれていますが、1on1は**上司のためのものではなく部下のためのもの**です。
対話の中で出てきた問題点に関して上司が「〇〇して対応しましょう」と答えを与えてしまうと部下が自分の頭で考える筋肉を鍛えることができなくなってしまいます。その結果、指示待ち人間を誕生させてしまいます。
部下側に考えてもらい上司は対話の壁打ち役となることが1on1の基本となります。
 **部下がPDCAサイクルを回すための潤滑油** というイメージが近いでしょう。
[PDCAサイクル（Plan-Do-Check-Act cycle） | 用語解説](https://www.nri.com/jp/knowledge/glossary/lst/alphabet/pdca)

1on1の対話の中でPDCAサイクルの

- Check(評価)
  ：振り返りをして良かったのか悪かったのか判断
- Action(改善)
  ：良かったこと悪かったことに対する改善案を考える
- Plan(計画)
  ：改善案に対しどのように実行するか考える

を考えて行きます。Do(実行)については1on1の外でやってきてもらうことです。
1on1ではこの評価→改善案出し→実行計画の流れを会話の中で行っていくようにするための上司の返答が重要になってきます。「 **どういうふうに解決するのが良いと思う？** 」「 **うんうんそれで？** 」といった聞き出すための返答が必要で、「 **こうしたほうがいいよ** 」「 **それは違うよ** 」は上司の考えをなすりつけてる良くない返答になります。

1on1とは、「 **部下が自分で考える機会を与える対話** 」です。

では次に自分がヤフー本を読んだ上で追加したポイントについて紹介します。

# スコープする
自分がヤフー本を読んだ印象ですが、本で紹介されている1on1はスコープが会社やキャリアなどとても大きく感じました。私は会社の人事部長やマネージャではないので、成長させていきたいポイントはもっと的を絞って「アウトゲーム」という範囲になります。ヤフー本のメソッドとしては **何を話すかというところも部下に委ねます** が、スコープした1on1として設定することで **話す内容を絞る** ことができます。

アウトゲーム1on1、エンジニア1on1、若手1on1とすることで部下がどの点について内省すればいいのかというハードルは下がります。（上司のコストを考えても）短い時間で定期的に繰り返していくには成長させたいカテゴリを加味した上で何についての1on1とするかは決めておいたほうが良いです。

またスコープを絞った1on1として定義されると何に対する効果が出るのかも明白になります。私が行っているアウトゲーム1on1ではアウトゲームの開発フローに関する振り返りをして自身の行動の改善案を出していくことでのチームの開発速度をアップするのが目標です。このように目的を提示できると導入するための理由として妥当なのか判断でき、逆にそんなに目的がないものであれば大抵は状況把握をしたいだけのものになっているので1on1とはしないほうが良いです。

1on1は **上司が状況把握するためのものではなく、部下が成長するためのもの** です。

# KPTを使う
1on1の基本は対話です。おしゃべりです。となると、必然的におしゃべりが得意な人とそうでない人もいるわけで、対話ベースのフォーマットでは効果に差が出てくると感じました。
自分もそうなのですが、喋りながら頭を回転させることが苦手なので予めじっくり考えることができるテキストのほうがありがたいときがあります。
このようなアドリブでその場で色々考えるカロリーをへらすためにKPTのシートを併用することにしました。
[「KPT法」とは？効果的な振り返りをするための実践方法をご紹介](https://hrnote.jp/contents/kpt-20201023/)
KPTとは

- Keep：良かった点
- Problem：問題点
- Try：問題点への対処

としてそれぞれを箇条書きにリストアップしたものを使って何かしよう、というものですが、このフォーマットがおしゃべり最中に考えるというハードルを下げることができるものとして良いなと思い使うようにしました。

1on1が開催される前にスプレッドシートにそれぞれK、P、Tをまとめてもらい対話ではそこに書かれていることをベースに進めます。事前に考えて記入してくるので対話の最中に思い出せない、拾えないなどのリスクは下げることができます。またKPTは1on1の対話で必要になってくるポイントを洗い出して整理する作業になります。話すことを予め考えることができる、話す内容が見えるというのは上司部下双方にとってメリットが大きく、1on1をスムーズに進めるための要因となりました。

# まとめ
1on1の目的は「1on1される側の成長」です。する側の聞き上手力を上げていくことが非常に重要です。そして難しい。
1on1を自分でやるようになってみて、人間それぞれ固有である以上正解手法はなく、どれだけ目的の状態に近づけることができるのかを模索するしかないということを感じました。
この記事がいちケースとして参考になればと思います。最後までお読みいただきありがとうございました！
【SwiftUI】AlamofireをMoyaっぽく使う

Swift4時代からMoyaを使っていて、バージョンアップで昔と書き方が変わっているのは知っていましたがSwiftUIで久しぶりにAlamofireを使ってみました。

ベターな使い方か分かりませんが、使いながらMoyaっぽく書きたいなーと思ったのでそれっぽく書いてみました。

自分でWrapperを作ろうとしたり色々調べてみましたが、結局gitに書いてあるやり方で出来そうな感じでした。

やり方はドキュメントにある`URLRequestConvertible`を使用します。

```
enum Router: URLRequestConvertible {
    case get, post
    
    var baseURL: URL {
        return URL(string: "https://httpbin.org")!
    }
    
    var method: HTTPMethod {
        switch self {
        case .get: return .get
        case .post: return .post
        }
    }
    
    var path: String {
        switch self {
        case .get: return "get"
        case .post: return "post"
        }
    }
    
    func asURLRequest() throws -> URLRequest {
        let url = baseURL.appendingPathComponent(path)
        var request = URLRequest(url: url)
        request.method = method
        
        return request
    }
}

AF.request(Router.get)
```
https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md



公式のAdvancedUsageのドキュメントではこのようにgetやpostで分岐させていますが、単純にこれを任意のエンドポイントごとに定義することでMoyaでやっていたようなやり方で運用できます。

```
enum Router: URLRequestConvertible {
    case hoge 
　　　　　　　　case fuga
  
    var method: HTTPMethod {
        switch self {
        case .hoge: return .get
        case .fuga: return .post
        }
    }

~以下省略~
```
AVX/AVX2によるnot演算の作成とsetzero

#はじめに
ここでは，AVXにはないnot演算の作成方法と，全てのレジスタを0にするsetzeroは論理演算でできていることについて説明します．

両者は，全てのビットを1にする（すべてをFにする），全てのビットを0にする命令です．

## not演算の作成
notは，全てのビットが1のマスクとのxorで実現できます．
全てが1のマスクは，-1をセットする（0xFF...をセットする）ことで作成できますがセット命令はメモリからのロードが必要となります．
一方で，比較命令の結果を使うことで，メモリを介することなく直接レジスタに全て1のマスクを生成できます．
比較結果がtrueの時，全てのビットが1となるため，適当な値（この場合は引数で入れた値）を自分と自分の比較にすることですべてがFになるマスクが作成可能です．

```cpp
inline __m256i _mm256_not_si256(__m256i src)
{
	return _mm256_xor_si256(src, _mm256_cmpeq_epi8(src, src));
}
```

もちろんこのマスクは使いまわすことができるため，大きなループで，何度もnot命令を出す場合は，マスク生成の時間を除くことができます
つまり，xor演算1回でnotを行うことができます．
この場合は，ループ外の演算のコストは無視できるほど小さいため，cmpでマスクを作ろうと，set(-1)でマスクを作ろうと計算時間に影響はありません．

```cpp
const __m256i zero = _mm256_setzero_si256();
const __m256i ffmask = _mm256_cmpeq_epi8(zero, zero);
//const __m256i ffmask = _mm256_set1_epi8(-1);
__m256i s[size];
__m256i d[size];
for(int i=0;i<size;i++)
{
	d[i]=_mm256_xor_si256(s[i],ffmask);
}
```

float/doubleのビット反転も同様に作成可能ですが，not演算のように全てのビットの反転処理が浮動小数点型で必要になることはあまり考えられません．
最上位の符号部や指数部，仮数部を各々でビット演算を扱うことが想定されます．
その場合は，andnot演算やxor演算で必要な処理を表現できます．

## _mm256_setzero_ps|pd_si256
```cpp
__m256i _mm256_setzero_si256 (void)
__m256 _mm256_setzero_ps (void)
__m256d _mm256_setzero_pd (void)
asm: vpxor ymm, ymm, ymm //si256
asm: vxorps ymm, ymm, ymm //ps
asm: vxorpd ymm, ymm, ymm //pd
```

| Architecture | Latency | Throughput |Uops|
|--------------|:-------:|:----------:|:--:|
| Alderlake    |   0.2   |    0.02    |  - |
| Icelake      |   0.2   |    0.23    |  1 |
| Skylake      |   0.2   |    0.25    |  1 |
| Broadwell    |   0.3   |    0.25    |  1 |
| Haswell      |   0.3   |    0.25    |  1 |
| Ivy Bridge   |   0.3   |    0.25    |  1 |
| Sandy Bridge |   0.3   |    0.25    |  1 |
| Zen3         |   0.2   |    0.02    |  1 |
| Zen2         |   0.2   |    0.25    |  1 |
| Zen          |   0.5   |    0.5     |  2 |

* AlderlakeやZen3はスループットが非常に速くなっています．

**説明**  
レジスタを0で初期化します．
どれかのレジスタの引数を同じにしてxor演算をすれば0の値が作れます．
即値の0をセットするわけではないため，メモリからのロードコストはかかりません．
0にする方法は他にもvsub same same等でも実現できますがほとんどのアーキテクチャでxorによる初期化が最速です．

また，`xor same same`は論理演算よりも速く動作します．
参考までに論理演算の性能を示します．
**論理演算（浮動小数点）**

| Architecture | Latency | Throughput |Uops|
|--------------|:-------:|:----------:|:--:|
| Alderlake    |    1    |    0.33    |  - |
| Icelake      |    1    |    0.33    |  1 |
| Skylake      |    1    |    0.33    |  1 |
| Broadwell    |    1    |     1      |  1 |
| Haswell      |    1    |     1      |  1 |
| Ivy Bridge   |    1    |     1      |  1 |
| Sandy Bridge |    1    |     1      |  1 |
| Zen3         |    1    |    0.25    |  1 |
| Zen2         |    1    |    0.25    |  1 |
| Zen          |    1    |    0.5     |  2 |

**論理演算（整数）**

| Architecture | Latency | Throughput |Uops|
|--------------|:-------:|:----------:|:--:|
| Alderlake    |    1    |    0.33    |  - |
| Icelake      |    1    |    0.33    |  1 |
| Skylake      |    1    |    0.33    |  1 |
| Broadwell    |    1    |    0.33    |  1 |
| Haswell      |    1    |    0.33    |  1 |
| Zen3         |    1    |    0.25    |  1 |
| Zen2         |    1    |    0.25    |  1 |
| Zen          |    1    |    0.5     |  2 |
分からないをすぐ伝えるのは、とても良いという話


この記事は、[株式会社カオナビ Advent Calendar 2021](https://qiita.com/advent-calendar/2021/kaonavi)の２０日目です。

https://qiita.com/advent-calendar/2021/kaonavi

----

例えば、IT企業のとあるエンジニアの会議で、行われるこんな会話。

**「今度のアプリだけど、`IDaaS`にはAuth0を使おう、インフラは`EKS`ね。初期は`Fargate`でも良いかなって思ったんだけど、結局マイクロサービスにしていきたいから最初から`K8S`でいいよね？」**

分かっていれば効率的なコミュニケーションになるのかもしれませんが、会議に参加している人の中には、こんな風に思う人もいるでしょう。

**「IDaaSってなに？K8S？Fargate？呪文？」**

![hanashiai_wakaranai_man.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4514/b87fb197-c1e6-f3ac-9466-1f3df0f4a8d1.png)


こんな時、本当はわからないけど、さも分かっていますという微妙な微笑みを浮かべたり、「良いと思います。無難ですね。」みたいにしてその場をやり過ごしたことはありませんか？

それは、せっかくのラッキーチャンスを見逃しています。

私がオススメする回答は、**「すいません、`XXXX`が分からないです。教えてもらっても良いですか？」**です。

会話の流れをせきとめて、自分の無知をさらけ出すのは勇気のいる行動です。しかし、自分も成長し、かつチームメンバー全員に利益をもたらす行動です。


## 後で調べるのは駄目なのか？

分からない時は、会議終了後に高速で調べて学習すればいい。そんな風に思ったかもしれません。しかし、それは自分個人のみを考えた場合の話です。仕事はチームで進めます、そのためチームにとって最大限の効果を発揮するにはどうしたらよいか？そんな風に考える必要があります。

## 他にも分かってない人がいる

チームを目線にいれて考えると、新しい視点が見えてきます。それは**「あなた以外にも、分かってない人がいる可能性がある」**ということです。IT系企業などは、特に高度に知的な共同作業を行う場です、会議に出ている人はみんな頭がよく見えますし、実際に頭が良い人が多いかもしれません。しかし、全ての人が、すべてのことに精通するのは不可能です。きっと、あなた以外にも分かってない人がいます。

会議が進行していく最中に「分からない」を伝えることで、そのような**分からない仲間**を助けることにもなります。

![wakaranai.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4514/b7561f55-f804-be63-7085-00262143959a.png)


## 分かっていると思っている人も、分かっていない場合がある

無知の科学という書籍に「説明深度の錯覚」という概念が出てきます。これは、本人は分かっているつもりだけど、説明することが出来ないような状態を表します。今回の例でいうと「IDaaS」という言葉を「SaaS」で同じ程度の認識しか持っていない可能性もありますし、認証という言葉が持つ重要な意味合いを話し手が理解できていない可能性もあります。

## 自分の脳が分かっていると錯覚してしまう

もう一つ、押さえておきたい考え方として、**"自分の脳が分かっていると錯覚してしまうのを防ぐ"**です。人間というのは不思議な生物なので、自分の周りに知識を持った人がいると、自分も同じように知識を持っていると錯覚してしまうそうです。会議の場で、なんとなく分かった雰囲気を出してしまうと、自分もなんとなく理解した気になってしまいます。すると、会議に参加しているメンバーは、分かった雰囲気を出す人ばかりになってしまいます。

# 分からないを伝えるとどうなるか？

実際に、分からないを伝えると以下のような行動が生まれます。

1. その場にいる詳しい人から、分かりやすい解説をしてもらえる。解説者も理解を深めることが出来ます。
1. その場で解決できない場合、理解を行うためのタスク、時間を仕事時間内に取る理解が得られやすくなります。
1. チーム内にいた実は分かっていなかった人も、知らぬ間に助けられて分かっている人になります

ちょっと勇気を出すだけで、チーム全体の知識向上になってしまいました。グループの無知が最も効率的に処理されますし、自分の無知も解決されます。

中には心理的安全性が低いチームがあり、無知を表明することがとても怖く思える場合もあるかも知れません。しかし、そういった状況は逆転の発送で捉えましょう。**"自分が無知をさらけ出すことで、このチームの心理的安全性を高めてやろう！"**という意識が大切です。

# まとめ

小学校時代など、「わからないことは恥ずかしい」という全体的な雰囲気の中で育ってきました。「わからない」とみんなの前で言い出すのが少し怖いと感じてしまうほどです。私は幸運にも、留学時代の恩師に言われた次の言葉で、この恐怖を払拭することが出来ました。

> 少しでもわからないことがあったら、すぐに授業を止めて質問してください。あなたが分からないなら、きっと他の誰かも分からないから

日本で育った自分は、雷で打たれたような衝撃をその時に受けました。その時は、この先生はなんて素敵なことを言うんだと感じました。しかし、最近になって、これは無知を放置しないという単純な戒めではなくて、グループ全体として成長するための、もっとも効率が良い手段なのだなと感じるようになりました。

もう40歳を超えまして、人にとやかく言わても、それほどショックを受けない年頃になりましたので、これからも積極的に**「え？何言ってるの？全然分かんない？」**と伝えて行こうと思います。
黙読ベンチマーク



[黙読とは - コトバンク](https://kotobank.jp/word/%E9%BB%99%E8%AA%AD-645376)

> 〘名〙 声に出さないで、目だけで読むこと。目読。

いや、そんなの知ってるよ！！という方、実は黙読にも種類があるというのはご存知でしょうか？

1. 発声しないだけで、頭の中で音を再現している　**「黙読」**
1. 頭の中でも音を再現しない黙読 => **「視読」**

この「視読」 は、本を早く読む方法として、よく紹介されているのですが、難しいのです。今までの人生で、本を黙読する時は音読と同じように脳内で音を出して読んできたため、脳内の声を黙らせることができないのです。

しかし2021年、私の読書方法探求の末に「視読」を行う２つの方法を見つけることが出来ました。

### ① 脳の声を追い越す方法

目を高速で動かして、脳内で再生する音がついてこれない速度を出す方法です。「このスピードにはついてこれまい」という速さで文章を読むことで「視読」を達成します。この方法は自分で編み出しました。



### ② 脳内で意味のない声を出し続ける方法

独学大全という書籍の十二章で紹介されていた方法です。「レロレロ」とか、「アエイオウ」といった意味を持たない単語を脳内発声しつつ読むことで、「視読」を行います。


# 黙読ベンチマークとは？

今回の本題です。エンジニアには有名な格言があります。それは

> 推測するな！計測せよ！

「視読」に注目した元々の動機は **"本を速く読みたい"** でした。であれば、実際にどの黙読方法が最も速く・効果的に読書できるのかを計測するべきです。計測して結果を考察すれば、どの黙読方法を選択すれば良いのか、数値で具体的に判断することが出来ます。

計測対象は、井上靖の「しろばんば」第一章を読み切るまでの時間です。
※各方法においては、速度の限界を目指して頑張るものとします。

## 計測結果

| 黙読方法 | 速度 | 理解度 |
|:-|:-|:-|
| 脳内で音読する方法  | １３分３４秒  | 深い。情景が頭に浮かび、登場人物が映像で浮かび上がる。おぬい婆さんが作る味噌汁の匂いがした気持ちがあった。読んでいて気持ちが良い。 |
| 脳の声を追い越す方法  | ３分５４秒  | 浅い、単語がところどころ消える。非連続的な写真を眺めていくような気持ち。脳が忙しい。ただ、意外なほどに頭には情報が入ってくる。  |
| 脳内で意味の無い声を出す方法  | ４分３０秒  | 理解度は中くらい、今回は「アエイオウ」と唱えながら読んだが、実感としてかなり文書が読めている感じがした。  |

# 考察
今回、ベンチマーク対象の書籍に「しろばんば」を選択したのは、小説であれば文章構造から要約することが難しいため、文字を読むという行為の純粋なスピードを測れるのではと思ったためです。また「しろばんば」は、私の好きな小説で、何度も読んでいます。繰り返しのテストでも、事前理解度の違いによる差異が生じにくいと考えました。

個人の感想ではありますが、 **「脳内で意味の無い声を出す方法」** が理解度のバランスも良く、またスピードもある程度出せるので良いなという感じがしました。ただし、脳内で「アエイオウ」を言い続けるのは結構しんどいかったです。

新たな発見としては、 **「脳内で音読する方法」** を忠実に実行するのは大変だということです。普段の私は、知らず知らずのうちに読み飛ばしをしていたようです。しっかりと脳内音読を行うと、読む速度は遅くなりますが、小説が映像で再生されていくようで、読書体験としては一番素晴らしかったです。

# 最後に

結局、今回分かったことは、**読書速度を下げると理解度が上がる**という、直感的に分かるような当たり前の結果ではありました。この結果を踏まえた上で、本の種類や時間的余裕に合わせて読書法を選択すると、効率的で豊かな読書ライフを送れるのではないでしょうか。