OmniAICreator/Qiita-1.07M huggingface dataset:
実務未経験・転職で入った会社を完走しました

まいど！
エンジニアで一番可愛い☆はるかちゃん☆やで！

今日はエンジニア実務未経験で入った会社を退職することになったので、どう成長したかを整理してみようと思うで。

:::note warn
警告
そんなん個人ブログに書けやって言わないでね
:::

# 経歴
### 現職までの流れ
大学院卒業 => メーカー研究職 => ITスタートアップのエンジニア => もうすぐ退職 <font color="red";">now!</font>

### エンジニアになる前から（入社前から）そこそこ出来たの？
後述しますが、ゼロキャリアですし、技術的にもど素人でした

### 何年いたの？
丸２年ほどエンジニアとして働かせて頂きました。

### どんな会社にいたの？
エンジニア5~8人くらいのスタートアップです。
メディア運営が主軸です

# 従事した業務
Ruby On Rails, TypeScriptを使用したアプリケーションの、機能追加・改善が主な業務です。

# 技術の棚卸
### Ruby（メソッド）
<dl>
<dt>Before</dt>
<dd>
ポートフォリオを作るときに使用するような、ベーシックなメソッドしか知らない状態。例えば、"each"は知ってても、"each_with_index"は知らない、みたいなイメージ
</dd>
<dt>After</dt>
<dd>
業務で適切なメソッドが出てこなくて困ることがほぼ無い状態。出てこなくても、「こんなメソッドあるやろ？」って検索したら大抵見つかるような感じ。もちろん、Rubyには膨大な数のメソッドがあるので、知らないものに行き当たることも普通にありますね。<br>
ちな、好きなメソッドは"tap"。君は？
</dd>
</dl>

### TypeScript（文法全般）
<dl>
<dt>Before</dt>
<dd>
入社前は使っていなかった
Javascriptを使用していたが
とんでもない苦手意識があって、特にコールバック関数を書くところが最高に気持ち悪いと思っていた。<br>
入社して間もない頃に、上長に向かって「Javascript全然わからないんですけど入社して大丈夫でした？」ってドキドキしながら聞いたのもいい思い出。
</dd>
<dt>After</dt>
<dd>
実は、Rubyと比較してTypeScriptをゴリゴリ書く業務が少なかったので、マスターした感じは全くない。<br>
TypeScript特有の型やインタフェースも入門レベルにしか使いこなせてない印象。
ただ、文法的には苦手意識というのは無くなって、むしろ好きかも状態です。
ReactやVueを業務で触る機会がなかったのは少し悔しい。
</dd>
</dl>

### CSS
<dl>
<dt>Before</dt>
<dd>
文字の色が変わったね？　よし、完成！<br>
みたいな状態
</dd>
<dt>After</dt>
<dd>
BEMをベースとしたクラスの命名規則を設定し、書いていました。
スコープへの気配りや、スタイルを極力アイテム化して使いまわせるようにと考えてました。<br>
ReactやVueだとコンポーネントですもんね、その辺は業務ではアンタッチ。
</dd>
</dl>

### OOD（オブジェクト指向設計）
<dl>
<dt>Before</dt>
<dd>
オブジェクト指向って言葉は知ってる
</dd>
<dt>After</dt>
<dd>
いろいろ本は読んだので、知識としてはある状態。<br>
ただ実際に使いこなせと言われると困ってしまうなぁ...<br>
スポットスポットではいい感じに設計できたというところもあり。
</dd>
</dl>

### DDD（ドメイン駆動設計）
<dl>
<dt>Before</dt>
<dd>存在も知らない</dd>
<dt>After</dt>
<dd>
実践ドメイン駆動設計　と他２,3冊を読みました。（エヴァンス本は読んでません）<br>
いわゆる「戦術」の方は忘却の彼方です。
「戦略」の方は少しは残ってて、ドメインをアプリに反映させること、ドメインエキスパートと話すこと、ユビキタス言語を決めていくこと・アプリに反映させること。<br>
そんなことを考えてました。
</dd>
</dl>

### SQL
<dl>
<dt>Before</dt>
<dd>ORMを使用していたため、ほぼ知らない</dd>
<dt>After</dt>
<dd>
基本的にはORMを使用していたが、たまーに、SQLを書いたり読んだ入りする機会があった。<br>
そのため、ベーシックなものであれば読み書きできる状態。<br>
応用は無理
</dd>
</dl>

### AWS
<dl>
<dt>Before</dt>
<dd>
ポートフォリオで見よう見まねで使用していた程度。理解はしていない。<br>
ECS, Terraformとか、CircleCIでCI/CDを作ってた。
</dd>
<dt>After</dt>
<dd>
唯一ここが入社前よりも能力的に下がったところかもしれない。<br>
残念すぎることに、一度も業務でAWSに触る機会がなかった。<br>
プライベートでも触らなかったので、知識がほぼ抜けた。
</dd>
</dl>

### テーブル設計
<dl>
<dt>Before</dt>
<dd>
簡単なポートフォリオしか作ってなかったので,そもそもテーブルに設計がいるの？ 状態
</dd>
<dt>After</dt>
<dd>
正規化や、極力Nullにしない、マスタとトランザクションの切り分け<br>
などなど
</dd>
</dl>

# 総評
業務であつかった技術について、基礎的なところは固まりつつある。
一方で、設計力に関しては今後の課題である。

# まとめ
いかがでしたか？
私と同じように、ブームに乗って、実務未経験からエンジニアに転職した人も多くいると思います。
君たちはこの１年で、２年でどれくらい成長した？
今年度もあと少し、そういうことを考えてもいい時期かもね？
☆ハルカ☆でした〜
Basic認証(アプリごとに違うpassを設定する)

とても基本的なことですが記録用にメモします。

新しくWEBアプリケーション開発でBasic認証を設定する際に、
以前作成したアプリのBasic認証用name,passがそのまま反映されてしまったので
原因を調査。

単純に開発環境の環境変数名が以前作成したアプリと同じ変数名になっていた。

(例文)
・以前作成していた環境変数
```
export BASIC_AUTH_USER='sample'
export BASIC_AUTH_PASSWORD='1111'
```

・今回新しく作成した環境変数
```
export BASIC_AUTH_USER='test'
export BASIC_AUTH_PASSWORD='2222'
```

↑これでは同じ変数名にname,passを設定しているので当然違うname,passにはならない。


**改善コード**
```
export BASIC_AUTH_USER_2='test'
export BASIC_AUTH_PASSWORD_2='2222'
```

このように変数名を変更することで違うアプリでも個々に設定できる。

かなり初歩的なことでしたが自分自身で気づいたことなので
アウトプットさせていただきました。

※ご指摘や修正等ございましたらお願いします！

以上
[Docker]docker-compose up でコンテナが立ち上がらない

```docker-compose up -d```を打ったときのエラー。
一部のコンテナが立ち上がらなかった。

# エラー内容
今回はhogeコンテナが立ち上がらない。他のコンテナは立ち上がっているのに。。。
```bash
ERROR: for hoge  Cannot start service hoge: network 4819b288c36316e18ef29e3f0ed22fb84f654ae4f659a2ae87707791d62b2242 not found
ERROR: Encountered errors while bringing up the project.
```

# 解決
どうやら前回docker-compose downした際にプロジェクトを止めることができていなかったよう。
```--remove-orphans```オプションで一旦全て削除してから```docker-compose up```するとうまくいった
```bash
$ docker-compose down --remove-orphans
$ docker-compose up
```
*--remove-orphansは未定義コンテナという意味。

具体的な原因はprojectにdocker-compose.ymlが二つ(A,B)あり、AでUpした一方でBでDownさせた際にこのようなことが起こった。
QMK薙刀式をRemap対応する方法

Keyboard Quantizer rev4(KQ4)に
QMK薙刀式を組み込んでみた。

調べていくうちにQMK薙刀式をRemap対応すれば
パソコン ~ KQ4(薙刀式) ~ USBキーボード
の組み合わせで繋ぐことができる。

色々と試した結果、出来た。
https://github.com/deepprog/qmk_firmware/tree/rp2040/keyboards/keyboard_quantizer/rp/keymaps/naginata
に今回の修正したファイルがあります。

初期ファームウェアがコンパイルできる環境で
make keyboard_quantizer/rp:default:uf2
の代わりに
make keyboard_quantizer/rp:naginata:uf2
に変更します。


対応方法は、QMK薙刀式のレイヤーと、カスタムキーコードの値を固定化することで
Remapのカスタムキーから数値設定したキーを登録する。

```c:naginata.h
//説明のため変更点を抜粋
typedef enum naginata_keycodes {
 //NG_Q = SAFE_RANGE, 
//SAFE_RANGEをやめてカスタムキーで
//使用されないでだろう0x5F50を開始値にする
  NG_Q = 0x5F50,
  NG_W, //0x5F51　Remapカスタムキーに対応する数値
  NG_E, //0x5F52
  NG_R, //0x5F53
  NG_T, //0x5F54
  NG_Y, //0x5F55
  NG_U, //0x5F56
  NG_I, //0x5F57
  NG_O, //0x5F58
  NG_P, //0x5F59

  NG_A, //0x5F5A
  NG_S, //0x5F5B
  NG_D, //0x5F5C
  NG_F, //0x5F5D
  NG_G, //0x5F5E
  NG_H, //0x5F5F
  NG_J, //0x5F60
  NG_K, //0x5F61
  NG_L, //0x5F62
  NG_SCLN, //0x5F63

  NG_Z, //0x5F64
  NG_X, //0x5F65
  NG_C, //0x5F66
  NG_V, //0x5F67
  NG_B, //0x5F68 
  NG_N, //0x5F69
  NG_M, //0x5F6A
  NG_COMM, //0x5F6B
  NG_DOT,  //0x5F6C
  NG_SLSH, //0x5F6D

  NG_SHFT,  //0x5F6E
  NG_SHFT2, //0x5F6F

  NG_ON,    //0x5F70
  NG_OFF,   //0x5F71
  NG_CLR,   //0x5F72
  NGSW_WIN, //0x5F73
  NGSW_MAC, //0x5F74
  NGSW_LNX, //0x5F75
  NG_MLV,   //0x5F76
  NG_SHOS,  //0x5F77
  NG_TAYO,  //0x5F78
  NG_KOTI,  //0x5F79

  NG_SAFE_RANGE, //0x5F7A //※１
} NGKEYS;

//#define NG_SAFE_RANGE SAFE_RANGE42//NG_SAFE_RANGEを※１に移動させる

enum keymap_layers {
_QWERTY = 0,
// 薙刀式
_NAGINATA = 1, // 薙刀式入力レイヤー　1
//Remapで設定するレイヤー番号に対応する。
// 薙刀式
_LOWER = 2,
_RAISE = 3,
};
```

```c:keymap.c
//説明のため変更点を抜粋
enum custom_keycodes {
  EISU = NG_SAFE_RANGE, //0x5F7A
  KANA2,                //0x5F7B

  SPD_1, //0x5F7C
  SPD_2, //0x5F7D
  SPD_3, //0x5F7E
};
```
レイヤーとカスタムキーコードを固定したQMK Firmwareをコンパイルして
対応したレイヤーとカスタムキーをRemapで設定します。
その他は、自作キーボードにQMK薙刀式を
移植する手順と変わりません。

Keyboard Quantizer Bも同じ方法で
対応できるでしょう。

この方法はBMPのカスタムキーを
0x5E00から固定値で設定している方法を参考にしました。
0x5F50はBMPとも重ならない番号です。

動作検証はレイヤー0に２つカスタムキーを設定してます。
~~EISU = 0x5F7A  左altキーに~~
~~KANA2 = 0x5F7B　右altキーに設定しています。~~

~~右altキーで、薙刀式モードに~~
~~左altキーで、通常モードに戻ります。~~

## 追記
編集モードの入力が変？（対応済み）
編集モードで「」をタイプすると、数字が入力された

原因
ユニコードの直接入力にaltの同時押しを利用しているのを忘れていた。

altキーにを設定したため、うまく動いていなかった。
altキーを元に戻し仮にPrtScにKANA2を設定し
「」の入力とカッコ内にカーソルが移動を確認した。

対策
テストはRemap設定を終えてから動作確認をしましょう。


## これは何をしているか　書き欠け途中
Keyboard Quantizer rev4
　USBキーボードのキー入力をカスタマイズできる機器
rev4のマイコンにはRP2040に変更しています。
詳しく下記のリンクから
https://github.com/sekigon-gonnoc/keyboard-quantizer-doc。

カナ配列「薙刀式」のQMK実装版を組み込む。

両方のプログラムを見ていて、
Keyboard Quantizer rev4は
　キーカスタマイズにはRemapで行う。







Remapの設定画面
![keymap.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76042/5289b1aa-6df5-d937-c59d-a75103274d10.png)
pytest の mock を使ってみる【Python】

# やりたいこと
Pythonのテストフレームワークのひとつ「pytest」の「モック」と呼ばれる機能に入門する。

# 環境
- macOS Monterey 12.2.1
- python 3.8.10
- pytest 7.0.1
- pytest-mock 3.7.0

# モックとは
- 「モックアップ」の略。モックアップとは、要はハリボテのこと。実際の機能は持っていないけど、外から見たらその機能を持っているかのように見せることができます。
- pytestにおけるモックには「pytest-mock」ライブラリを使用します。


# インストール
pipで各種ライブラリをインストールします。
```bash
$ pip install pytest pytest-mock
```

# モックを使う方法

以下のようなディレクトリ構成のファイルを題材として使います。
```bash
.
├── src
│   └── mock_target.py
└── tests
    ├── __init__.py
    └── test_mock_target.py
```

モック化を行うときは `mocker.patch("モック化したいオブジェクト", モック化の種類)`のように指定します。
「パッチ」って、なにかにペタっと貼って隠すやつだと思うので、なんとなくニュアンスが理解できます。（？）

## 関数が返す値を固定する

題材として使うテスト対象コードは以下です。
`sample_function()`は、半々の確率でTrueかFalseを返します。
```py:mock_target.py
import random

def sample_function():
    random_number = random.randint(1, 20)
    return random_number % 2 == 0
```

モックを使用したテストコードは以下のようになります。
動的に値を指定したい場合は `return_value` を使います。

```py:test_mock_target.py
import os
import sys

sys.path.append(os.path.join(os.path.dirname(__file__), '..'))

from src.mock_target import sample_function

def test_sample_function(mocker):   # 引数にmockerをいれる
    # mocker.patch('モック化したいオブジェクト', return_value=固定したい値)
    mocker.patch("src.mock_target.sample_function", return_value=True)
    assert sample_function() is True
```

モックを使わず `assert sample_function() is True` とテストした場合、本来は半々の確率で成功か失敗となりますが、
モックを使い、 `sample_function()` の返り値を「True」で固定することにより、つねにこのテストが成功することになります。


## 関数が返す値を動的に指定する


題材として使うテスト対象コードは以下です。
int型の`num`を引数にとる`sample_function()`は、ランダムにTrueかFalseを返します。
```py:mock_target.py
import random

def sample_function(num: int):
    random_number = num + random.randint(1, 20)
    return random_number % 2 == 0
```

モックを使用したテストコードは以下のようになります。
動的に値を指定したい場合は `side_effect` を使います。

```py:test_mock_target.py
import os
import sys

sys.path.append(os.path.join(os.path.dirname(__file__), '..'))

from src.mock_target import sample_function

def return_pattern(num: int):
    if num % 2 == 0:
        return True
    else:
        return False

def test_sample_function(mocker):   # 引数にmockerをいれる
    # mocker.patch('モック化したいオブジェクト', side_effect=動的な値を指定した関数)
    mocker.patch("src.mock_target.sample_function", side_effect=return_pattern)
    assert sample_function(6) is True
```

モックを使わず `assert sample_function(6) is True` とテストした場合、本来はランダムに成功か失敗となりますが、
モックを使い、
「numに偶数を指定した時は`sample_function(num)`の返り値も偶数となる」「numに奇数を指定した時は`sample_function(num)`の返り値も奇数となる」と動的に関数の返り値を指定することで、
 `sample_function(6)` の返り値を「True」で固定することができ、つねにこのテストが成功することになります。





# 参考にした記事
- [[Python] pytest でモックを使う方法(pytest-mock)](https://webbibouroku.com/Blog/Article/pytest-mock)
- [[python] まだmockで消耗してるの？mockを理解するための3つのポイント](https://note.crohaco.net/2015/python-mock/)
- [pytestでMockを使う](https://qiita.com/East-Da/items/211d06359a7573116eb7)
【Flutter】複数あるデータで一意のIDを生成する方法(UUIDの使い方)

# はじめに
Flutterでアプリ開発をしていて、
例えば、ユーザー情報やユーザが作成したデータなど、
データを管理する必要が多々あると思います。

保存したデータを削除、更新、引用など利用する場面で、
重複しない一意のIDを生成する必要がありました。

上記を解決する一つの方法を記事にしたいと思います。

今回は、[uuid](https://pub.dev/packages/uuid "uuidパッケージのURL")というパッケージを使いますので、
uuidの使い方を知りたい人にも役立つはずです。

# 目次
<!-- タイトルとアンカー名を編集 -->
* [①手っ取り早く使い人に向けて](#Chapter1)
* [②uuidとは](#Chapter2)
* [③uuidを使う準備](#Chapter3)
* [④uuidの使い方](Chapter4)
* [⑤uuidを使って一意のIDを生成する方法](Chapter5)

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# ①手っ取り早く使い人に向けて
下記が使用例ですので、手っ取り早く使いたい人はどうぞ。

```dart
import 'package:uuid/uuid.dart';

// 管理するデータのクラス
class UserData {
  String id = '';
  String name = '';

  UserData(this.id, this.name);
}

// データの管理クラス
class UserDataRepsitory {
  List<UserData> userDataList = [];

  void add(String name) {
    var uuid = Uuid();
    // IDを生成する
    var newId = uuid.v4();

    // IDに被りがなくなるまで、ループ
    while (userDataList.any((userData) => userData.id == newId)) {
      // 被りがあるので、IDを再生成する
      newId = uuid.v4();
    }

    // ユーザデータ新規作成
    var newData = UserData(newId, name);
    // ユーザデータを追加
    userDataList.add(newData);
  }
}
```

<a id="#Chapter2"></a>
# ②uuidとは
パッケージで、下記のような文字列を生成してくれます。
「110ec58a-a0f2-4ac4-8393-c866d813b8d1」

<a id="#Chapter3"></a>
# ③uuidを使う準備
pubspec.yamlに「uuid: ^2.2.2」を追加して、pub getしてください。
![qiita5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475427/ffcea18f-8b63-3dff-3bf6-70242a8d91c9.png)


<a id="#Chapter4"></a>
# ④uuidの使い方
パッケージをimport。
```dart
import 'package:uuid/uuid.dart';
```

IDの生成方法は下記です。
uuidには、v4というメソッド以外にも、時間ベースでIDを生成するv1などがありますが、
とりあえずv4を使用しておけばいいと思います。
```dart
    var uuid = Uuid();
    // IDを生成する
    var newId = uuid.v4();
```

<a id="#Chapter5"></a>
# ⑤uuidを使って一意のIDを生成する方法
```dart
// IDのリスト
List<String> idList = [];

// IDを生成
var uuid = Uuid();
var newId = uuid.v4();

// IDに被りがなくなるまで、ループ
while (idList.any((id) => id == newId)) {
  // 被りがあるので、IDを再生成する
  newId = uuid.v4();
}

// IDを追加
idList.add(newId);
```
git push heroku master時のエラー！Precompiling assets failed.

git push heroku master時に以下のエラーが発生した際の解決策を記録

**新規アプリケーションをherokuへ反映する際にエラーが発生した。**

```ターミナル上のエラー文.
 ! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'https://git.heroku.com/アプリ名.git'
```

原因を調査してみると、ターミナル上に
```ターミナル上のエラー文.
Precompiling assets failed.
```
という文があった。

**これは「アセットのプリコンパイルに失敗しました」という意味だった。**

しっかりと上までターミナルを見てみると
ModuleNotFoundError: Module not found: Error: Can't resolve '../tweets' in '/tmp/build_259621bf/app/javascript/packs'というメソッドエラーがあった。

おそらくapp/javascript/packs内で不要な記述をしているのだと思い、
確認すると削除したjavascriptファイルを読み込む記述をしていた。

すぐに削除しコミットプッシュを行い、再度git push heroku masterを実行。

すると問題なくデプロイが成功！

git push heroku master時のエラーは慌てず冷静にログを確認し原因を調査することが大事だと感じた。

※認識が間違っていましたらご指摘いただけると幸いです。

以上
Python_dicのkey検索方法

わかりやすい英語記事があったため、ストック。

word_freq = {
    "Hello": 56,
    "at": 23,
    "test": 43,
    "this": 78
}
key = 'test'

①keyの有無をif文で判断
if key in word_freq:
    print(f"Yes, key: '{key}' exists in dictionary")
else:
    print(f"No, key: '{key}' does not exists in dictionary")


②getを使用する
if word_freq.get(key) is not None:
    print(f"Yes, key: '{key}' exists in dictionary")
else:
    print(f"No, key: '{key}' does not exists in dictionary")

③keyメソッドを使用する
if key in word_freq.keys():
    print(f"Yes, key: '{key}' exists in dictionary")
else:
    print(f"No, key: '{key}' does not exists in dictionary")


④keyの値を求める関数を使用する
#存在しないkeyの場合errorを返すところを利用する
def check_key_exist(test_dict, key):
    try:
       value = test_dict[key]
       return True
    except KeyError:
        return False
word_freq = {
    "Hello": 56,
    "at": 23,
    "test": 43,
    "this": 78
}
key = 'test'
if check_key_exist(word_freq, key):
    print(f"Yes, key: '{key}' exists in dictionary")
else:
    print(f"No, key: '{key}' does not exists in dictionary")


出典
https://thispointer.com/python-how-to-check-if-a-key-exists-in-dictionary/
ubuntuのアプリケーションショートカットを作成する


`~/.local/share/applications`配下に`.desktop`ファイルでデスクトップエントリを作成する。
operaでqiitaを表示するサンプル

```bash:~/.local/share/applications/cutom_opera.desktop
[Desktop Entry]
Version=1.0
Name=custom opera
GenericName=Web browser
Comment=Fast and secure web browser
Exec=opera https://qiita.com
Terminal=false
Icon=opera
Type=Application
Categories=Network;WebBrowser;
```

アプリケーションに表示される
![Screenshot from 2022-03-13 15-05-16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118567/a6a12fff-36fd-560e-1332-6d588c6eb9e2.png)
cscの作法 その50

# 概要

cscの作法、調べてみた。
再帰やってみた。

# 参考にしたページ


https://qiita.com/probabilityhill/items/187c794ea725f68cb30f

# 実行結果

```


>set PATH=C:\Windows\Microsoft.NET\Framework\v2.0.50727;%PATH%

>csc hanoi.cs
Microsoft(R) Visual C# 2005 Compiler version 8.00.50727.8784
for Microsoft(R) Windows(R) 2005 Framework version 2.0.50727
Copyright (C) Microsoft Corporation 2001-2005. All rights reserved.


>hanoi
How many disks? 3
move disk1 from A to C
move disk2 from A to B
move disk1 from C to B
move disk3 from A to C
move disk1 from B to A
move disk2 from B to C
move disk1 from A to C



```


以上。
RedshiftのUDFをLambdaで作る

# はじめに
RedshiftのUDFをLambdaで実装できるようになったとのことで、[開発ガイドのCREATE EXTERNAL FUNCTION](https://docs.aws.amazon.com/ja_jp/redshift/latest/dg/r_CREATE_EXTERNAL_FUNCTION.html)に載っているサンプルで試してみました。（「Python Lambda 関数を使用したスカラー Lambda UDF の例」）

# 事前準備
## IAMロール作成＆Redshiftクラスタ作成
（正直IAMロール系はあまり詳しくなく）「AWSLambdaRole」を付けたRedshift用ロールを作ってRedshiftクラスターを作成。

# Lambda関数作成
ファンクション名：「lambda_multiplication」
ランタイム：「Python 3.8」
コード↓
```python
import json

def lambda_handler(event, context):

    t1 = event['arguments']
    resp = [None]*len(t1)
    
    success = True
    for i, x in enumerate(t1):
        mul = 1
        for j, y in enumerate(x):
            mul = mul*y
            
        if (mul >= 9223372036854775807 or mul <= -9223372036854775808):
            success = False
            break
        else:
            resp[i] = mul
    ret = dict()
    ret['success'] = success
    if not success:
        ret['error_msg'] = "Integer multiplication overflow"
    else:
        ret['results'] = resp
    ret_json = json.dumps(ret)
    
    return ret_json
```

Lambdaをテストするなら下記をテストイベントにセット
```json:テストイベント
{
  "arguments": [[ 1, 2, 3 ]]
}
```

# UDF作成
```SQL:UDF作成
CREATE EXTERNAL FUNCTION exfunc_multiplication2(int, int, int) 
RETURNS INT 
STABLE 
LAMBDA 'lambda_multiplication' 
IAM_ROLE '(作成したIAMロールのarn)';
```

# UDF実行
```SQL:テーブル作成&レコード投入
dev=# CREATE TABLE t_multi (c1 int, c2 int, c3 int);
dev=# INSERT INTO t_multi VALUES (1, 2, 3);
```
```SQL:UDF実行
dev=# SELECT c1,c2,c3,exfunc_multiplication(c1, c2, c3) FROM t_multi;
 c1 | c2 | c3 | exfunc_multiplication2
----+----+----+------------------------
  1 |  2 |  3 |                      6
(1 row)
```

# RedshiftからLambdaに渡されるeventメッセージ
クエリidもわかるのはいいですね。
```json
{
'user': 'postgres01', 
'cluster': '(redshiftクラスターのarn)', 
'database': 'dev', 
'external_function': 'exfunc_multiplication', 
'query_id': 971, 
'request_id': 'b314ebaf-1536-4516-94bf-0df6fa354efd', 
'arguments': [[1, 2, 3]], 
'num_records': 1
}
```
ちなみにテーブルに複数レコードある場合は下記のようになります。
おそらく一定のバルクでレコードをLambda側に渡してるものと思われます。
```json
{
'user': 'postgres01', 
'cluster': '(redshiftクラスターのarn)', 
'database': 'dev', 
'external_function': 'exfunc_multiplication', 
'query_id': 1035, 
'request_id': 'efa5334f-6512-4967-bfc8-3f2131a71782', 
'arguments': [[1, 2, 3], [2, 3, 4]], 
'num_records': 2
}
```

# ちなみに
Explain上もほんの少しcostが変わりました。
```SQL
{
dev=# EXPLAIN SELECT c1,c2,c3,exfunc_multiplication(c1, c2, c3) FROM t_multi;
                        QUERY PLAN
-----------------------------------------------------------
 XN Seq Scan on t_multi  (cost=0.00..0.03 rows=2 width=12)
(1 row)

dev=#
dev=# EXPLAIN SELECT c1,c2,c3 FROM t_multi;
                        QUERY PLAN
-----------------------------------------------------------
 XN Seq Scan on t_multi  (cost=0.00..0.02 rows=2 width=12)
(1 row)
```

# さいごに
細やかなことができるのはいいですが、やはり気になるのはパフォーマンスですよね。。
今後試してみようと思います。
SIGNATE練習問題（アヤメ画像分析）をやってみた

# 背景
* データ分析、機械学習初心者
* KaggleのTitanic練習問題をなんとかやってみた
* 自然言語処理よりは画像認識が時間がかからなそうと聞いたので、やってみた

# 環境
* Jupyter Notebook

    *  Google Colabへ移す予定
    
* Pythonライブラリ
    * pandas
    * sklearn
    * numpy

# 流れ
1. データの読み込み、確認
1. クレンジング（学習データとテストデータの分類）
2. 分類器の作成
2. 学習済みデータをもとに予測、正確性の確認
2. テストデータをもとに予測
2. 結果ファイル作成、提出

# データ読み込み
* サイトにアクセスして、データタブから下記3ファイルをダウンロードしておく
    * train.tsv
    * test.tsv
    * sample_submit.csv

https://signate.jp/competitions/115

* Pythonにて、ライブラリimport、データ読み込み

```python:ayame_recognition.py
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn import svm
from sklearn.model_selection import cross_val_score
from sklearn.metrics import accuracy_score
import numpy as np


Traindata=pd.read_csv("train.tsv",delimiter="\t")
Testdata=pd.read_csv("test.tsv",delimiter="\t")

```
# フォーマットの確認
* SIGNATEのサイトからフォーマットを確認する
    * ヘッダーと、データ型を把握しておく
    * 評価版データの目的変数（Class）を出すことが今回の趣旨である
    * アヤメ品種が3種類あること把握しておく
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2595699/2955e051-c41d-1063-7a5b-4b82361151fe.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2595699/442b020f-fef3-e66d-a780-b3087d83e5af.png)

# クレンジング
* クレンジング（学習データとテストデータの分類）
    * 説明変数と目的変数をそれぞれ別の変数に代入する
    * 複数列の値を全て取り出して、代入
    * 学習データの説明変数、学習データの目的変数、テストデータの説明変数に分ける
```python:ayame_recognition.py
X=Traindata.loc[:,['sepal length in cm','sepal width in cm','petal length in cm','petal width in cm']]
Y=Traindata.loc[:,['class']]
Xt=Testdata.loc[:,['sepal length in cm','sepal width in cm','petal length in cm','petal width in cm']]
```
* 学習用データは、さらに学習用データと試験用データに分類する（2割がテストデータ）
```python:ayame_recognition.py
X_train,X_test,y_train,y_test = train_test_split(X,Y,test_size = 0.2)
```

# 分類器の作成
     * sklearnから分類器を呼び出して、分類した学習用データを入れる
     * fit関数で機械学習する
```python:ayame_recognition.py
clf = svm.SVC()
clf.fit(X_train,y_train)
```

# 学習済みデータをもとに予測、正確性の確認
* 分類器に対して、テストデータを入れて、sklearnのpredict関数で予測する
 ```python:ayame_recognition.py
y_pred = clf.predict(X_test)
```
* 予測したデータと、実際のデータ（classが入ったy_test）が正しい確認する
 ```python:ayame_recognition.py
accuracy = accuracy_score(y_test,y_pred)
print(accuracy*100,'%')
```
* 100.0 %と出たら、予測が正しそう

# テストデータをもとに予測（本番）
```python:ayame_recognition.py
X_pred = np.array(Xt)
y_pred = clf.predict(X_pred)
```
# 結果ファイル作成、提出
* ヘッダー無しにする
```python:ayame_recognition.py
Submit=Testdata.loc[:,['id']]
Submit['result']=y_pred
Submit.to_csv("submit.csv",header=False,index=False)
```
【初心者向け】Python はじめ方

# はじめに
これからPythonをはじめようとしている方（全くの初心者）向けの記事です。

# 最初にすべきことは環境構築

Pythonにかぎらず、プログラミングをはじめるためには、プログラムを書くための環境が必要になります。
初心者の方がまず最初にすべきことは、**この環境を構築すること**です。
しかしながら、初心者の方にとって、**環境構築はとてもハードルが高い**ものです。
プログラミングをはじめようとした方の８割が、この環境構築で挫折すると言われています。

# Google Colaboなら環境構築が不要！
Pythonの場合、**この面倒な環境構築を行わなくても、簡単にプログラミングを始める**ことができます。
それが、Googleの提供するGoogle Colaboratory、略して、**Google Colabo**です。

# Google Colaboの始め方

1. Googleの**アカウント**を取得する
2. [Googleコラボ](https://colab.research.google.com/?hl=ja) にアクセス
3. 右上の**ログインボタン**を押して、ログイン
4. 左上のファイルメニューから**ノートブックを新規作成**を選んで、ノートブックを立ち上げる
これで、Pythonを実行できる環境が整いました。

# ノートブックについて
新規にノートブックを開くと以下のような画面がでてきます
ここでは、簡単なプログラムを書いて、内容を①〜④で説明します。
![スクリーンショット 2022-03-13 14.37.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2118220/6df0654b-2664-8a59-acb0-35ca2a25a619.png)

- ①再生マークがあるセルにプログラムを入力します。
- ②シフト＋エンターを押すとプログラムが実行され、①のすぐ下のセルに結果が表示されます
- ちなみに、print（）は、（）内を表示せよという命令になります。
- ③ GoogleColaboの場合、セルの一番下に書かれたプログラムには、自動でprintが適用されます
- ④テキストを入力できるセルもあります。

# ファイルについて
GoogleColaboで作成したファイルは、拡張子jpynbで**Googleドライブ**に保存されます。
再開するときは、Googleドライブから当該ファイルを開くのが便利です

# 最後に
いかがでしたでしょうか
Google Colaboは自分が入力したプログラムが正しく動くかどうかすぐに確認できるなど、とても使いやすい仕様になっています。
Pythonを使ったデータ分析や機会学種、スクレイピングでも、GoogleColaboで十分対応できますので、ぜひ、積極的に使ってみてください。
AWSリホスト時のテスト

# はじめに
仕事柄、オンプレで稼働しているシステムをAWSにリホストしたいという依頼をよく受けます。その時、必ず検討しなくてはならないのが移行テストです。リホストとは言えAWSへ移行するためには基本的にIPアドレスは変更になります。オンプレでIPアドレスを維持したままのリニューアルに慣れたお客様は割と抵抗がある様ですね。今回は、IPが変わる移行でどうやってテストをするかを考えてみたいと思います。

# 移行しやすい構成
IPアドレスが変更になることを前提に移行テストを考えると、基本的にサーバ間連携を再チェックする必要があります。

1. IPアドレスの直参照をしている場合はできる限りDNS名に参照に切り替える
これは、DBをRDSにしたいなど考えた時、RDSはIP直指定はNGです。なぜなら、RDSのIPアドレスはフェイルオーバー時に変わります。オンプレの負荷分散装置では１つのVIPに対し、負荷分散をしてVIPは変わらないフェールオーバーが一般的かと思いますが、AWSのELBでは、マルチAZによる冗長化が基本なので、そもそもセグメントが違い同じIPに出来ません。

2. DNS名はホスト名ではなく別の参照名を付ける
リホストの場合はアプリの作りを変えるわけにはいかないのでうまくいかないこともありますが、基本的にはホスト名は変更できるようにしておくべきです。IPアドレスとホスト名を同時に変更し、サーバ間参照時に使うDNS名だけを合わせるのが移行時最も楽な構成だと思います。

3. DNSを引くタイミングを確認
例えば、WEBサーバで動いているPHPがDB参照する時、どの段階でDBのDNS名をIPアドレスに変更しているか確認する必要があります。最近はちゃんとDNS TTLを参照してくれている事が多いですが、昔のアプリだと、apacheの起動時にしかDNSを引かないという構成になっていて絶句したことがあります。。。DBコネクションプールを使ったりしていると、そもそもコネクションが維持されている間は元にIPに接続されてしまいます。（まぁ、元のIPに接続できなくなれば強制的に切り替わるかもしれませんが）

その辺りを気にして頂ければと思います。

# 移行方針とテスト手法検討
前章で述べた通り、基本的にはリホスト時にはIP、ホスト名は変更してコピーを作り、現行本番を動作させたまま、テストを行うのがいいと思います。この時、サーバ間参照名を変えないでテストするためには、テスト用のDNSサーバを用意して同じ参照名で別のIPアドレスを返すようにするのが楽だと思います。また、この時、注意して欲しいのが、現行本番への影響です。間違えて本番へ接続してデータを更新してしまったりしないように、しっかりSecurityGroupなりで、アクセスできないようにしてテストする事が重要です。


# まとめ
IPアドレス、ホスト名に依存しないアプリ構成を心がけましょう。
移行テスト時は、本番環境に影響しないようにしっかりSecurityGroupを掛けましょう。
【 『dokojava卒業』vs codeでJavaを使う (Mac OS) 】

現在書籍でJavaを学習中です。
書籍はdokojavaというwebサービスを用いて学習していくのですが、
慣れてきたら自身のPCに開発環境を構築することが推奨されていたので、
今回実際に導入してvs code上でJavaを使用できるようにしようと思います。
(⚠︎僕のPCには既にvs codeはインストール済みです)

## JDKのインストール
JDKとは`Java Development Kit`の略称で、javaで開発をするためのプログラムのセットです。
JDKにはさまざまな種類があるそうですが、今回は`Amazon Corretto`というものをインストールしていこうと思います。

### ■手順

①Amazon Correttoを検索
②AWSサイト内にある、`Amazon Corretto 17`をダウンロードします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2165178/1e7588fd-ce69-445c-587d-70e2e68aad05.png)
③今回はMac OS版をダウンロードしたいので.pkgのつくリンクからダウンロードしました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2165178/98ab98e1-fff4-784b-ac84-08e30c378180.png)
④しっかりダウンロードできたことを確認したいので、ターミナルで`java --version`を実行。
ダウンロードしたバージョンが表示されれば成功です！

## vs codeの拡張機能を導入
Javaで開発をするにあたって便利/必要な拡張機能を導入します。

### ■手順
##### ①Extension Pack for Java
「Javaの基本的な動きをサポートする」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2165178/9310df20-a1e8-fec0-2980-9fbfda2d99c3.png)
##### ②Gradle Extension Pack
「構成管理ツールGradleを使うためのもの」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2165178/591dbbe3-dc30-5a46-b9f8-c8c18763aa7b.png)
##### ③Spring Boot Extionsion Pack
『Javaのフレームワーク「Spring Boot」を使うための拡張機能』
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2165178/cc095455-5264-cd9f-5ed0-fd307d23fd45.png)
##### ④Lombok Annotations Support for VS Code
『冗長的なJavaのコードを軽減する』
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2165178/e94e43d9-10fa-6d09-5752-2d57be2d210c.png)

## vs codeでJavaを実行
Javaプロジェクトを作成〜Javaのプログラムを実行までの流れ。

### ■手順

##### ①vs codeを開き`Create Java Project`を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2165178/f354b5d6-4b1b-14ed-c6a6-72bfa6fd4495.png)
##### ②No Build Toolsを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2165178/e6b9b0a4-d5b0-ad16-5c81-93ade635d88f.png)
##### ③プロジェクト名を命名する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2165178/dc488295-ca3c-f15a-a64d-488eb3f82188.png)
##### ④作成したプロジェクト内にあるApp.javaを開き、`Run`を押すと、実行結果が表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2165178/8aae2fbc-a97b-e85b-0a84-2d94dc066ae0.png)

以上になります！
PythonでXMLの読み込みと書き込み

Pytho で XML を読み書きするサンプルコードです。
以前は xml.dom を使っていましたが ElementTree を使うと楽にできました。
役に立てば幸いです。

# Pythonコード

```python:main.py
# -*- coding: UTF-8 -*-
from xml.dom import minidom
import xml.etree.ElementTree as ET

def save_xml():
  root = ET.Element('root')
  elem1 = ET.SubElement(root, 'elem1')
  elem2 = ET.SubElement(elem1, 'elem2')
  
  # 子ノードを追加
  elem3_1 = ET.SubElement(elem2, 'elem3')
  elem3_1.set('attr1','1234')
  elem3_1.set('attr2','abcd')
  elem3_1.text = 'value1' 

  # 子ノードを追加
  elem3_2 = ET.SubElement(elem2, 'elem3')
  elem3_2.set('attr1','5678')
  elem3_2.set('attr2','efgh')
  elem3_2.text = 'value2' 

    # インデントを付けて保存
  doc = minidom.parseString(ET.tostring(root, 'utf-8'))
  with open('test.xml','w') as f:
    doc.writexml(f, encoding='utf-8', newl='\n', indent='', addindent='  ')

def read_xml():
  tree = ET.parse('test.xml')
  root = tree.getroot()

  # findall()は直下のみなのでiter()を使用
  elems = root.iter('elem3') 
  for e in elems:
    print('attr1='+e.get('attr1')+' attr2='+e.get('attr2')+ ' test=' + e.text)

save_xml()
read_xml()    
```

# save_xml() の結果

```xml:test.xml
<?xml version="1.0" encoding="utf-8"?>
<root>
  <elem1>
    <elem2>
      <elem3 attr1="1234" attr2="abcd">value1</elem3>
      <elem3 attr1="5678" attr2="efgh">value2</elem3>
    </elem2>
  </elem1>
</root>
```

# read_xml() の結果

```
attr1=1234 attr2=abcd test=value1
attr1=5678 attr2=efgh test=value2
```
AutoHotKeyを起動時に自動で立ち上げる


[AutoHotKey](http://ahkwiki.net/Top)って便利ですよね。
Wineodowsの起動時に自動でスクリプトが走ってくれたらもっと便利ですよね。

結論としては作成した`.ahk`ファイルのショートカットファイルを以下に配置しちゃいましょう。
`C:\Users\{ユーザー名}\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup`


# おまけ(自分が使用するスクリプト)

- テキスト入力のショートカット入力を作成しておく
```ahk
InsertText(Content) {
    cb_bk = %ClipboardAll%
    Clipboard = %Content%
    Send, ^v
    Sleep, 200
    Clipboard = %cb_bk%
}

::cddoc::
InsertText("cd C:\Users\{ユーザー名}\Documents")
return
```
PytorchでGPUを使うのを諦めた話(windows)

研究室PCではWindows10 educationが支給される。ここにPytorch+CUDA11.3をインストールするために、GPU周りのソフトウェア環境構築をしてついに使えるぞ！！

```python
print(torch.cuda.is_available())

===
False
```

あれ???

Device ManegerのDisplay adaptersにぶら下がっているのは、Intel(R)HD Graphics 630のみ。CUDAはNVIDIA製のGPUしかサポートされていないので、当然つかえない。新たに買うまでには至らないので、断念しました。

家のm1 mac miniもCUDA使えない。tensorflowはARMチップのGPUが使えるんだけど、CPUと速度が変わらないというし、いろいろと微妙。
Splunk: CSVファイルをルックアップとして登録しテストデータとして使用する

しばしば使用するのでメモ。

###### 実施環境： Splunk Free 8.2.2

ルックアップは一般には既存のデータに対して情報を追加するために使用しますが、その本体がリストデータであることから、簡易的なテストデータとしても使用できます。

例えば、以下のようなテストデータが欲しいとします。

| _time | NUM | STR |
|-----:|:-----|-----:|
| 2022/1/7 9:00:00    | 100 | AAA |
| 2022/1/7 9:00:05    | 200 | BBB |
| 2022/1/7 9:01:00    | 300 | CCC |

本来であればサーバ上で該当のログを作成し、それが Splunk に取り込まれた後に試験を実施するべきですが、環境などによってはそれが難しい場合もあります。
そこで、ルックアップファイルの出番です。
まずは、以下のような CSV ファイルを作成します。
ログ出力日時の列名を「_time」、値を10桁の UNIX 時刻にすることがポイントです。

![スクリーンショット 2022-02-06 21.15.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465018/1b2bc65f-cc1b-2dd8-f96c-08ce48f9b845.png "csv")

この CSV ファイルをルックアップテーブルファイルとして登録します。
あとは inputlookup コマンドを使用することで、この CSV ファイルのデータをそのまま持ってくることが可能です。

```Splunk:Splunk
| inputlookup "testdata.csv"
```

![スクリーンショット 2022-02-06 21.17.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465018/ea8493e5-3727-a245-43db-deade334d7bb.png "inputlookup")

 search コマンドの代わりにこのコマンドを置くことで、登録した CSV ファイルをテストデータとして使用できます。

```Splunk:Splunk
| inputlookup "testdata.csv"
| timechart span=1m sum(NUM)
```

![スクリーンショット 2022-02-06 21.18.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465018/18449f22-6f37-5865-9131-995445a51e5d.png "timechart")

Splunk のアドオンである Lookup Editor と合わせると、テストデータを簡単に作成できるようになるため便利です。
p42 硬貨の問題(C#)


#### 自分(正解)
```c#

using System;
using System.Reflection;

public class Program
{

    public static void Main()
    {
        int c1 = 3;
        int c5 = 2;
        int c10 = 1;
        int c50 = 3;
        int c100 = 0;
        int c500 = 2;
        int A = 620;
        int answer = 0;
        int remainder = 0;
        //{key,value}で対応つけられたら楽かも
        int[] money_list = new int[6] { 500, 100, 50, 10, 5, 1 };
        int[] count_list = new int[6] { c500, c100, c50, c10, c5, c1 };

        int index = -1;
        foreach (int money in money_list)
        {
            index += 1;

            remainder = A / money;

            if (count_list[index] <= remainder) { remainder = count_list[index]; }
            A -= money * remainder;
            answer += remainder;
        }
        Console.WriteLine(answer);

        
    }
}
```


#### もっと簡単に書けた

```
remainder = A / money;
if (count_list[index] <= remainder) { remainder = count_list[index]; }
```

のところは、

```
int remainder = min(A / money, count_list[index]
```
でいけた
Flutterで画像を表示する(Image Widgetを使う)方法

# はじめに
Flutterで画像を表示する方法をいつも忘れてしまうので、メモ書きとして残します。


# 目次
<!-- タイトルとアンカー名を編集 -->
1. [フォルダを作成して画像を配置](#Chapter1)
1. [pubspec.yamlに画像パスを追加](#Chapter2)
1. [Image Widgetを作成](#Chapter3)
1. [結果](#Chapter4)

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# ①フォルダを作成して画像を配置
![qiita1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475427/ef652c2d-ebaf-fddb-1dfd-b70c3d220d09.png)

プロジェクト直下にimagesフォルダを作成。その中に表示する画像を配置します。
AndoroidStudioを使用している場合、
エクスプローラーからドラッグアンドドロップで配置できます。

<a id="#Chapter2"></a>
# ②pubspec.yamlに画像パスを追加
![qiita2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475427/899b4259-024d-1779-5e1f-b1be59f88e0d.png)

上記のように、画像のパスを追記します。
(画像が複数あり、すべて使用する場合は「images/」としてするとよいです）

<a id="#Chapter3"></a>
# ③Image Widgetを作成
![qiita3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475427/c9571bf2-349f-90a4-4d72-8ad8d4ebb514.png)

上画像のように、表示したい場所で下記のコードを記述します。
(パスは配置したものに変更してください。）
```
Image.asset('images/image_path.png')
```

<a id="#Chapter4"></a>
# 結果
![qiita4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475427/26dd7f9f-8efa-fd64-0b3e-c473ef3424ec.png)
AWSへのNAS移行

# はじめに
今回は、AWSへのストレージ移行について書いてみたいと思います。ストレージと言ってもNFS、CIFSなどで接続するNASや、FCやiSCSIなどで接続するSAN、S3の様なオブジェクトストレージなど色々ありますが今回はNASの移行をターゲットいしたいと思います。

# 移行方法検討
最近、AWSにシステム移行するにあたって、NetAppやIsilonと言ったNASをどうしたらよいかという相談を受けることが多いです。
これらのNASをの移行先としてはFSxやEFSが一般的だと思います。場合によっては、この際S3に変更してしまうのもいい考えだと思うのですが、その場合は、NFSやCIFSによるアクセスではなくS3 APIやAWS CLIでのアクセスが必要になります。（StorageGatewayを使えばNFS、CIFSアクセスは可能ですが、可用性、拡張性に難があります）
と言うわけで今回は、NASからFSxやEFSに移行する方法について考えてみたいと思います。

1. rsyncを使う(NFS)
NFSの移行をする場合、最もオーソドックスで枯れた方法です。ただし、速度は速くありません。特に、ファイル数やディレクトリ数が多い場合はとても時間とメモリが必要です。

2. Robocopyを使う(CIFS)
CIFSの移行をする場合、最もオーソドックスな枯れた方法です。ただし、これもrsync同様、小さなファイルやディレクトリが多い場合、速度はあまり早くありません。

3. AWS DataSyncサービスを使う
AWSのサービスで仮想アプライアンスを介してコピーを実施します。仮想アプライアンスはオンプレ(VMware/Hyper-vなどに配置可能)にもEC2にも配置可能です。転送はDirectConnect経由でもインターネット経由でもOKです。通信はTLSで暗号化されます。送り先はFSx、EFS、S3など異機種間での転送も可能です(ただしアクセス権は付けなおす必要あり)速度は、rsync、Robocopyよりは少し早い気がしますが大差ないです。AWSコンソールから移行状態を管理できるので楽と言えば楽だと思います。

4. AWS SnowBallを使う
これはちょっと毛並みが違います。１～３はネットワーク越しにデータを送ることを前提にしていますが、そもそも太い回線を用意できないとか、PB級のデータを送りたいと言った場合はネットワーク越しでも難しいこともあります。そういう場合は、SnowBallという所謂NASをAWSから発送して貰い、それをオンプレで接続してコピーしたのち送り返すという方法があります。送り返したSnowBallのでデータはS3にリストアされます。よって、EFSやFSxに移行したい場合は、S3->EFS,FSxの再転送が必要になります。AWS内のなのでそれなりの速度で実施可能なのですが。そう言った手間があります。また、S3に入った時点で元のCIFSやNFSのパーミションは失われるので、それらを後から復元してやる必要もあります。ネットワークを確保できるならネットワーク転送の方が楽です。

5. SnapMirror(NetApp限定)を使う
NetAppの機能なのでNetApp to FSx for NetApp ONTAPの場合しか使えませんが、そんなの通り、Mirrorを簡単にできてしまうので、超楽です。条件に当てはまるならこの方法一択だと思います。

6. xcp(NetApp限定)を使う
xcpはNetApp社が提供しているツールです。利用にはNetAppのシリアルが必要なのですが、FSx for NetApp ONTAPにはシリアルはないので、NetAppに問い合わせてシリアルを発行してもらう必要があります。このツールは移行元がNetAppの場合、かなりの速度でコピーできます。試しに、rsyncで135時間程掛かったNFS領域(ファイル数 520万、ディレクトリ数60万、容量110GB)をxcpで転送してみたところ30分ほどで終わりました。正直、びっくりですね。どうやってるんだろう。。。コピー元がNetAppだけど何らかの事情でSnapMirrorが使えない場合はこちらがお勧めです。
ただし移行先にEFSは指定できませんでした。portmapに応答してくれないとだめなようですが、EFSは応答しないので。

# まとめ
移行元がNetAppならSnapMirror、Snapmirrorが使えないならxcpがお勧め。移行元がNetApp以外ならDataSyncがお勧め。

# 参考情報
[AWSで利用できるNFSマネージドサービス](https://qiita.com/REALKTMR/items/818d28b65dfe69e0a123)
[AWS Black Belt Online Seminar AWS DataSync](https://d1.awsstatic.com/webinars/jp/pdf/services/20210316_AWSBlackBelt2021_AWS-DataSync-v1.pdf)
[Amazon FSx for NetApp ONTAP(NetAppページ)](https://www.netapp.com/ja/aws/fsx-ontap/)
Javaのループ制御について学んでみる

## ループの制御
while/do...while, for/拡張for命令ではあらかじめ決められた修了条件を満たしたタイミングでループを修了します。しかし、処理によっては、（修了条件に関わらず）特定の条件を満たしたところで強制的にループを中断したい、あるいは、特定の周回だけをスキップしたいということもあるでしょう。
Javaでは、このような場合に備えていくつかのループ制御命令を用意しています。
## break命令
break命令は、現在のループ処理を強制的に中断する命令です。
具体例を見てみましょう。1~100の値を加算していき、合計値が1000を超えたところでループを脱出します。

Main.java
```
package com.company;

public class Main {
    public static void main(String[] args) {
        int i;
        int sum = 0;

        for (i = 1; i <= 100; i++) {
            sum += i;
            if (sum > 1000) {
                break;
            }
        }
        System.out.println("合計金額が1000を超えるのは、1~" + i + "を加算したときです。");
    }
}

```
実行結果
```
合計金額が1000を超えるのは、1~45を加算したときです。
```

この例のように、break命令はifのような条件分岐命令と合わせて利用するのが一般的です（無条件にbreakしてしまうと、そもそもループが1回しか実行されません）。

## continue命令
ループそのものを完全に抜けてしまうbreak命令に対して、現在の集会だけをスキップし、ループそのものは継続して実行するのがcontinue命令の役割です。
次の例は、1~100の範囲で偶数値だけを加算し、その合計値を求めるサンプルです

Main.java
```
package com.company;

public class Main {
    public static void main(String[] args) {
        var sum  = 0;

        for (var i = 0; i <= 100; i++) {
            if (i % 2 != 0) {
                continue;
            }
            sum += i;
        }
        System.out.println("合計値は" + sum + "です。");
    }
}

```
実行結果
```
合計値は2550です。
```
このように、continue命令を用いることで、特定条件の下（ここではカウンター変数iが奇数のとき）で、現在の周回をスキップすることができます。
偶数/奇数の判定は、値が2で割離れるか（2で割った余りが0か）どうかで判定しています。よく利用する方法だそうなので覚えておくとよいそうです。

## 入れこのループを中断/スキップする
制御命令は互いに入れ子（ネスト）にできます。ネストされたループの中で、無条件にbreak/continue命令を使用した場合、内側のループだけを脱出/スキップします。
次の例は九九表を作成するためのサンプルです。ただし、格段ともに50を超えた値は表示しないものとします。

Main.java
```
package com.company;

public class Main {
    public static void main(String[] args) {
        for (var i = 1; i < 10; i++) {
            for (var j = 1; j < 10; j++) {
                var result = i * j;
                if (result > 50) {
                    break;
                }
                System.out.printf(" %2d", result);
            }
            System.out.println();
        }
    }
}

```
実行結果
```
  1  2  3  4  5  6  7  8  9
  2  4  6  8 10 12 14 16 18
  3  6  9 12 15 18 21 24 27
  4  8 12 16 20 24 28 32 36
  5 10 15 20 25 30 35 40 45
  6 12 18 24 30 36 42 48
  7 14 21 28 35 42 49
  8 16 24 32 40 48
  9 18 27 36 45
```
ここでは、変数result（カウンター変数iとjの積）が50を超えたところで、break命令を実行しています。これによって内側のループを脱出するので、結果として、積が50以下である九九表を出力できるわけです。
では、これを「値が一度でも50を超えたら、九九表そのものの出力を停止する」には、どのようにしたらよいでしょうか?これを表すのが次の例です。

Main.java
```
package com.company;

public class Main {
    public static void main(String[] args) {
        limit: // limit:を定義する
        for (var i = 1; i < 10; i++) {
            for (var j = 1; j < 10; j++) {
                var result = i * j;
                if (result > 50) {
                    break limit; // breakの後にlimitをつける
                }
                System.out.printf(" %2d", result);
            }
            System.out.println();
        }
    }
}


```
実行結果
```
  1  2  3  4  5  6  7  8  9
  2  4  6  8 10 12 14 16 18
  3  6  9 12 15 18 21 24 27
  4  8 12 16 20 24 28 32 36
  5 10 15 20 25 30 35 40 45
  6 12 18 24 30 36 42 48
```
「printf(" %2d", result)」は、変数resultを最低2桁で表示しなさい、という意味です（不測時は空白を補います）。
M1 Mac Java

M1 Macにjavaをインストールした際の備忘録
個人的にM1 Macを購入したのでJDKをインストールするためのメモを残す。

参考リンク
https://qiita.com/kinoshitaken123/items/66c631099b4c8f98b3bf


### JDK
JDK17から商用でも使えるそうなのでOracle版を使ってみようと思う。

- OpenJDKのサイト
https://jdk.java.net/17/
![スクリーンショット 2022-03-13 13.05.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15258/59e4f888-4d49-5cea-9f72-44e89523a945.png)

```
java --version
tar xzvf openjdk-17.0.2_macos-aarch64_bin.tar.gz
ls -ll
sudo mv jdk-17.0.2.jdk /Library/Java/JavaVirtualMachines
java --version
openjdk 17.0.2 2022-01-18
OpenJDK Runtime Environment (build 17.0.2+8-86)
OpenJDK 64-Bit Server VM (build 17.0.2+8-86, mixed mode, sharing)
```

JDK11(arm64)も欲しかったのでazulのサイトからダウンロード
+ azulのサイト
azulはjava platformを提供してる会社らしい詳細はリンク先を読んでほしい。
https://www.azul.com/

+ JDKのリンク
https://www.azul.com/downloads/?version=java-17-lts&os=macos&architecture=arm-64-bit&package=jdk

![スクリーンショット 2022-03-13 13.12.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15258/54b3eb29-410a-21b5-3e34-da795f7fa70c.png)


## Eclipse
https://www.eclipse.org/downloads/packages/
Arch64をダウンロード
![スクリーンショット 2022-03-13 13.04.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15258/9f6224f2-6fa0-2db9-3db8-43f6045a38a9.png)

## JDKの切り替え方法
+ 参考サイト
https://amateur-engineer.com/mac-java-version/
 
```
## インストール済みのJava一覧
/usr/libexec/java_home -V
## 環境変数設定
## JDK11に設定した例
export JAVA_HOME=`/usr/libexec/java_home -v "11"`
PATH=$JAVA_HOME/bin:$PATH
```
オンラインエディター比較 簡易レビュー

# はじめに

技術を触れる際にすぐに試せる環境が用意できると、
本質だけを素早く学ぶことができると思いました。

とくに昨今では一つの技術を学ぶために、
それに付随する技術を知らないと、
例えば環境構築に時間を取られ最悪学習までに至らない可能性があります。

このような場合にオンラインエディターサービスが便利でした。
特に最近はサービスのULRをドキュメントにリンクしてあり、
該当コードをすぐに試せたりする状況が進んでいるようにも見えます。
私がそれらのサービスがどのような違いがあるか理解できていなかったので、
備忘録としてサービスを簡単にレビューしてみました。

# サービス紹介/レビュー

今回見てみた対象サービスを紹介します。
どれもgithubアカウントで連携することで無料ですぐに利用できました。

## repl.it

https://replit.com

REPL(read eval print loop)とあるように、
そのコンセプトをそのままサービスにしたような印象です。
私はClojure開発でREPLを知りましたが、
ClojureではほぼREPLで開発するといっても過言じゃないぐらい重要かなと思います。

サービスとしてはEditorの横にConsoleがあり実行結果が出力されます。
Consoleの場所はShellに変更でき、
ほとんどサーバを実行するような感覚で利用できるようです。
そのため、言語の制限がなく、javaやNode.js,R,C++などなんでも試せるようでした。
今回の比較サービスの中では、
他のサービスに利用したい言語がない場合repl.itと言えるかもしれません。

試しにClojureで実行してみましが、
実行までが（初回のインストールを除いたとしても）遅いのが気になりました。
vite.js等も試してみましたが、
Console部分が二分割されてブラウザ出力も確認することができましたので、
それらは通常通り使えそうな印象でした。
一方でフロントエンド環境のためだったら、もっと抽象化された他のサービスでよさそうです。

言語制限がない場合の選択肢としてのサービスとみた場合、
実行の遅さを取るか、言語の実行環境をローカルに構築するか悩ましい感じを受けました。

## codesandbox

https://codesandbox.io

フロントエンド技術特化のIDE(デプロイまでできるという意味でIDEと言っています)サービスに見えました。
フロントエンドに特化している分、
今回の見たサービスの中では一番良く抽象化できているサービスと感じました。

内部はvscodeベースのようですが、
そのままvscodeと同じにはせず必要な部分のみを出しているようなUIです。
例えば一番右側は出力部分で、Browserの結果が確認できますが、
Testsというタブでテストの出力結果も確認できるといった構成となっていました。
UIは全体的に綺麗で利用する上で迷う部分がありませんでした。

ayu darkが個人的に好きなのですが、
custom themeを設定することでテーマの変更も簡単にできました。
https://github.com/ayu-theme/vscode-ayu

DeploymentではVercel,Netlify,Github Pagesと連携できるので、
ある程度の規模であればこれ一つで完結するプロジェクトも多そうな印象です。

## stackblitz

https://stackblitz.com

こちらもフロントエンド技術特化のIDEサービスのようです。

vscodeベースで作られている一方で、
テンプレートから読み込んだ後必要な操作がわからないことが多かったです。
例えば、React Tsテンプレート読み込み後最初からコードにエラーが出ている箇所があり、
エラー箇所の修正のためtsconfigをいじろうとしてもtsconfigがなかったりしました。
他にも新規packageの入れ方がわからず、
そもそも今回の技術の学習という意味ではその技術が利用されたテンプレートがないと学習できないのかもしれません。

Firebaseとの連携が最初からできるようで、
Firebaseを利用したい場合は選択肢になるかもしれません。

無料枠でできることが少ない可能性もありますが、
個人的にはUI共に優れたcodesandboxの利用で十分に感じました。

## codepen

https://codepen.io

フロントエンド技術特化のサービスです。
ただし用途としてはブラウザの結果を試すことだけに特化していて、
HTML,CSS,JSの入力部とブラウザの結果の4つに別れています。

このエディターでゴリゴリコードを書くのは難しい印象なので、
どちらかというと決まったコードをシェアすることがメインの用途となりそうです。

シェアされたものはログイン等不要で参照でき、
コードもその場で変更できる点は他のサービスと異なる点と言えそうです。
MDNのCSS関連ドキュメントにはよくcodepenで貼ってある印象ですが、
これはログイン不要な使いやすさに起因しているのかもしれません。

# 最後に

技術を学ぶことを念頭に比較してみました。
ざっくりまとめると、
CSSの学習だったらcodepenで十分だったり、
design systemのフレームワークだったらcodesandboxのテンプレートを利用したり、
言語の制限がないrepl.itを利用することができそうです。

皆さんの学習の効率化につながればと思います。
pytest-mockでspy

モック対象の振る舞いはそのままで、呼び出し回数や引数、返り値のみをテストで確認したい場合に、spyが使える。

# TL;DR

今回は、自作のクラスのメソッドがテスト対象だったので、下記のようにspy。

第1引数にオブジェクト、第2引数にメソッド名の文字列リテラル。返り値は、spyのMockオブジェクト。

https://github.com/pytest-dev/pytest-mock/blob/main/src/pytest_mock/plugin.py

```python
spy = mocker.spy(app.Hoge, 'bar')
```

実装コード

```python
def spy(self, obj: object, name: str) -> unittest.mock.MagicMock:
        """
        Create a spy of method. It will run method normally, but it is now
        possible to use `mock` call features with it, like call count.
        :param obj: An object.
        :param name: A method in object.
        :return: Spy object.
        """
```

# その他メモ

MockerFixtureを使うと、mocker経由で生成したmockなどは、サジェストが有効になるのでちょっと便利。

```python
from pytest_mock import MockerFixture
```

また最初は、Mock(wraps=)のwrapsオプションでspyのようなことを考えていましたが、spyメソッドを見つけたので、シンプルになりました！spyの実装では、wrapsを活用しているじゃないかと推測してます。下記、実装の一部抜粋。

```python
if asyncio.iscoroutinefunction(method):
            wrapped = functools.update_wrapper(async_wrapper, method)
        else:
            wrapped = functools.update_wrapper(wrapper, method)

        spy_obj = self.patch.object(obj, name, side_effect=wrapped, autospec=autospec)
        spy_obj.spy_return = None
        spy_obj.spy_exception = None
        return spy_obj
```

# 検証したコード

```python
import pytest
from pytest_mock import MockerFixture

import app

def test_app_spy(mocker: MockerFixture):
    spy = mocker.spy(app.Hoge, 'bar')
    app.main()

    assert spy.call_count == 1
    # assert spy.call_count == 2
    spy.assert_called_once()
    spy.assert_called_once_with(1, 2, 3)
    assert spy.spy_return == 1 + 2 + 3
    # assert spy.spy_return == 1 + 2 + 4
```

# 参考

[https://github.com/pytest-dev/pytest-mock#:~:text=not currently tested.-,Spy,-The mocker.spy](https://github.com/pytest-dev/pytest-mock#:~:text=not%20currently%20tested.-,Spy,-The%20mocker.spy)
Reactの基本（メモ用）

Reactチュートリアルを学習したので、備忘録として記事を作ります。
誤った解釈をしているかもしれません。その時は適宜修正していきます。

## Reactとは？
>React はユーザインターフェイスを構築するための、宣言型で効率的で柔軟な JavaScript ライブラリ。複雑なUIを「コンポーネント」と呼ばれる小さく独立した部品から組み立てることができる。

## renderメソッド
画面上に表示したいものの説明書き
```React
class ShoppingList extends React.Component {
  render() {
    return (
      <p>hoge</p>
    );
  }
}
```

## props
親コンポーネントから子コンポーネントにpropを渡す。
子コンポーネントは、親コンポーネントの中身を
```React
{this.props.hoge}
```
という形で呼び出すだけで良い。
この方法でアプリ内を情報が流れていく。

## stateとsetState
再レンダーするために必要。
```React
class Square extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: null, //初期値を設定
    };
  }

  render() {
    return (
      <button
        className="square"
        onClick={() => this.setState({value: 'X'})} //再描写によりstateの値が変更
      >
        {this.state.value} //再描写後の値が表示（「X」が表示される）
      </button>
    );
  }
}
```

まだまだ未知なことが多いですが、これからもアウトプットを通して理解を深めていきます！
pecoを用いたコマンド履歴出す機能を作るときに調査したことまとめ

# 本記事について

[pecoを使って少しでも仕事を早くする](https://qiita.com/otama/items/b6e31208751d88b44f77)
[pecoを使って端末操作を爆速にする](https://qiita.com/reireias/items/fd96d67ccf1fdffb24ed)

を見て、どうしてこの書き方なのかっていうのを調べた。

# 結果

```.zshrc
alias tac='tail -r'
alias distinct='awk '\''!a[$0]++'\'

# peco
function peco-select-history() {
    BUFFER=`history -n 1 | tac | distinct | peco`
    CURSOR=${#BUFFER}
    zle reset-prompt
}

zle -N peco-select-history
bindkey '^r' peco-select-history
```

こうなった。

# 調査メモ

### ショートカットからコマンド呼び出す。

zshの機能
https://qiita.com/yuku_t/items/e58cbecf13407446bd50

### zleって何？
Zsh Line Editor
https://dev.classmethod.jp/articles/zsh-zle-introduction/

### history コマンド
https://timesaving.hatenablog.com/entry/2020/12/05/210000#zsh-%E3%81%A7%E3%81%AE%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%81%AE%E5%85%A5%E5%8A%9B%E5%B1%A5%E6%AD%B4

### fc コマンド
https://atmarkit.itmedia.co.jp/ait/articles/1912/05/news042.html

つまり

history
=> fc -l
=> 履歴を16件表示するコマンド
履歴には番号がついている

オプション
n: 番号を表示しない
数字: この数字以降の番号の履歴を表示。つまり、1なら全部

### tac コマンド

入力を逆順で表示する
https://hydrocul.github.io/wiki/commands/tac.html
これで最新が上に来るようになる。
catを逆にしてるからtacって名前

macにはデフォルトで入ってない。

### tail -r
https://hydrocul.github.io/wiki/commands/tail.html
https://xtech.nikkei.com/it/atcl/column/15/042000103/080400023/

macでtacしたい場合

じゃあどうする？

選択肢
whichでtacかtail -rか分岐
macでtacを使えるようにする
tail -r を使う

tail -r よりもtacのほうが直感的なので2番目で

```.zshrc
alias tac='tail -r'
```

### awkで重複削除

awkで重複削除
https://qiita.com/pocket8137/items/a6de22d0be6b26f7bcac

uniqだとsortが必要になるのでだめ。
=> わかりづらいので名前変えたい
distinctでよいのでは

変数展開を行わないようにしないといけない
https://qiita.com/y518gaku/items/35870f379bc4b0b85f72#%E3%82%AF%E3%82%A6%E3%82%A9%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0


https://www.softel.co.jp/blogs/tech/archives/5623

```.zshrc
alias distinct='awk '\''!a[$0]++'\'
```

### zle BUFFERとCURSOL
https://dev.classmethod.jp/articles/zsh-zle-introduction/
これ読めばわかる

### ${#BUFFER}
文字列の長さ
http://dhythm.blog11.fc2.com/blog-entry-156.html

### shellにおけるバッククォート
shell バッククォート
https://uxmilk.jp/27649

### reset-promptとかの意味

いろいろ書いてある
https://qiita.com/b4b4r07/items/8db0257d2e6f6b19ecb9

結局なんでやってるのかわからなかったので以下で検証した

```
何もなし
redisplay
clear-screen
reset-prompt
```

```
何もなし => 表示される(これでいいのでは？)
redisplay => 表示される(違いわからない)
clear-screen => 端末のリセットされて表示される。これは嫌
reset-prompt => 表示される(違いわからない)
```

とりあえずキーバインドの記事でも元記事でもreset-prompt使ってたし、reset-prompt使うことにした。
クリーンアーキテクチャなんもわからんからサンプルを実装してみた

# この記事について

クリーンアーキテクチャについて本(Clean Architecture 達人に学ぶソフトウェアの構造と設計)を読んだのですが、本を読むだけだと実感が湧かない部分がありました。
そういうときは実践してみるに限る！ということで自分でサンプルを実装してみました。
私は組み込み系の開発者なので、デバイス制御するWindowsアプリケーション(C#)を作ってみました。

# 実装の対象

サンプルとして、外部(テストツール)からTCP/IPでコマンドを受け取って、仮想デバイスを制御するようなWindowsアプリケーションを作成しました。
持っている機能としてはこんな感じです。

- モーター移動コマンドを受け取ったら指定された分だけモーターを動かし、これまでの合計移動距離を画面に表示する
- センサー読み取りコマンドを受け取ったらセンサーの値を拾って画面に表示する

※実デバイス制御は行いません。デバイスを繋いでデバイスドライバを書けば実デバイス動作できるだろう、程度の粒度まで実装をしています。
このサンプルを、クリーンアーキテクチャで実装したバージョンとそうでないバージョンを、それぞれ実装しました。

# 単純に実装した場合

ソースコードは https://github.com/nendo-code/DeviceCommandApp です。

クラス構成としては下記のような感じです。
![notca.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211743/51fe2767-e2c5-14cb-b431-76b9e929f190.png)

このバージョンは、実装は非常にシンプルです。小規模なツールをサクッと作るならこれもありだと思います。
しかし各クラスが密結合なので単体テストの書くのがしんどいです。Singletonで直接呼び出したりしています。
今回の例は特に通信プログラムなので、単体テスト時は通信部分やデバイスドライバ部分をスタブ化したいところですが、それができないのが痛いです。
テストする場合は結合しての手動テストがメインになるでしょう。

# クリーンアーキテクチャ的な実装の場合

ソースコードは https://github.com/nendo-code/DeviceCommandApp_CA です。

クラス構成としては下記のような感じです。
![ca.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211743/003f7d14-6a28-2a50-85c5-3f08cc95e6ba.png)
※データベースは今回使用していないのでDBDriverは実装していません。

何かの冗談かと思うくらい複雑になりましたね。
フォルダ名などは超有名な↓の図に合わせて構成しました。ソースコードと対比をとると理解しやすいかと思います。
![CleanArchitecture.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211743/7d6453b6-fa6f-ed43-2d91-0de146a4892e.jpeg)

この構成のポイントとしては下位のレイヤのクラスは上位レイヤの実装に依存していないという点です。
上位レイヤを使う時は必ずInterfaceを使っています。
こうすることでテスト用のMockに差し替えるのが容易になり、単体テストがしやすくなります。

構成はかなり複雑ですが、各クラス内の実装内容自体はシンプルです。
また、各クラスが疎結合になっているので単体テストは非常にやりやすくなっています。

最初のバージョンを構築するまでには時間がかかりますが、一度できてしまえばその後の拡張はしやすそうだな、というのが感想です。
システムの規模が大きくなっても修正による影響範囲が少なくてすみそうなのが大きいです。
実際のプロジェクトで実装するときは、プロジェクトの都合に合わせてフォルダの名前や構成は変えるのがよいかと思います。
(私が実際のプロジェクトで実装しているときはもっと簡略化しています。)

# 理解したこと
本を読み、また実際に実装してみて思ったのは、
クリーンアーキテクチャは新しくもなければ特別な技術でもないということです。

本質としては、
・システムをレイヤーに分割し、レイヤーごとに何を関心事にするかを決める
・下位レイヤーは上位レイヤーの「実装」に依存しない。インターフェースにのみ依存する。（境界を設ける）
を守りましょうね、という事に集約できます。

これは設計の基本であり、昔から行われているソフトウェア設計と大きく変わりはありません。
その基本に従い、整理したアーキテクチャの一例として提示されたのがクリーンアーキテクチャなのだと思います。

「Clean Architecture 達人に学ぶソフトウェアの構造と設計」はこうしたソフトウェア設計の基本やオブジェクト指向の原理原則についてまとめて理解できる良書なので、
まだの方はぜひ読むことをお勧めします！

# 参考文献

- [Clean Architecture 達人に学ぶソフトウェアの構造と設計](https://www.amazon.co.jp/dp/B07FSBHS2V/)
- [実装クリーンアーキテクチャ](https://qiita.com/nrslib/items/a5f902c4defc83bd46b8)