OmniAICreator/Qiita-1.07M huggingface dataset:
AWS IAMの概要メモ

# この記事について
この記事は、AWSの重要サービスの1つであり、認定試験の勉強で理解に苦労した分野でもある`IAM`について、自分なりに整理した内容をまとめたメモです。

# AWS IAMとは
IAMとは、`Identity and Access Management`の略称であり、「アイアム」と読みます。
公式の[ユーザーガイド](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/introduction.html)では、以下のように説明されています。

> AWS Identity and Access Management (IAM) は、AWS リソースへのアクセスを安全に管理するためのウェブサービスです。IAM により、誰を認証 (サインイン) し、誰にリソースの使用を承認する (アクセス権限を持たせる) かを制御します。

これだけでもIAMがどのようなサービスなのか、何となく理解はできますが、もう少し具体例を挙げてみたいと思います。

## 認証と認可
### 認証
認証とは、本人しか知り得ない情報や本人特有の情報を用いて、相手が誰なのかを判別することを言います。
例えば、ID・パスワードの組み合わせや、生体認証（指紋や虹彩など）がこれに該当します。
AWSでは、**IAMユーザー**によって認証が実現されます。

### 認可
認可とは、対象の権限を制御する、つまりやっても良い事とダメな事を決めることを言います。
オフィスに例えれば、ある社員Aさんは執務スペースへの入室は認めるが、セキュリティルームへの入室は認めない、といったことが認可にあたります。
AWSでは、**IAMポリシー**によって認可が実現されます。
認証したユーザーに関連付けられたIAMポリシーで、各サービスの利用可否を制御しています。

# IAMの中心となる機能
## IAMユーザー
**IAMユーザー**によって、AWSは利用者(ユーザー)の判別を行います。
IAMユーザーを利用するのは、マネジメントコンソールを使用する人間だけではなく、AWSのAPIを実行するプログラムも含まれます。
誰が使っていたのかを判別できるよう、利用者ごとにIAMユーザーを作成することが推奨されます。

ユーザーがマネジメントコンソールを使うときは12桁のアカウントID・ユーザー名・パスワード、
プログラムからAWSのサービスを利用するときはアクセスキーID・シークレットアクセスキーを使うことが一般的です。

## IAMグループ
同じ権限や役割を持ったIAMユーザーの集まりを**IAMグループ**といいます。
IAMグループには権限を付与することができるため、「開発担当」や「運用担当」といったグループを作成しておくと、IAMユーザーが所属するグループを変更するだけで、適切な権限管理が可能になります。
（ユーザー個別に権限を付与すると、権限の付け忘れや付けすぎなどのミスを招きやすくなります）

以下のイメージのように、1ユーザーを複数のグループに所属させることも可能です。
![IAMgroup.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653162/7ae40f87-d1a0-453e-dc99-2069b3051182.png)

## IAMポリシー
アクセス権限を設定するドキュメントのことを**IAMポリシー**といいます。JSONフォーマットで記述します。
IAMポリシーは、ターゲットに対して関連付けをする（アタッチする）ことで、初めて効力を発揮します。つまり、**どこにも関連付けされていないポリシーを作っただけでは、何の効力も持たない**ということになります。

よく利用されるIAMポリシーは、以下のように分類されます。
* **アイデンティティベース**：ユーザーやグループ、ロール（＝アイデンティティ）に設定するポリシー
  * インラインポリシー：各ターゲットに個別で直接指定するポリシー。同じ設定を複数の対象に適用するには向かないため、管理ポリシーの使用が推奨される
  * 管理ポリシー
    * AWS管理ポリシー：AWSが管理しているポリシー。汎用的なパターンが予め用意されており、ポリシーのバージョンアップも適宜行われる
    * カスタマー管理ポリシー：利用者が独自に作成するポリシー。利用者が責任を持って適切な管理を行う必要がある
* **リソースベース**：S3バケットなど、AWSリソースに対して設定するポリシー。リソースが主体なので、誰に対して許可（拒否）するのか、明示的な指定が必要
  * インラインポリシー：AWSリソースに対しては、インラインポリシーのみ適用可能

### ポリシーは拒否が優先
一方で許可、他方で拒否という相反するポリシーが設定されている場合は、順序やポリシーの種別に関係なく拒否が優先されます。
とあるサービス全般の許可をAWS管理ポリシーでしておき、カスタマー管理ポリシーでシステムにあわせた特定の操作のみ拒否するという手法をとることができます。
明示的な許可も拒否も設定されていない操作は拒否されるため、許可対象の操作が多い場合に有効です。

## IAMロール
AWSのサービスなどに対して、一時的にAWSへのアクセス権限を付与するために使用する機能です。
シークレットキーなどの認証情報をプログラムに記述する必要がなくなるため、セキュリティを向上させることができます。

### IAMロール 信頼ポリシー
IAMロールに設定するリソースベースのポリシーです。
なんでもアクセス権限を取得できてしまっては困るため、このポリシーで一時的なアクセス権限の取得を認める対象を設定します。
許可する対象のことを「プリンシパル」といいます。

* EC2インスタンスを対象とした信頼ポリシーの設定例
```json
{
  "Version": "2012-10-17",
  "Statement": [
      {
          "Effect": "Allow",
          "Principal": { "Service": "ec2.amazonaws.com" },
          "Action": "sts:AssumeRole",
      }
  ]
}
```
なお、EC2インスタンスとIAMロールを関連付ける場合は、**インスタンスプロファイル**を経由しなければなりません。
マネジメントコンソールでEC2インスタンスとIAMロールを関連付けると、自動的にインスタンスプロファイルが作成されるため、あまり意識することはありませんが、CloudFormationなどで構築する場合は指定が必要になります。
【機械学習】sklearnによるGrid Searchの実践

# はじめに
Grid Searchについてまとめました。

# Grid Search
Grid Searchは複数ハイパーパラメータの各組み合わせでモデルを学習、検証する手法です。
複雑なモデルになるほど複数のハイパーパラメータが必要になり、モデル精度を向上させるためにこのような手法が使われます。
また、Cross Validationと組み合わせて使われます。

sklearnではGridSearchCVという関数が用意されています。
GridSearchCVを使うことで、指定したパラメータの全組合せの中からCross Validationで最適なパラメータを求めることができます。

GridSearchCVの主なプロパティとしては以下のものがあります。
- estimator: チューニングを行うモデル
- param_grid: パラメータ候補`パラメータ名: [候補リスト]`
- scoring: 評価指標
- cv: Cross Validationの分割数(default: 3)
- verbose: ログ出力レベル
- n_jobs: 同時実行数(-1: コア数で並列実行)
- refit: 　trueのとき最良のパラメータで再学習

## 実践
Elastic Net回帰モデル(よろしければ以下の記事をご覧ください)にGridSearchCVを適用してみます。

https://qiita.com/suzuki0430/items/e3958f027af1dd011f21#elastic-net%E5%9B%9E%E5%B8%B0

以下の場合、`alpha`の候補が6個、`l1_ratio`の候補が7個あるため、42個の組み合わせから最適なパラメータを選ぶことになります。
また、Cross Validationで5分割するため、210(42☓5)回計算を行います。

```py
from sklearn.linear_model import ElasticNet
from sklearn.model_selection import GridSearchCV

# モデルの定義
base_elastic_model = ElasticNet()

# パラメータ候補の定義
param_grid = {'alpha':[0.1,1,5,10,50,100],
              'l1_ratio':[.1, .5, .7, .9, .95, .99, 1]}

# パラメータチューニング
grid_model = GridSearchCV(estimator=base_elastic_model,
                          param_grid=param_grid,
                          scoring='neg_mean_squared_error',
                          cv=5,
                          verbose=2)

grid_model.fit(X_train,y_train)
```
`best_perams_`メソッドで、`{'alpha': 0.1, 'l1_ratio': 1}`が最適なパラメータとして選択されたことを確認できます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569054/dba97d24-8599-44b6-9f66-c1c93d194b3c.png" width="800">

そして、テストデータの予測を以下のように行います。

```py
y_pred = grid_model.predict(X_test)
mean_squared_error(y_test,y_pred)
```

# 参考資料
https://www.udemy.com/share/103I003@8kT245GD3ilumJGEsp2Lh6dSryavrYqeIqIr9Vn0yelx0uh9Ddfq1YRD9g8gFZPL/

https://starpentagon.net/analytics/scikit_learn_grid_search_cv/
S3 CLI コマンドメモ

# 背景

業務で S3 のコマンド (ローカルは MinIO) を扱うようになったので、便利そうなコマンドをメモしておく。

# コマンド一覧

- `$ aws configure --profile minio`
    - プロファイルを設定する
- `$ aws configure list --profile minio`
    - プロファイルの中身を確認する
- `$ aws --profile minio --endpoint-url http://127.0.0.1:19000/ s3 ls`
    - バケット一覧を出力する
- `$ aws --profile minio --endpoint-url http://127.0.0.1:19000/ s3 ls s3://<bucket-name>`
    - バケット内のディレクトリ一覧を出力する
- `$ aws --profile minio --endpoint-url http://127.0.0.1:19000/ s3 sync source s3://<bucket-name>/<directory-name>`
    - `source` ディレクトリ内のファイルをまとめて `<bucket-name>` バケットに転送する。

# 参考記事

https://qiita.com/reflet/items/3e0f07bc9d64314515c1
俺「外部キー制約ってなんやねん」

# 整合性を保つよ！

2つのテーブルの整合性を保つために用いられる工夫の一種だよ！

具体的に見ていこう👍

# `user_id`カラムでユーザー情報を格納する

例えばあるWebアプリに次のテーブルがあるとする。

- usersテーブル
    - ユーザーを管理する
- postsテーブル
    - ユーザーの投稿を管理する

注目すべきは、postsテーブルには「誰が投稿したか」が分かるように`user_id`っていうカラムがあるところだ。

名前から推測できるように、この`user_id`にはユーザーの`id`番号が入る。

中々良いアイデアだ。

誰が投稿したかを分かるように、postsテーブルに別のテーブル（今回で言うとusersテーブル）の情報を格納する。

ある投稿の`user_id`カラムが10だったときは、`id`が10のユーザーが投稿したんだな、とこれで分かる。

# 存在しないユーザーの`id`

この設計には1つ問題が潜んでいる。

というか、余計なことができちゃう隙がある。

例えばそのアプリはユーザーが10人しかおらず`id`が1-10までしかないのに、`user_id`に例えば20が格納されてしまう可能性がある。

要は実在しない`id`番号ががpostsテーブルの`user_id`に入る可能性がある（悪意のあるユーザーによって攻撃することができる）。

これを防ぐ仕組みが「外部キー制約」である。

# 外部キー制約で制限できるよ！

postsテーブルの`user_id`に**外部キー制約**をかけて連携対象をusersテーブルにする

すると、postsテーブルの`user_id`にはusersテーブルに存在する`id`番号しか格納されないようになる。

外部のキーで制約するから、外部キー制約だよ！
バッチファイルで今日の作業用のファイル・フォルダを作成する（日付文字列付きコピー）

Y子です。
今回は、「過去に作成したファイルをコピーして、今日の作業用のファイルを作る。ファイル名には今日の日付を付ける」というバッチを作成します。
下記の記事の派生版、といった感じです。
・[バッチファイルでファイル・フォルダをバックアップする（日付文字列付きコピー）](https://qiita.com/koiwaiwaiko/items/468fba0ff82db7019f4c)

_【[確認環境：Windows 10 Home (Bld. 19044.1766)](https://qiita.com/koiwaiwaiko/items/ef2d457ae1e1a7c8b698 "Windows10のバージョンを確認・表記する")】_

# 仕様
* ファイルやフォルダをコピーする。
* コピー先は、コピー元と同じフォルダとする。
* コピー先ファイル名・フォルダ名は、 __今日の日付__ を拡張子前に付けて、「`filename_yyyymmdd.docx`」「`dirname_yyyymmdd`」等とする。
* コピー元ファイル・フォルダ名の末尾に日付文字列がある場合、今日の日付に置き換える。
* コピー元ファイル・フォルダが存在しない場合、コピーしない。
* コピー先ファイル名・フォルダ名が既に存在している場合、コピーしない。
* 引数が1つでない場合、コピーしない。

# 使い方
* バッチファイルに、ファイル名やフォルダ名を引数で与えることで動作する。
* バッチファイルに、ファイルやフォルダをマウスでドロップしてもよい。
* バッチファイルのショートカットを「`sendto`」に置き、右クリック「送る」から選択してもよい。

# コード
```bat:copy_with_curdatestr.bat
@echo off
setlocal

rem 引数がない場合は、最後に飛んで終了する
if "%~1"=="" (
  echo 【エラー】引数がありません
  goto :label_end
)

rem 引数が複数ある場合は、最後に飛んで終了する
if not "%~2"=="" (
  echo 【エラー】引数が2つ以上あります
  goto :label_end
)

rem 対象ファイル・フォルダ…例：「C:\work dir\test.txt」「C:\work dir\dir」
set str_file=%~1

rem コピー元のファイルまたはフォルダが存在しない場合は、最後に飛んで終了する
if not exist "%str_file%" (
  echo 【エラー】ファイルが存在しません："%str_file%"
  goto :label_end
)

rem 上位フォルダのフルパス…例：「C:\work dir\」
set str_dir=%~dp1

rem ファイル名分割…拡張子なし「test」と拡張子のみ「.txt」
set str_fn=%~n1
set str_ex=%~x1

rem 今日の日付文字列を作成……例：「20220630」
set str_date=%date:~0,4%%date:~5,2%%date:~8%

rem 旧ファイル名の末尾が「_日付」に一致するか判定
echo %str_fn:~-9% | findstr /r "\<_[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]\>" > nul 2>&1
if "%errorlevel%"=="1" (
  rem 一致しない=日付がなかった場合…末尾に日付を結合する
  set str_new_fn=%str_fn%_%str_date%%str_ex%
) else (
  rem 一致する=日付があった場合…末尾を削って日付を結合する
  set str_new_fn=%str_fn:~0,-9%_%str_date%%str_ex%
)

rem 新しいファイル名(フルパス)
set str_newfile=%str_dir%%str_new_fn%
echo 新ファイル名：%str_newfile%

rem リネーム不可の(新ファイル名が既存ファイルと重複する)場合、最後に飛んで終了する
if exist "%str_newfile%\" (
  echo 【エラー】同じ名前のフォルダが存在します："%str_new_fn%"
  goto :label_end
) else if exist "%str_newfile%" (
  echo 【エラー】同じ名前のファイルが存在します："%str_new_fn%"
  goto :label_end
)

rem コピーする：フォルダの場合
if exist "%str_file%\" (
  echo d | xcopy /s /e /h /k /q "%str_file%" "%str_dir%%str_new_fn%" > nul 2>&1
rem コピーする：ファイルの場合
) else (
  echo f | xcopy /r /q "%str_file%" "%str_dir%%str_new_fn%" > nul 2>&1
)

rem コピー成否を確認
if exist "%str_file%" (
  echo コピーしました：%str_new_fn%
) else (
  echo 【エラー】コピーできませんでした：%str_new_fn%
)

:label_end
echo 処理を終了しました
endlocal
pause
```

# 説明
ファイル名の、拡張子を除いた末尾に、アンダースコア＋日付（数字8文字）を付加します。
コピー元ファイル名の、拡張子を除いた末尾9文字が、アンダースコア＋数字8文字だったら、末尾9文字を削除してから付加します。

# 使い方・実行結果
まず、`C:\work dir\test01.txt`というファイルを、バッチファイルにドロップしてみます。

```:実行結果
新ファイル名：C:\work dir\test01_20220630.txt
コピーしました：test01_20220630.txt
処理を終了しました
続行するには何かキーを押してください . . .
```

同じファイルを再度ドロップすると、こうなります。
```:実行結果
新ファイル名：C:\work dir\test01_20220630.txt
【エラー】同じ名前のファイルが存在します："test01_20220630.txt"
処理を終了しました
続行するには何かキーを押してください . . .
```

`C:\work dir\test02_20220620.txt`というファイルだと、こうなります。
```:実行結果
新ファイル名：C:\work dir\test02_20220630.txt
コピーしました：test02_20220630.txt
処理を終了しました
続行するには何かキーを押してください . . .
```

# おわりに
いにしえのファイル管理、という気もしますが、手軽で確実でもあるので、同じような運用を続けてる方は多いのではないでしょうか。
わたしの職場だけだったりして…。

では！
【GA4/UA対応】CookieからクライアントIDを取得するJavascriptサンプル（gtag）

Googleアナリティクス4、ユニバーサルアナリティクスにおけるWebのユーザーを識別するIDのひとつである、【クライアントID】（client_id）を取得するシンプルなjavascriptのサンプルです。

カスタムディメンションやイベントに仕込みたいという要望があるかもしれませんので、備忘録的に残します。GAが1st Party Cookieを活用し、「_ga」というcookie名を使い続ける限りは利用できるとは思います。

GAのグローバル サイトタグ API からも取得出来ますが、2022年6月時点では、GA4 X GTMを利用していた場合には、タグテンプレートを利用しないと使いづらい事象などもあり、1stParty Cookieから直接利用するケースもあるかもしれないという理由もあり、用意しています。

## コード解説
・単純にCookieから「_ga」を特定
・値だけ取り出して、任意の変数「gaclid」に格納
・デフォルトではGA1.xxxという表記なので、頭6桁を削除
・テストでは、クライアントIDをアラート（alert）で表示しています。


## コード

```
<script>

function getclid(){

gaclid = "";
newgaclid = "";
ckall = document.cookie;
ckmatch = new Array();
ckh = new Array();

//if
if(ckall != ''){
	
	ckh = ckall.split(';');
	for(i = 0;i < ckh.length;i++){
		ckmatch[i] = ckh[i].split('=');
		if(ckmatch[i][0].trim() === '_ga'){
		gaclid = ckmatch[i][1];
	};
	
	};
//endif

//取得したclientidを整形
//デフォルトではga1.xxといった文字列がつく
newgaclid = gaclid.slice(6);
alert(newgaclid);
//

};

}

</script>
```

## 注意事項
・cookie名を「_ga」以外にしている場合は、変更をお願いします。
・cookieの扱いはもっといい方法あると思いますので、あくまで一例です。

・当然ながら、GAタグが先に起動していないと、初回訪問の場合は取得できません。
　必要な場合は、コードの発火順番を工夫してください。

・Googleさんの仕様が変わった場合には修正が必要です。

## 公式への要望
・GTM環境でもAPIが以前のように扱いやすくなることを祈ります！
Twitter、はてなのシェアボタンの作成

Twitterとはてなブックマークのシェアボタン（共有）の表示方法についてです。

### Twitterシェアボタン

[Twitter Publish(公式ページ)](https://publish.twitter.com/?buttonType=TweetButton&widget=Button)の下の方にあるCode Copyというボタンを押すと、下のHTMLコードがコピーされるので、このコードを貼ればTwitterシェアボタンを表示できます。

```
<a href="https://twitter.com/share?ref_src=twsrc%5Etfw" class="twitter-share-button" data-show-count="false">Tweet</a><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
```

Twitterシェアボタンを押すと、タイトルとリンク先URLのツイート画面が表示されます。
タイトルはtitleタグの中の文言で、リンク先URLはシェアボタンがあるページのURLです。
（ちなみに自分のローカル環境の場合、リンク先URLは表示されるけどリンクはされてなかった。パブリックのインターネットからだと存在しないURLだからね。）

また、aタグを少し変更すれば、ツイートするタイトルとリンク先URLも指定できます。
タイトルはdata-text属性、リンク先URLはdata-url属性で指定します。

```
<a href="https://twitter.com/share?ref_src=twsrc%5Etfw" class="twitter-share-button" data-text="テストタイトル！" data-url="http://www.testhogemoge.net" data-show-count="false">Tweet</a><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
```

この辺のちょっとしたカスタマイズは、下のサイトが参考になると思います。
・[Twitterシェアボタンの設置方法とカスタマイズ](https://www.howtonote.jp/twitter/button/index4.html)

### はてなブックマークボタン共有ボタン

[はてなブックマークボタン（公式ページ）](https://b.hatena.ne.jp/guide/bbutton)にサンプルのHTMLコードがあるので、これをコピペすればはてなブックマークのボタンを表示できます。

```
<a href="https://b.hatena.ne.jp/entry/" class="hatena-bookmark-button" data-hatena-bookmark-layout="basic-label-counter" data-hatena-bookmark-lang="ja" title="このエントリーをはてなブックマークに追加"><img src="https://b.st-hatena.com/images/v4/public/entry-button/button-only@2x.png" alt="このエントリーをはてなブックマークに追加" width="20" height="20" style="border: none;" /></a><script type="text/javascript" src="https://b.st-hatena.com/js/bookmark_button.js" charset="utf-8" async="async"></script>
```

はてぶボタンを押すと、タイトル名とURL（ドメイン名）の共有する画面が表示されます。
タイトル名は、meta property="og:title"タグの中の文言でした。試してないけど、このmetaタグがなかったら他の値が使用されるのかも。。
（ちなみに自分のローカル環境の場合、タイトル名は表示されなかった。）

### Twitter・はてなブックマークボタンのシェアボタンのデザインをカスタマイズしたい場合

シェアボタンのデザインを色々とカスタマイズしたい場合、下のサイトが参考になりそうです（公式サイトにあるデフォルトデザインで満足してしまったので試してはないです）。
・[コピペで簡単！はてなブログのSNSシェアボタンをカスタマイズ](https://www.notitle-weblog.com/hatena-share-button/)

### 参考サイト
・[Facebook・Twitter・LINE・Pocket・はてブの公式シェアボタンリンクまとめ](https://qiita.com/flatsato/items/d931f13a92c09e4dd655)
・[ソーシャルボタンまとめ](https://qiita.com/butchi_y/items/b365dc7ac4739ac9c74d)
React Router v6のネストについて

結論：公式ドキュメントをしっかり読みましょう（笑）

Reactを復習していたとき、講座内のReact Routerがv5で大幅に記述が異なっていて、
甘えてググってしまい沼に陥ってしまいました。
# ネストする時の基本ルール
参考：https://reactrouter.com/docs/en/v6/getting-started/overview
## Routeコンポーネントを入れ子にする
こちらは単純で、
```react
<Route path="/" element={<App />}>
  <Route path="page1" element={<Page1 />}>
    <Route path="detaila" element={<Page1DetailA />} />
  </Route>
</Route>
```
以上のような記述で、
- /
- /page1
- /page1/detaila

3ページを定義することができます。
さらに深い階層の定義に関しても同様の記述で可能です。

## 子階層のレンダリング位置をOutletコンポーネントで定義
入れ子構造にする際は、
親コンポーネントのどこに子コンポーネントをレンダリングするか、を記述する必要があります。
レンダリングする位置に
```react
<Outlet />
```
を記述すればOKです。

ルールは以上になります。
結構シンプルですね。
公式ドキュメントを読んでみたら意外と5分で解決みたいなことはよくありますので、
一度公式ドキュメントと闘う癖をつけた方がいいかもしれないですね。
システムリリースの不安な気持ち

# はじめに 

https://qiita.com/stkent/items/5b6daf3a5c9c56f4089e?utm_campaign=popular_items&utm_medium=twitter&utm_source=dlvr.it

~~をパクって~~にインスパイアされ、過去の経験を元に記事を起こしたいと思います。


# システムリリースは異常な精神状態下で行う作業である
私はシステムリリース作業を何度も経験しましたが、あの精神状態はあまり味わいたくないです。
複数人いると多少の心強さは感じますが、データセンターで一人での作業は心臓がはち切れそうでした。
どんなに周到に準備した手順書ですら、機能しない時もしばしば体験しました。
体験をもとに私が考えるシステムリリースのベストプラクティスを紹介します。

# リリース手順書
## システムコマンドは必ずコピペする
これは重要です。先にも述べた通り、異常な精神状態なので自分の指先すら信用してはならないのです。
私のターゲットはほとんどがLinuxでしたので、
テキストファイルにコマンドを記録しておき、順番に実行すれば作業が完了できるように手順書を用意してました。
現在ならマークダウンに記述するのも良いと思います。


## 正常系だけでなく異常系も記述する
しっかりリリース手順書をテストしていても、なぜだか上手くいかない場合がありました。
(お客さんが勝手にプロダクション環境をいじっている場合もありました。)

このような場合に備え、調査する時間も作業時間にできるだけ含めるようにしていました。
それに加え、リリースを断念する判断基準も明確にしておくのも重要です。
例えば、
**「１時間調査しても原因が特定できない場合、リリースを断念する」**
というように記述し、事前にお客さんと合意形成をしておく必要があります。


## Batchは可能な限り分割する
これは設計に関わることですが、大きなBatchを１本用意するよりも、小分けにしておいた方が良いです。
Batch処理の終盤でランタイムエラーなどで処理が中断しても、途中の処理から再開でき、リカバリー時間が短縮できる為です。


## データセンター内作業は要注意、書籍や文献等を十分用意する
最近データセンターには行っていませんので分かりませんが、私の時代は携帯の電波が届きませんでした。
(PHSは使えるところもありました)
リリース作業時に障害が発生すると、インターネットのリソースに頼りたくなりますが、データセンター内ではそうは行きませんでした。
Linuxであればコマンドのリファレンス等を準備しておりました。


## それでも不十分
いくら周到に準備しても、やはりリリース作業中の障害は発生しますので、
普段から訓練しておくことを強くお勧めします。

## おわりに
最近は大規模なシステムリリース作業に関わることは無くなりました。
今思い返しても、リリースできなかったことはないと記憶してます。

システムリリース作業に関わる方のご参考になればと思い、この記事を書きました。

以上
不要になったOCIのクラウドアカウントを削除する

# はじめに

不要になったOCIのクラウドアカウントを削除しようとしたら少しハマったのでメモとして残します。
公式な手順としては、OCIのドキュメント **「[テナンシの削除およびクラウド・アカウントの終了](https://docs.oracle.com/ja-jp/iaas/Content/General/Tasks/deleting_tenancy.htm)」** に書かれています。
**テナンシの削除(delete)** と、**クラウドアカウントの終了(terminate)** が正しい呼び方になります。
これによると、条件として以下のように書かれています。

> ・テナンシがホーム・リージョンにあること。
> ・テナンシに子テナンシがないこと。
> ・テナンシがユニバーサル・クレジット・サブスクリプションを使用していること。
> ・テナンシはFree Tier、無料トライアルであるか、PAYGにアップグレードしました(それ以外の場合、営業担当に連絡してください)。
> ・テナンシに組織管理作業リクエストがないこと。

私の場合は全部条件を満たしてそうなので、このドキュメントに従ってやっていきます。

# クラウドアカウントの削除をする

まずは **「テナンシ詳細」** を選びます。

![01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272753/6a572be7-1f16-3f08-6bea-c3cc40127e71.jpeg)

**「テナンシの削除のリクエスト」** というボタンがあるのでクリックします。

![02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272753/74b85ed2-9ed9-585d-0ec4-c5d03b76e0a8.jpeg)

この画面でテナンシ名を入力して、**「テナンシの削除のリクエスト」** をクリックします。

![03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272753/3675548a-5e6d-3827-6a1f-10c6dc17505c.jpeg)

すると、こんなエラーメッセージが出てきて削除できません。
リソース（インスタンス、VCN(仮想クラウド・ネットワーク)など）が残っていることが原因かと考え、該当のテナンシからリソースを全て削除して再度実行してみたのですが状況は変わりません。

![04.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272753/8c4bd3d1-eb46-3995-cfcc-e84febea4600.jpeg)


# サポートに連絡する

しょうがないのでサポートに連絡します。
以下の画面で **「サポート・チャット」** をクリックして問い合わせます。

![05.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272753/f661c000-c318-0354-9601-fea5459b8ffa.jpeg)

英語でクラウドアカウントを終了(terminate)したい旨を伝えると、次のように返ってきました。

![06.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272753/7ab92923-ff07-6f6c-b6e4-1453f8f05d5c.jpeg)

どうやらFree Tierアカウントのままだと、チャットボットが返信するだけで、サポートの人は対応してくれないようです。詰んだ。。。

# オラクルに連絡する

どうにかする方法はないかと調べていたところ、 **「支払のアップグレードと管理」** から、オラクルに連絡できることがわかりました。

![s00.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272753/af8d0f32-6590-e2b4-5246-79ae60009f8a.jpeg)

ここで、 **「営業コールのリクエスト」** をクリックします。

![s01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272753/34f97b64-1bf4-aae9-93b9-1867d75f83c2.jpeg)

メールアドレスと電話番号を入力して **「送信」** します。

![s02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272753/5b7fa9ed-f181-8b43-a62c-6edbdb361776.jpeg)

# オラクルの人から電話が・・

翌日、オラクルの中の人（おそらくサポート担当）から電話がかかってきました。
ここでクラウドアカウントを終了(terminate)したいのにできない旨を伝えると、チケットを切って対応してくれるようです。
アカウントの終了のために、理由を添えて合意した旨を英語でメールするよう言われたので返信しました。

> Since it is no longer needed, I agree to delete my Tenancy and terminate my Cloud Account.

# その後

メールでの依頼から1週間ほど経ちましたが特に音沙汰がありませんでした。
そのためオラクルの方に確認のメールをしたところ、その日に **「アカウントの削除が完了しました」** と返信がきました。

念のため削除されたことを確認しようとOCIにログイン確認したところ、 **なぜかログインできてしまいます。**
そして、インスタンスの作成もできました・・・

再度こちらから削除されていない旨をメールすると、**「再度確認しましたがお客様のアカウントは削除されています」** と返信がきました。
で、もう1度確認すると **やっぱりログインできる。。**

ということでこちらからアカウントが削除されていないことを示す証跡を送って、現在進行形で対応中です。
進展あり次第、追記しようと思います。

# （2022年8月追記）

1ヶ月ほど経ってオラクルサポートから連絡がありました。
- アカウント削除後もログインできてインスタンス作成できるのは不具合だったので修正した。
- アカウントの終了(terminate)が完了した。
    - 確認したところログインできないことを確認
- アカウントの終了後、30日以内に削除(delete)される
- 削除後は、同じテナンシ名で第三者がクラウドアカウントを作成することも可能になる。

ということで1ヶ月以上かかりましたが無事解決しました。
belongs_toとhas_manyを使ったDBへの参照先指定(アソシエーション)

belongs_toとhas_manyの意味としてはこちらの記事で扱っているので、
こちらを前提として進めていきます。

学習中ですので間違えている箇所があると思いますが、ご容赦ください:bow_tone1:

https://qiita.com/3Meshi_Pro9_ram/items/b87f2314f3aa17b4f46c

usersテーブルはすでに作成されており、schemaに新たにrelationshipsテーブルを作成します。
```schema.rb
 create_table "relationships", force: :cascade do |t|
    t.integer "following_id", null: false
    t.integer "follower_id", null: false
    :
  end

 create_table "users", force: :cascade do |t|
    :
    t.string "name"
    t.text "introduction"
    :
  end
```
今回はuser同士をどう紐づけるかということで悩みました。
今まではuserモデルとbookモデルを1対多の関係でbelongs_toとhas_manyを使っていましたが、今回は同じモデル同士での紐付けとなるので、どこかしらで矛盾が発生し、表現が難しくなります。

そこで今回は、中間テーブルという仮のテーブルを用意し、Userとrelashionshipsを１対多の関係で結び、
user同士に関係を持たせるという表現になります。

ここではUserを大まかに２つに分けています</br>
<ul>
  <li>フォローされる側</li></br>
  <li>フォローする側</li>
</ul>
どちらもUserです。

relationshipモデルにに記述する際は、以下のように記述します。
```relationship.rb
  belongs_to :following, class_name: 'User'
  belongs_to :follower, class_name: 'User'
```

belongs_toが参照する先は、モデル（テーブルを作成するときに作ったモデル）名を参照し、合致するモデル名があれば
モデルに対応したテーブルを参照します。
followingとfollowerが指定されていますが、合致するモデル名は存在ません。
relationshipsテーブルの中にfollower、followingのカラムがありますが、それは検索対象ではありませんので、
nil（何もない）が帰ってくると思います。⇦多分

先ほど、この二つのレコードはどちらもUserを二つに分割したもの
そもそもの実態はUserです。

ですので、後ろのclass_nameで、実態はどのモデルに格納されているのかを指定してあげています。

この場合followerとfollowingのどちらもUserが本体ですので、Userモデルを参照先として指定しています。

```user.rb
  has_many :relationships, foreign_key: :following_id
  has_many :followings, through: :relationships, source: :follower

  has_many :reverse_of_relationships, class_name: 'Relationship', foreign_key: :follower_id
  has_many :followers, through: :reverse_of_relationships, source: :following
```

こちらはUserモデルです。
userは複数のrelationship(followerもしくはfollowing)のデータを持っており、
foreign_keyで、relationshipsテーブルに格納されているfollowerもしくはfollowingは
どちらのUsersを持つのかを指定しています。
つまり、relationships(users)が、followerとfollowingのどちらに属しているとするのかを指定しています。
reverse_of_relationshipsは、人間が勝手につけた仮のテーブル名で、先ほどのbelongs_to　:followerと同じように参照先が存在しません。
ですので、class_nameにモデル名を指定して、そこが本体のモデル名だと指定する必要があります。
※ここで同じ名前にしないのは、変数と同じような問題になることを防ぐためです。

<h2>through</h2>
こちらは中間テーブルを介してデータの取得ができるというものです。

throughを使うと、中間テーブルと関連づいたテーブルの参照ができます。<br>
例えば
```
has_many :followings, through: :relationships, source: :follower
```
を見てみます。
relationshipsテーブルと関連づいたカラムには、followerとfollowingがありました。
throughを使うことで中間テーブルと関連づいたテーブルデータの参照ができます。
この場合、userは複数のfollowingを持っており、参照先であるfollowingsテーブルは存在しませんが、relationshipsテーブルにはカラムとして存在します。
relationshipsにあるデータを取得するためにthroughでrelationshipsテーブルを参照先に指定してあります。

![スクリーンショット 2022-06-30 3.49.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2687611/f88e41fe-4c49-047d-57df-ee606171257f.png)

今の状況を図で表すとこのようになります。

sourceは、
[あるuserがフォローしている人（複数）=あるuserにフォローされている人]
という関係があるので、
中間テーブルを介して、[あるユーザーにフォローされている人（follower）]を取ってこれるようになります。

```
has_many :followers, through: :reverse_of_relationship, source: :following
```

これも
[あるユーザーのフォロワー（複数）＝あるユーザーをフォローしている人]の関係があるので、
中間テーブルを介して、[あるユーザーをフォローしている人（following）]を取ってこれるようになります。

参考文献

https://www.youtube.com/watch?v=gATeEnr8gh4
Rails 5.2系から6系へアップデートする際の落とし穴

## 内容
Rails 5.2系から6系へアップデートをした際に、`ActionView::Template::Error invalid base64` エラーが発生してしまう

## 結論
CSRFトークンのフォーマットの違いが原因で発生するエラー

Rails 5.2.5ではCSRFトークンのフォーマットにbase64_urlsafeを利用しているのですが、Rails 6.0系ではbase64_strictを利用している、この違いによってArgumentErrorが起きるようです

## 原因
Rails6.0系のアップデートで、フォーマット方式を変更できるオプションを用意しないまま、フォーマット方式が強制的に変わってしまった
それにより、base64_urlsafeをデコードできずに、エラーが発生してしまう

```
rails: 5.2.5 -> 6.0.x
CSRF Token format: base64_urlsafe → base64_strict
```

https://github.com/rails/rails/issues/41783



## 解決法
解決策は2つあります
1. Rails6.1系にアップデートをする
1. 一旦5.2.6にバージョンアップし、`Rails.application.config.action_controller.urlsafe_csrf_tokens`の設定をする

### 1. Rails6.1系にアップデートをする
Railsの6.1系からは、CSRFトークンのデフォルトエンコード方式がurlsafe版のbase64に切り替わっているので、問題なくアップデートができる

https://github.com/rails/rails/pull/18496

### 2. 一旦5.2.6にバージョンアップ
Rails.application.config.action_controller.urlsafe_csrf_tokensというフォーマット方式を設定できるオプションが
5.2系は5.2.6で設定可能になりました

この設定をすることにより、安全にRails6.0系へのアップデートを行うことができます
はじめてのMacOS〜homebrewでpathを通すのにハマった話〜

## 初めに
会社支給のpcがmac book proだったため
色々苦労していますがやらないと覚えないのでチャレンジ・・・
今回はhomebrewでハマったので備忘録として残す。

## 対象者　
~~長年windowsOSでやってきてMacOS触ったことない人~~
->Windowsとかではなく、guiに慣れててcuiに慣れてない人

## homebrewとは
pythonでいうpipみたいな感じでbrewとやると色々環境作れるらしい。

<h3><b>すごい<b><h3>

## インストール後毎回パス通すのめんどくさい
というわけで環境変数を設定します！！！
pathを通します！！！

https://amateur-engineer.com/mac-path-zsh/

## pathを通して満足したものの他の入れてみる。
macのgitよりかバージョン管理できるgitに切り替えよう。

https://qiita.com/saku2021/items/b167f8f449a85e57061b


## brewは認識するのにgitは認識しない。
以下のようにpathを追加したところ

```
export PATH=$PATH:/opt/homebrew/bin
# HomebrewのGitを使うパス
export PATH=$PATH:/opt/homebrew/opt/git
```


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1211754/d553cad5-dfa6-3971-e491-e8a6e8d5887e.png)

切り替わってない！！！


## 原因を探す

```
$ brew doctor
```
すると色々わかるっぽい。

```
Warning: /usr/bin occurs before /opt/homebrew/bin in your PATH.
This means that system-provided programs will be used instead of those
provided by Homebrew. Consider setting your PATH so that
/opt/homebrew/bin occurs before /usr/bin. Here is a one-liner:
  echo 'export PATH="/opt/homebrew/bin:$PATH"' >> ~/.zshrc
```

Warning:が出てるじゃん！

usr配下のbin先に見ちゃうけどいい？
って書いてある。

このbinが先だとgitは初期のmacのやつを見に行くんだなきっと。


```
export PATH=/opt/homebrew/bin:$PATH
# HomebrewのGitを使うパス
export PATH=/opt/homebrew/opt/git:$PATH
```

既にあるpathの前に自分の追加したpathを記載するように修正した結果

```
$ git --version
git version 2.37.0
```

gitをmacの標準ではなくbrewで入れることができた！！

## おさらい

```
$ brew docotor
```
で出力文をかくにんしよう。
Bitriseのビルド環境に事前にインストールされているものが何かを知る方法

Bitriseのビルド環境（Stackと呼ぶ）では、HomebrewやCocoaPods、Bundlerなど、iOSアプリをビルドするために必要なツールが事前にインストールされています。
ただ、これらのツールのバージョンがいくつなのか、他にどんなツールがインストールされているかを知りたいことがあります。

<br><br>

実は、以下のリポジトリにStackに関する情報がまとまっています。

https://github.com/bitrise-io/bitrise.io

例えば、現在の最新版であるXcode13.4のStackの情報はこちらです。

https://github.com/bitrise-io/bitrise.io/blob/master/system_reports/osx-xcode-13.4.x.log

Homebrewのバージョンは`3.4.11`であることがわかります。

![Cursor_と_https___raw_githubusercontent_com_bitrise-io_bitrise_io_master_system_reports_GEN2_INTEL_osx-xcode-13_4_x_log.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81715/194ba18c-5b9a-88f4-51bf-660ec076a220.png)

CocoaPodsは`1.11.3`のようです。

![Cursor_と_https___raw_githubusercontent_com_bitrise-io_bitrise_io_master_system_reports_GEN2_INTEL_osx-xcode-13_4_x_log.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81715/a1c3871b-7441-8d94-ebf7-ae8de150431f.png)

<br><br>

なお、BitriseのWorkflow Editorのリンクから上記リポジトリのページに飛ぶこともできます。

![Cursor_と_Bitrise_Workflow_editor.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81715/31a6f691-980c-8156-8662-4bbb654948ea.png)
[Swift] 一度だけ変更可能なプロパティを実装する方法

初期値はnilで、その後1回値を代入したら、その後何度代入しても値が変わらないプロパティを実装したい。

didSetを使うと、以下のようにシンプルに実装できました。

```swift
struct User {
    var id: Int? {
        didSet {
            if oldValue != nil {
                id = oldValue
            }
        }
    }
}
```

```swift
var user = User()
print(user.id)  // 初期値はnil
user.id = 1
print(user.id)  // 1に変わった
user.id = 2
print(user.id)  // 1のまま変わらない
```
kubernetesで依存関係のあるDeploymentを正しい順番で起動する

`docker-compose`での`depends_on`に対応した機能は、kubernetesではデフォルトではサポートされていません。本記事は、それを解決する手法についてです。

## Deployment.yaml

`app1`が`db`に依存しているという状況を考えます。何も考えずにmanifestを書くと、以下のようになるかと思います。

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app1
  labels:
    app-name: app1
  namespace: ns
spec:
  replicas: 1
  selector:
    matchLabels:
      app-name: app1
  template:
    metadata:
      labels:
        app-name: app1
      name: app1
    spec:
      containers:
      - name: app1
        image: SOME_API_IMAGE
      restartPolicy: Always

---

apiVersion: apps/v1
kind: Deployment
metadata:
  name: db
  labels:
    app-name: db
  namespace: ns
spec:
  replicas: 1
  selector:
    matchLabels:
      app-name: db
  template:
    metadata:
      labels:
        app-name: db
      name: db
    spec:
      containers:
      - name: db
        image: mongo:4.2.21
      restartPolicy: Always
```

しかし、これでは起動順が保証されないため、`app1`が正しく起動しないということが容易に起こります。そこで、`app1`に`InitContainers`の記述を追加することで、起動を遅延させます。そこでは、experimentalな機能として追加されている`kubectl wait`を用います。すると、以下のような形になります。

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app1
  labels:
    app-name: app1
  namespace: ns
spec:
  replicas: 1
  selector:
    matchLabels:
      app-name: app1
  template:
    metadata:
      labels:
        app-name: app1
      name: app1
    spec:
      containers:
      - name: app1
        image: SOME_API_IMAGE
      restartPolicy: Always
      initContainers:
        - name: wait-for-deps
          image: bitnami/kubectl:1.24
          imagePullPolicy: IfNotPresent
          command:
            - /bin/sh
            - -exc
            - kubectl wait pods --for=condition=Ready -n ns -l "app-name in (${APP_NAMES})"
          env:
            - name: APP_NAMES
              value: db
```

ここで、環境変数`APP_NAMES`は`db1, db2`のように複数指定できます。

## ClusterRole.yaml

この段階では以下のエラーメッセージにより、エラーが出るかと思います。

```
Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:ns:default" cannot list resource "pods" in API group "" in the namespace "ns"
```

これは権限不足のエラーになるので、以下のようにRoleを設定してあげます。

```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-reader
  labels:
    death-star-project: ns
  namespace: ns
rules:
  - apiGroups: [""]
    resources: ["services", "endpoints", "pods"]
    verbs: ["get", "list", "watch"]

---

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: pod-reader
  labels:
    death-star-project: ns
  namespace: ns
subjects:
  - kind: ServiceAccount
    name: default
    namespace: ns
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: ""
```

以上操作により、`db`→`app1`の順番で起動することが保証されたmanifestを作成することができます。

## おわりに

自分はそこまでk8sに詳しいわけではないので、実運用ではこうしていてこの処理はいらないなど改善策があればコメント頂けると幸いです。
クラスメソッドとインスタンスメソッド

# クラスメソッドとインスタンスメソッドについての気づきたち
## クラスメソッドの定義方法
```rb
class User
  def self.greeting
    puts "クラスメソッドへようこそ"
  end
end
```
- **メソッドの前に`self.`を指定**
## インスタンスメソッド
```rb
class User
  def greeting
    puts "インスタンスメソッドへようこそ"
  end
end
```
## 使い分け
:::note info
クラスメソッド：クラス全体に関係する処理で使用する
:::
:::note warn
インスタンスメソッド：インスタンスに対して個別的に適用したい処理で使用する
:::

## ⚠️
クラスメソッド・インスタンスメソッドに関する知識は、ここに蓄積していくため、編集・追記が多くなると思いますが、ご容赦ください・・・・
Android StudioでGitHubアカウントにログイン、リモートリポジトリを作成、pushする

# 概要
Android Studio上でGitHubと連携し、バージョン管理を行うためには、GitHubアカウントにログインする必要がある。その際アクセストークンを用いて認証を行う。また、リモートリポジトリの作成、プッシュをコマンドラインを使わずにAndrod Studio内で完結することも可能である。これらの操作をflutterプロジェクトを新規作成した際に行うことが多いため、手順を備忘録として残しておく。


# 手順
1. githubアカウントのアクセストークンを発行
2. アクセストークンを利用してログイン
3. リモートリポジトリを作成
4. pushする

# 1. githubアカウントのアクセストークンを発行

ブラウザからGitHubにログインし、Settings -> Developer Settings -> Personal access tokens -> Generate new tokenの順に遷移して、アクセストークン作成画面を開く。
Noteに「personal」など、適当な名前を入力する。Expirationはトークンの有効期限で、90日程度で良い
repo, admin:org, gistなどにチェックを入れ、Generate tokenでトークンを生成。
トークンをコピーし、メモなどに一次保存する。

## 2. アクセストークンを利用してログイン

Android Studioを開いて、preference -> GitHub -> 左下の+の順に遷移してLog In to GitHubを開く。
右上のUse Tokenを押して、Tokenに先程コピーしたトークンを貼り付けてLog Inする。ログインされれば、自分のアカウントが一覧に表示されるはずである。

## 3. リモートリポジトリを作成

Android Studio上で、VCS -> Import into Version Control -> Share Project on GitHubを選択して、先程ログインしたGitHubアカウントに新規リポジトリを作成する。リモートリポジトリ名はデフォルトでプロジェクト名になっているが変更可能。コマンド操作をしなくても簡単にリポジトリが作成できる。

## 4. pushする

最後に、VCS -> Git -> Pushの順に遷移して、リモートリポジトリにプッシュすることができる。
冒険者の教えと騎士の心得

今回はファンタジー？な問題作

### こんにちは、Javaおじさんのシキムです。


40才目前で、プログラム工学に興味を持ったので本や記事で読んだ難しい話を
咀嚼して簡単な言葉で語りたいと思います。

-----
ファンタジー小説の、よくあるパターンに冒険者と騎士の争いの話があります。
まずは、冒険者と騎士の争いについてしばらくお付き合いください。

冒険者曰く、
----
騎士団は堅物だ。「規則だ。規則だ。」とうるさくてしょうがない。臨機応援に戦わなきゃいけないんだ。それに一人だと弱っちいやつばっかじゃないか。

騎士団曰く、
----
冒険者は野蛮だ。すぐ個人プレーに走る。なにが臨機応変だ、行き当たりばったりというんだよ。お前のところの新入りは、両手に２本づつ剣もって４刀流だって叫んでたぞ。

まさに、言いたい放題である。
----
どうでしょうか？王道のファンタジーの争いって感じだと思います。
そしてこの後、ともに戦う姿を見ることでお互いを認め合う流れがよくあるパターンです。
　
魔物との激闘のあと、彼らは語りました。

冒険者の戦い方(冒険者の教え)
----
冒険者はパーティで組んで、個と個の繋がりを大事にして戦っていたよ。**冒険者の教え**を基本として、どんな敵にもタイプに応じて最適な戦い方をしていたね。確かに臨機応変な戦いぶりだったよ。


騎士団の戦い方(騎士の心得)
----
**騎士の心得**によって集団を個として戦っていたよ。弱かった連中も集団を個とすることで一定の強さで戦えていたね。大きな敵も戦術によってきっちり倒していたね。
　
　
お互いに、相手のいいところが見えてきたようです。

冒険者と騎士団のメリットまとめ
----
**冒険者**
・個と個の繋がりで連携して戦う。
・それぞれの戦い方を意識して臨機応変に戦いを行うことができる。
・魔族のボスなど１体の強大な魔物に強い

**騎士**
・集団を個として戦う
・弱いも騎士も同じ戦い方をすることで一定の戦いを行うことができる。
・大型の魔物や集団の魔物に強い

そろそろ、設計の話をしようか。
----
今回の話は、現実のエンジニア界隈をイメージしていました。

冒険者は、自社開発エンジニア。
騎士団は、SIerエンジニア
冒険者の教えや騎士の心得は、設計学やシステム工学

をイメージしていました。

少人数でアプリケーションやサービスを開発する自社開発エンジニア
大人数で大型のシステムを開発するSIerエンジニア

意外と近いものがあると思います。

そして、ここからが本題
----
エンジニアの**冒険者の教え**や**騎士の心得**は、どちらも**設計学**や**システム工学**のようなものになると思います。

しかし、これでは突き詰めていくと最初の冒険者と騎士団の争いが起きてしまいかねないと思っています。最も顕著なのが、可読性についてです。

**自社開発エンジニアの目指す可読性とは、難解ではあるが知識があれば、複雑なものでも可読性を維持したまま開発できること。**

そして、

**SIerエンジニアの目指す可読性とは、万人が理解でき全員が同じものを開発できること。**

同じ可読性といっても、置かれる状況によって目指しているものに差が出ているのだと思います。

もちろん、変更容易性などお互いに同じ考えもあるとはおもいますが可読性のような大きな隔たりが発生することが多くあるとお思います。

設計を考えるときには、**冒険者の教え**と**騎士の心得**を分けて考えることが必要ではないか？
そんなことを考えて、設計とは何ぞやという問題にこれからも向き合っていきたいと思います。
　
　
　
　

**なお、あくまでも自社開発エンジニアとSIerエンジニアは雰囲気としてイメージ付けるために表現したものであり特定の職業をディスっているわけではありません。**
AWS EBSの用語要点まとめ（自分メモ

・Amazon EBS（Elastic Block Store）
EBSはEC2インスタンスに割り当てられるブロックストレージで、物理ハードディスクドライブと同じように利用できる。
ブロックストレージとは記憶媒体を「ブロック」という固定長の単位で分割して管理するストレージのこと。AWSには「Amazon EBS」というブロックストレージのストレージサービスがあります。

・EBSとEC2インスタンス
EBSは必要に応じて複数作成し、EC2インスタンスにアタッチ（取り付け）して利用します。ただし作成したボリュームは1つのEC2インスタンスからのみアタッチでき、基本的には同時に2つ以上のインスタンスからアクセスすることはできない。
一部のボリュームタイプでは複数インスタンスからのアタッチが可能な「マルチアタッチ」機能に対応。ただし、利用できるインスタンスタイプやリージョンが限られているなどの制限事項があります。

また、EBSは各AZに独立して存在します。あるAZに存在するEC2インスタンスは同じAZに存在するEBSボリュームをアタッチできますが、別のAZに存在するEBSボリュームはアタッチできません。同じAZに存在するEBSボリュームであれば、一つのEC2インスタンスに複数アタッチすることもできます。

・ボリュームタイプ
EBSには容量や性能の異なるボリュームタイプがあり。EBSボリュームを作成する際に、以下のボリュームタイプから用途に合ったものを選択。
１、汎用SSD（ｇｐ２、ｇｐ３）ーEC2インスタンスの起動ボリュームや開発環境。１GiB〜１６TiB。16000iOPS。２５０MiB/s（ｇｐ２）、１０００Mib/s(gp3)
２、プロビジョンドIOPS SSD(io1)ー汎用より高い性能が要求されるシステム。大規模DBなど。４Gib~16TiB。６４０００IOPS。１０００MiB/s。
３、プロビジョンドIOPS SSD(io２)ーio1より高性能、高信頼性、１００倍の耐久性、１０倍のIOPS。４Gib~16TiB。６４０００IOPS。１０００MiB/s。
４、スループット最適化（ｓｔ１）ービッグデータやシーケンシャル、ログの処理。ECインスタンスの起動ボリュームには選択できない。５００Gib~16TiB。５００IOPS。５００MiB/s。
５、コールドHDD（ｓｃ１）ー利用頻度の低いログやバックアップのデータ保管用。ECインスタンスの起動ボリュームには選択できない。５００Gib~16TiB。２５０IOPS。２５０MiB/s。

io1とio2は同じ「プロビジョンドIOPS SSD」ですが、io2はio1と比べて耐久性と性能に優れています。耐久性について、io1では99.8～99.9%、io2では99.999%と設計されており、io2はio1より100倍高い耐久性があります。また容量あたりのIOPS性能も、io1では1GiBあたり50IOPSであったのに対して、io2では1GiBあたり500IOPSと10倍の性能を発揮できるように設計されています。
1GBあたりの利用料金は、高価なものから順に「プロビジョンドIOPS SSD（io1、io2）」、「汎用SSD（gp2）」、「スループット最適化HDD（st1）」、「コールドHDD（sc1）」となっています。

・DeleteOnTermination（終了時に削除）
EBSボリューム上に保存したデータは、EC2インスタンスを終了（削除）すると削除される。保持したい場合はEBSの設定「終了時に削除」のチェックを外すか、「DeleteOnTermination」の値を「false」に設定。
「終了時に削除」のチェックはEC2インスタンスの起動（作成）時に設定する必要がある。
終了時に削除（DeleteOnTermination）のデフォルト値は、EBSがEC2インスタンスのルートボリュームかそうでないかで異なります。ルートボリュームの場合は「true（削除される）」、ルートボリュームではない場合は「false（削除されない）」に設定されています。
ルートボリューム（ルートデバイスボリューム）... OSの起動イメージが格納されていたり、システムによって使用されるデータが格納されたボリューム
なお、EC2インスタンスの動作中に設定を変更したい場合は、コンソールではなくAWS CLIを利用。

・スナップショット
EBSは、データのバックアップ手段としてスナップショット機能を備えています。スナップショットとはある時点のストレージの状態（保存されているファイル群など）を取得したもののこと。例えばデータが破損した場合やある時点のデータに戻したい場合、スナップショットをリストアすることでストレージ上のデータが復元。
EBSではスナップショットから新しいEBSボリュームを作成することもできます。スナップショットを基にEBSボリュームを作成する際は、異なるAZを選択できたり、暗号化機能を付与することもできます。
スナップショット機能およびスナップショットからのボリュームの作成機能を利用することで、別のAZへデータを移行することができます。

・暗号化
EBSでは、ボリュームやスナップショットを暗号化することで機密性を高めることができる。暗号化する際はAWS KMS（Key Management Service：暗号化に使用するキーを作成・管理するサービス）を利用。
暗号化の設定はEBSボリューム作成時に指定。作成したボリュームの暗号化ステータスは後から変更できないので注意。
暗号化を行うには、事前にKMSにおいて暗号化に使用するキーを作成し「マスターキー」欄へ入力。
なお、作成済みのEBSボリュームの暗号化ステータスは変更できないが、スナップショットからEBSボリュームを作り直すことで、既存のデータを保持したまま暗号化ステータスの異なるEBSボリュームを作成できます。

・RAID（Redundant Arrays of Inexpensive Disks：レイド）
EBSでは、アタッチしているEC2インスタンスのOSの機能を利用してEBSボリュームのRAID構成を組むことができます。
RAIDとは複数のボリュームを論理的に1つのボリュームとして構成する技術のことです。RAIDにはいくつかの種類がありますが、そのうちの1つ「RAID 0」は、複数のボリュームへデータを分散して書き込むことによって、1台のボリュームに続けて書き込むよりも高速にデータアクセスを行います（ストライピング）。
EBSボリュームの性能上限はio1またはio2のプロビジョンドIOPS次第ですが、上限値を超えた性能が必要な場合、RAID 0を構成することによって性能向上を見込めます。
ただし、RAIDを構成している場合はスナップショットの取得時に注意が必要です。単独のEBSボリュームだけではリストア時にデータの不整合など問題が発生する可能性があるため、複数のボリュームに対してスナップショットを取得する「マルチボリュームスナップショット」を使用します。
マルチボリュームスナップショットでは、特定のボリュームではなく、ボリューム群をアタッチしているEC2インスタンスを指定してスナップショットを取得します。
このまえCloudflareで障害があったらしいけど、そういえばCDNってなんだっけ？


## はじめに
先日業務中にCloudflareでの障害が別チームの業務に影響があったのでこの件を知ることとなる。
Cloudflareで発生した障害のあらましとしては、新しいアーキテクチャへの移行作業中に発生したBGP設定ミスが原因とのこと。
※BGPとはAS（自立システム）間で経路情報をやり取りするルーティングプロトコルの一つである。

そしてそのCloudflareでの障害がなぜ影響したかというと【CloudflareはCDNプロバイダー】だからである。

ん〜なるほど。
そういや<b>【CDN】</B>ってなんだっけ？

## CDNとは

CDNとは<b>【コンテンツ・デリバリー・ネットワーク】</b>の略称。

なにをしてくれるものかというと、インターネット上に配置した<b>代理サーバー（キャッシュサーバー）</b>に<b>コピー（キャッシュ）したコンテンツ</b>を配置することで<b>効率よくコンテンツを配信</b>することができるというもの。

そう、【コンテンツ】を【デリバリー】してくれる【ネットワーク】である。

## CDNを使うとなにが良いの？
使用するメリットを含めてもう少し掘り下げてみよう。

まずは<b>負荷分散</b>ができるとういう点。
複数の代理サーバーにコンテンツのコピーを配置することができるので、大量のアクセスがあっても負荷を分散することができて遅延したり落ちたりするリスクを引き下げることができる。

次に<b>表示速度の改善</b>。
オリジナルのコンテンツが存在するサーバー（オリジンサーバー）よりもユーザーに近い代理サーバーから配信することで、表示速度を落とさずコンテンツを配信することができる。

また副次的にではあるが負荷分散の観点で<b>DDoS攻撃</b>をとりあえず防いでくれる。



## おわりに
なるほど<b>【CDN】</B>完全に理解した。（ダニングクルーガー効果をご存知？）

ちなみにBGP設定ミスによる通信障害って今回に限ったことではなく過去に何度かあったのね。
機会があれば通信障害の発生ケースをお題に勉強してみようかな？

https://www.orangeitems.com/entry/2021/10/11/163550
Google Vision APIを用いてOCRをした結果をJSONファイルで保存/読み込みする

# 記事概要

Google Vision APIを用いてOCRをした際の結果を再利用するためにJSONファイルに書き出し、読み込みを行います。

## 本記事の前提条件

環境における前提としてGoogleのVision APIのアクセスキー登録やライブラリのダウンロードが終わっているものとします。

筆者はソースコードも含め下記を参考にしているため、そちらを一度参照するとスムースに本記事が読めると思います。

https://qiita.com/shoku-pan/items/bf5645894803769edc72#vision-api-%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2%E3%83%83%E3%83%97


## モチベーション

Googleの提供するVision APIはかなり良い精度のOCRを可能にしてくれますが、**従量課金制になっているためなるべく少ない回数の呼び出しで済ませたい**という事情があります。


具体的には、OCRのテキスト抽出に限って言うとだいたい下記のようになっています。

- 月に1000画像まで無料
- 以後は1000画像あたり1.5$（非常に大量にやると割引になる）
- なお、最初に登録したときに300$のクレジットが付与される

本当のところはもっと細かいので以下のページを参考にしてください。

https://cloud.google.com/vision/pricing?hl=ja

正直結構安い気もしますがfor文が入ったコードとかをデバッグしまくると1000画像なんかは結構簡単に超えちゃいそうなので一度APIの処理結果をファイルとして保存してあとからいろいろな処理をしたくなります。

# 解決策

解決策として下記の手順をとります。

- APIを呼び出して結果を取得
- OCRの結果が格納されたobjectをJSON形式で相互変換
- JSONのdump/loadで読み書き

## APIを使ってOCR結果を取得

これは引用元のQiita記事のコピーになります。

```py
# 画像のファイル名:input_file を 定義すること
import io
from google.cloud import vision

client = vision.ImageAnnotatorClient()
with io.open(input_file, 'rb') as image_file:
    content = image_file.read()
image = vision.Image(content=content)
# 結果を格納するobjectを取得
response = client.document_text_detection(image=image)
```

## OCRの結果をJSON形式に相互変換


先程得られた結果は`google.cloud.vision_v1.types.image_annotator.AnnotateImageResponse`という型のobjectになっているため、json形式に変換して読み書きをするようにします。

下記のStackoverflowの質疑を見た感じそれ用の変換関数が用意されているようです。

https://stackoverflow.com/questions/52169264/vision-api-how-to-get-json-output


ひとまず下記の関数で相互変換が可能でした。ドキュメントはしっかり読み込んでいないので変なところがあったら教えて下さい。

```python
from google.cloud.vision import AnnotateImageResponse

# object->json
json_data = AnnotateImageResponse.to_json(response)
# json->object
response_ = AnnotateImageResponse.from_json(json_data)

# True
print(response == response_)
```


## ファイルに読み書き

JSON形式になったのでdump/loadで読み書きができます。
ということでそれっぽく関数を書くとすると下記の様になります。

```python
import json
from google.cloud.vision import AnnotateImageResponse

def save_as_json(response, filename):
    data = AnnotateImageResponse.to_json(response)
    with open(filename, mode='wt', encoding='utf-8') as file:
        json.dump(data, file, ensure_ascii=False, indent=2)
        
def load_from_json(filename):
    with open(filename, mode='r', encoding='utf-8') as file:
        temp = json.load(file)
    response = AnnotateImageResponse.from_json(temp)
    return response
```
【Vercel】自動テスト【Next.js】

## Vercelにデプロイする
まず下記の Vercel サイトの右上の"Sign Up"からGitアカウントでサインアップしてください。

https://vercel.com/

![スクリーンショット 2022-05-06 2.34.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/f85586de-283c-e749-3522-0053d177540f.png)

![スクリーンショット 2022-05-06 2.35.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/c2db746d-8758-dc5c-ec65-8ec5fe981878.png)

サインアップが完了したら画面左側の`Import Git Repository`の入力フォームをクリックし、`Add GitHub Account`を選択してください。

![スクリーンショット 2022-05-06 2.39.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/926f9a2f-4fea-9863-c211-02ec1f51f4d1.png)

GitHubのページが表示されますので`Repository access`の箇所の`Only select repositories`を選択し、リポジトリを選択します。

![スクリーンショット 2022-05-06 2.44.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/d6083a9e-249c-16ec-ef15-d1dccf8fadf2.png)

選択したら`Save`をクリックしてください。

すると`Import Git Repository`に先ほど選択したリポジトリが表示されます。
`import`をクリックします。
![スクリーンショット 2022-05-06 2.47.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/75b11a0e-10be-3995-18bf-e3312f6692f5.png)


表示された画面の`Configure Project`に必要事項を入力します。
![スクリーンショット 2022-05-06 2.48.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/c4f577fa-5e88-9ada-66c8-007b9a4f6229.png)

入力ができたら`Deploy`をクリックします。

しばらくすると以下のような画面が表示されます。

![スクリーンショット 2022-05-06 2.54.18のコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/4598cba7-6def-865a-5df4-0c5f520444fd.png)

赤枠内をクリックして正常に動作していればデプロイは完了です。

## 自動テストの設定
プロジェクトのダッシュボードを開きます。
![スクリーンショット 2022-06-30 午前0.41.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/ccfa4e86-f60e-cf51-1dcf-14ca6e89d68e.png)

`settings`をクリックします。
![スクリーンショット 2022-06-30 午前0.41.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/23e9e3b6-168e-9632-e4d9-8f3caf40896d.png)


`General`の中の`Build & Development Setting`を探します。
`Build & Development Setting`の`BUILD COMMAND`の`OVERRIDE`をオンにします。
![スクリーンショット 2022-06-30 午前0.43.52のコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/665b5851-f8fe-64a0-9eb7-ccd35ce8fb22.png)

下画像のように`yarn test && next build`または`npm test && next build`と入力します。
![スクリーンショット 2022-06-30 午前0.46.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/4e0223b8-6ee0-466d-2a7a-556f15d1d92c.png)

これで`git push`した際にテストを実行し、テストが通った場合のみ`build`とデプロイが実行されるようになります。
技育博に参加してみて

# はじめに
　　今回は技術の共有というよりは情報の共有・僕の備忘録に近しいところがありますので参考になる方はあまりいらっしゃらないかも知れません。ですが、終了してから3日経ってもこんなに気分が高揚して、楽しかったなと思うのは久しぶりだったので書かせてください。また、詳細な動き方とかは他の方が書かれてますので、そちらを見てみてください。僕は感情メインのお話をしたいと思います。

# 技育博とは
　　技育博はサポーターズさんがこのコロナ禍で消えたオフラインでのエンジニアのつながりをもう一度再建しようとして考えてくださって僕たち学生にくださったとても貴重な機会です。
　　本当はサポーターズさんの方でキャッチコピーを作ってくださっているのですが、僕が当日参加して感じたサポーターズの運営さんの思いや僕も思いをメインとして書きました。

# やってること・感じていたこと
　　まずは、僕のやってることをちょっと書かせてもらいます。

　　1.プログラミングサークルEngineの代表
　　2.学生団体データサイエンス倶楽部の運営会長
　　3.JST未来プロジェクトの一分野にプロジェクトメンバーとして参加
　　4.企業さんから業務委託をいただいて金融時系列データの分析

　　とても運がよく、さまざまなことを経験させていただいています。

　　ですが、周りからの期待・自分自身への決意・譲れないことが相まっていつしか自分の首を絞めて走り続けることを自分に強制していました。

　　結果、遊びに行くこともなくなった。周りからしたら「仕事・勉強の方が大事みたい」って思われたのでしょうね。いつからか、孤独になりました。なんなら後ろ指差されるようになりました。

　　仕事ではミスを重ねて、自分に自信が持てなくなって。何もしたくなくて。なんで自分はこんなことをやっているんだろうか。なんのためにやっているんだろうか。そんな暗澹たる気持ちでした。

　　そんな時に技育博の案内を受けました。正直な話、最初は前向きな気持ちじゃなかったです。でも、少しでも環境が変わる可能性があるならそれにかけてみてもいいかな、どうせ1日だしと思って参加を決めました。

# 参加してみて
　　後ろ向きな気持ちで入った技育博でしたが、実際に参加してみて周りの熱量に圧倒されました。自分よりも全然優秀で前にいるような人たちが肩並べて走ってる。

　　衝撃でした。でも、それと同じくらい嬉しかったんです。ああ、自分がやっていたことは間違いではなかった。あの空間全てが僕を肯定してくれているように感じました。大袈裟に聞こえるかも知れませんが、本当にそう感じました。

　　自分は自信を持って今の道を走ればいいんだ。そうやって背中を押された気がします。そして、お前にはまだできることがたくさんあるぞ。そう言われた気がするんです。

　　他の団体さんと個別に話すことも何度かあって、僕個人としてですが他団体の活動に参加することにもなっています。

　　精神的に苦しくてもプログラムを書き続けていたあの時間。ふと孤独を感じても勉強を続けたあの時間。自己嫌悪に陥りながらも仕事を続けたあの時間。全て二度と経験したくないくらいキツかったです。

　　でも、その時間があったからこそ今の自分があって、コミュニティーがある。そして、それら全てを包み込んで肯定してくれたあの瞬間あの空間は何があっても忘れません。

　　オフラインって、エンジニアって、仲間って最高だなって思いました。

　　でも何よりも技育博って最高だなって思いました。

# 最後に
　　まずは、今回のような機会を作ってくださったサポーターズ運営のみなさん、また協賛企業の皆様。本当にありがとうございました。

　　そして、僕とお話した方もそうでない方もあの環境を作り出してくださった参加学生の皆様。ありがとうございました。

　　みなさんのおかげで僕は新たな一歩を踏み出そうと決められました。暗澹たる気持ちから抜け出せました。自分を許すことができました。本当に感謝しています。

　　あの環境にいなければ僕はまだ下を向いていたと思います。でも、あの環境にいたことで上を向くことができました。

　　また機会があれば絶対に参加してみたいと思います。今回は名刺を用意してませんでしたが、次回は名刺を用意して。しりとりに参加して。

　　最後になりますが、あの空間を提供してくださった皆様に感謝を。またどこかでお会いしましょう。
FlutterでCrashlyticsが上手く機能しないときに試すこと

## 自動データ収集設定を有効化する。
```dart
await FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(true);
```
これをCrashlyticsを初期化するときにセットしておくとデータの自動収集を有効化できます。

## iOSの場合
![スクリーンショット 2022-06-30 0.33.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1086494/43493ca7-6b1c-d78d-b7eb-343e79795e30.png)
Build SettingsのDebug Information FormatをDWARF with dSYM Fileに変更する。
また、Generate debug symbolがYesに設定されているか確認する。

ずいぶんハマりましたが、僕はこれでとりあえず解決しました。
プログラマならPDCAよりOODAなのか？

## はじめに
「業務改善のアイデア出して」
「スピード感を持って業務を進めてください」
...そんなこと言われても、やり方知らない！

そんなあなたにはPDCAやOODAという思考法が必要かもしれません。
この記事では、PDCAやOODAのメリット/デメリットや向き不向きの実例を解説します。

## 対象者
この記事は下記のような人を対象にしています。

- 駆け出しエンジニア
- プログラミング初学者
- PDCAって聞いたことあるけど、やり方知らない人
- OODAって何て読むの？な人

## 結論
- 中長期の目線が必要or定型業務ならPDCA
- 短期的な視点orアイデア発想が必要ならOODA

## PDCAとは
PDCAは工場の業務改善のために編み出された思想です。

### Plan(計画する)
まずは現状を分析し、目標を設定します。
現状分析には[IPO/SIPOC](https://qiita.com/YutaManaka/items/6e6df2fd0397898d930a)や[ロジックツリー](https://qiita.com/YutaManaka/items/59e549073f7bff792d48)が役立ちます。
目標設定には[5W2H](https://qiita.com/YutaManaka/items/0fa94826082c7505d1b9)や[SMART](https://qiita.com/YutaManaka/items/e6b31aa13f5fd90bb2f5)が便利でしょう。

目標を設定した後、アクションプランを計画します。
計画の立案には[SWOT](https://qiita.com/YutaManaka/items/e0b43b7c94f03cdc15d2)や[ペイオフマトリクス](https://qiita.com/YutaManaka/items/26f8d142d5d2f3eef459)などを使います。
### Do(実行する)
目標と計画が定まれば、あとはやるだけ。
やる順番は[GTD](https://qiita.com/YutaManaka/items/a1c917951b1ef00d76e2)で管理し、全体スケジュールは[ガントチャート](https://qiita.com/YutaManaka/items/574ccff0a9bbd8dbe7b7)で管理しましょう。

### Check(振り返る)
実行がひと段落したら、その結果について、振り返りを行います。
目標がSMARTに設定できていれば、数字で振り返りができるのでおすすめです。

### Action(改善する)
振り返りを終えたら、次のサイクルに移るための改善案を考えましょう。
KPT(Keep/Problem/Try)などで改善案を出していきます。

上記の4つのパートを1サイクルとして、どんどんサイクルを進めていくのがPDCAの基本的な流れになります。

### PDCAのメリット/デメリット
全てうまくいきそうなPDCAですが、良いところもあれば、悪いところもあります。

:::note
PDCAのメリット
- 目標が明確になる
- 実行に集中できる
- 改善点が分かりやすい
:::

:::note alert
PDCAのデメリット
- Planに時間をかけ過ぎて、それ以外が疎かになりがち
- 想定外の事態に弱い
- 新しい発想が生まれにくい
:::

### PDCAに向いている業務
PDCAは元々、アメリカで工場のライン作業の品質を上げるために発想された思想です。
日本に持ち込まれて、アメリカ人以上にうまく使えたおかげで、日本の製造業が高度経済成長期を支えたのはあまりにも有名な話。

というわけで、以下のような、製造業系の業務に向いています。

:::note
PDCAに向いている業務
- 中長期の視点が必要な、企業の戦略立案
- ルーティーンワークが多い業務(工場のライン作業など)
- 失敗したら取り返しのつかない業務
:::

プログラマーの仕事でも、保守運用の定型業務はPDCAサイクルで進めるとうまくいきそうですね。

## OODAとは
OODAは「ウーダ」と読みます。
OODAはスピード重視のプロセスになります。
アメリカの空軍パイロットが朝鮮戦争で戦績を上げた時の体験をもとに理論を組み立てました。

### Observe(観察する)
まずは現場で起きていることを観察します。
このときに、今までの常識を一旦忘れて、観察に徹する、という姿勢が大事です。

### Orient(理解する)
観察して得られた情報から原因を推察したり、それに対する対応策のアイデアを出します。
この段階では「出来なさそう」「あほらしい」みたいなバイアスは一旦外して、とにかく自由にアイデアを出すのが大事です。

### Decide(決める)
理解するフェーズで出たアイデアから、実行するものを決めます。
このとき、PDCAのPlanのようにガッチリとした目標や行動指針のようなものは要りません。
「現状でベストだと思われるのはこれだから、まずやってみよう」という気持ちでOKです。

### Act(実行する)
最後に実行します。
この実行の結果、何かしらの変化が起きるはずなので、それをまた観察して、OODAループを繰り返していく...そして成功するまでやり続ける、という流れになります。

### OODAのメリット/デメリット
PDCAに比べて新しい発想のOODAですが、当然メリット/デメリットがあります。

:::note
OODAのメリット
- 最初から成功する必要がないので、精神的に楽。
- 素早く行動できる
- 状況の変化に強い
:::

:::note alert
OODAのデメリット
- 失敗する確率が高まる
- ルーティーンワーク/業務改善に不向き
:::

### OODAに向いている業務
刻々と状況の変わる戦場でいかに敵機を撃墜して生還するか、というミッションのために編み出された思考法のため、徹底した現場主義がOODAの特徴です。
下記のような業務が向いているでしょう。

:::note
OODAに向いている業務
- 短期的に結果が求められるプロジェクト
- 状況が目まぐるしく変化するクライアントワーク
- 新しい発想が必要な業務
:::

プログラマーの業務だと、新機能の実装や、障害の修正などに向いているでしょう。

## PDCAとOODAは表裏一体
計画重視で定型業務の改善に強いPDCAと、スピード重視でアイデア発想に強いOODA。
「PDCAはオワコン。OODAが最新の思考法だ！」という論調が流行っていますが、自分は賛成しかねます。
どちらもあくまで思考法なので、どちらか一方しか使ってはいけない、というわけではありません。
それぞれに強み・向き不向きがあるので、うまく使い分けていくのがベストだと思います。

## おわりに
PDCAとOODAについてまとめました。
うまく使い分けて業務を効率よく進めましょう。


## 参考記事
[【もう時代遅れ？】PDCAとは？ 致命的な問題点、失敗する原因、企業事例](https://www.kaonavi.jp/dictionary/pdca/)
JLCPCBで紫の基板を作ろう

# はじめに
JLCPCBでは何と**紫色の基板が2ドルで作れる**とのことで早速発注してみました。
紫基板製造は去年の9月からサービスを始めた模様
https://twitter.com/jlcpcb_japan/status/1434813075329196032

JLCPCBのサイトはこちら！
https://jlcpcb.com/
JLCPCBは新規ユーザー向けに54ドルのクーポンを配っています。
https://jlcpcb.com/JPV

# 他の基板メーカーとの比較
紫色基板を作ろうと思った時のその他の基板メーカーとの比較
(条件：基板厚1.6mm , サイズ100x100mm , 2層 , 枚数5枚)
**<font color="Red">・JPCPCB　 　⇒　2ドル</font>**
・Elecrow　　⇒　19.90ドル
・FusionPCB　⇒　取り扱い無し
・PCBWay　　 ⇒　38.96ドル

上記の通り、JLCPCB以外のメーカーと比較するとメチャクチャ安いですよね。
**今の所紫色を作るならJLCPCB一択です**

紫色基板の注文はこちらからできます
https://cart.jlcpcb.com/quote

# 今回作ったもの
トラ技2019.4を参考に、Digilent社のAnalogDiscovery2の雑音ジェネレータの強化基板を作成しました。

ってわけでJLCPCBから届いた基板はこれ↓
綺麗に紫色になっています。
![IMG_9528 - コピー.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867623/f5319db8-541b-9865-ce6d-6c9b7c168ca4.jpeg)

実装もした
![IMG_9525 - コピー.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867623/530eafac-fb86-8232-6fd3-1bc853739bf9.jpeg)
![IMG_9524 - コピー.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867623/21f8e5d3-20bc-9ed8-1eee-89358174b75e.jpeg)

# 実際に動かしてみた
AnalogDiscovery2の雑音出力は下のように、クロック成分がかなり強く出ています。
![1MHz_Noisegen_scope - コピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867623/8f2953c8-912f-463e-eed0-9567fc1285d1.png)
これを今回作成した基板を通すと…
![IMG_9526.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867623/1871ddaa-2be9-e674-79d6-87f16ac289fc.jpeg)
![1MHz_White.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867623/cc5f1083-9a87-e88b-4225-543254af8f7e.png)

クロックの成分が取れて滑らかなりました

# 紫色基板発注方法

このリンクからJLCPCBのオーダー画面に飛ぶ
https://cart.jlcpcb.com/quote
**画面中段、「PCB Color」でPuepleを選択しよう！**
※細かい発注の仕方はこの記事を参考に
[JLCPCBで基板を作ろう[KiCad6編]](https://qiita.com/Konbanwa11/items/4e1d14b7cdc2282063fb)
![スクリーンショット 2022-06-26 171721.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867623/4251bbe8-224a-a2b1-7083-284616248271.png)

# 最後に
今回、珍しい紫色の基板が安く、2ドルで作れるとのことで発注してみましたが、
その他基板メーカーと比べて1/10の値段なのに紫の発色も良く、基板自体のクオリティも高いので非常に満足な結果となりました。

この記事を読んだ方々も是非注文してみてはいかがでしょうか。

JLCPCBは以下のリンクより、新規ユーザー向けに54ドルのクーポンを配っていますので、
新規ユーザーは更に安く作れるかも知れません。
https://jlcpcb.com/JPV