OmniAICreator/Qiita-1.07M huggingface dataset:
【プリンシプルオブプログラミング】 第2章（2.1~2.7）「原則」要点抜粋

この記事は「プリンシプルオブプログラミング」という書籍の、特に重要だと感じた部分を紹介します。この書籍は全部で7章あります。1記事につき1章（項目が多い章は分割）を取り上げていき、今回は第2章の部分です。
### 第2章 「原則」 〜プログラミングのガイドライン〜
> 「われわれ自身を制御することをなさしめないで、われわれの精神を解放するものはすべて危険である。」
ヨハン・ヴォルフガング・フォン・ゲーテ
# 2.1 KISS（Keep It Simple, Stupid）
- シンプルなコードは「読みやすい」「理解しやすい」「修正が容易」「テストがしやすい」「コミュニケーションコストを節約できる」のメリットがある
- 「動作させるために、もっともシンプルなものは何か」と常に自問する
- 「今書いているコードは本当に必要なものか？」と常に自問する
- コードに余計なことをしない
###### 余計なこと
1. 新しく覚えた技術を使いたいがために不要にトリッキーなコードを書く
2. 将来の必要に備えたコードを書く（今不要なら書くべきではない）
3. 勝手に要件を加える（要件を決めるのはユーザーであり、プログラマが要件を決めてはいけない）
###### 関連
- 「less is more（より少ないことは、より豊かなこと）」
- 「オッカムの剃刀」
# 2.2 DRY（Don't Repeat Yourself）
- 繰り返さない、重複して書かない
- ひとまとまりのロジックをコピペしない
- コードをそのまま説明しているコメントは不要
###### 重複による弊害
1. コードを読む量が増え、さらに複雑になる
2. コードを修正する箇所が増え、さらに修正漏れの危険が出る
3. レガシーコードとなり、テストがない
###### コードの抽象化により、重複を排除する
- コードのロジックを抽象化するには処理のまとまりに名前を付けて、「関数化」「モジュール化」する
###### コードの抽象化することのメリット
1. コードの量が減り、読む量が減る
2. ロジックやデータに名前が付き、コードが読みやすい
3. 同じコードが1箇所に集約され、修正箇所が1箇所で済む　-> 修正しやすく、品質が担保しやすい
4. 再利用しやすくなり、機能追加の際、より速く、より品質よくできる
###### 関連
- 「WET（Write Every Time）」同じことを繰り返す
- 「One Fact in One Plade」1つの場所には1つの事実
- 「Once and Only Once」一度だけ、たった1度だけ
- 「レガシーコード」テストがないコードのこと
# 2.3 YAGNI（You Aren't Going to Need it）
- 本当に必要になったとき、必要なものだけを書く
# 2.4 PIE（Program Intently and Expessively）
- 意図を明確に表現するようにコードを書く
- 「書きやすさ」より「読みやすさ」を重視（コードは書くより読む機会の方がずっと多い）
- コードは「What」と「How」しか表現できないので、コメントで「Why」を書く
- 意図を表す究極の形は「文芸的プログラミング」手法
# 2.5 SLAP（Single Level of Abstraction Principle）
- 抽象化レベルの統一（コードのレベルを合わせる）
- 「具体的な処理を書く作業」と「抽象化レベルを揃える作業」を分ける
###### 書籍とコードのアナロジー
- 序文：コメント
- 目次：関数の一覧
- セクション：複数のモジュールのグループ
- 　章：関数
- 　段落：関数内のコードブロック
- 　文：1つ1つのステートメント
- 　相互参照・索引：エディタのジャンプ機能や検索機能
# 2.6 OCP（Open-Closed Principle）
- コードは 「拡張に対して開いている」「修正に対して閉じている」の両方を満たす設計にする
- 変更に対して柔軟に対応できる「柔らかい」設計にする
# 2.7 名前重要
- 「適切な名前が付けられる」=「その要素が正しく理解され、正しく設計されている」
- 適切な名前は意図が伝わる
- コードを書く前に名前（≒短いコメント）を決める
- 名前は「手段」と「目的」を説明し、「手段」は言及しない
- 「規約」や「問題領域」から外れた用語を使用しない -> メンタルマッピング回避
- 説明文から考えた名前から、元の説明文を推測できるかチェックする -> ループバックチェック
Scalaの勉強はじめました 3 〜オブジェクトとクラス①〜

## はじめに
N予備校の「Scala基礎」コースを受講しています。
今回は、オブジェクトとクラスについてです。

## クラス

:::note
複数のオブジェクトを作るための雛形のようなもの
:::

```scala
class Cat(name: String) {
  def greet(): Unit = println(s"吾輩は${name}である")
}
val cat = new Cat("ねこ")
cat.greet()
```
`name`がフィールド、`greet`がメソッド。

:::note
クラスの中でしか使わないメソッドやクラスの中だけでしかアクセスさせたくないフィールドには、`private`というアクセス修飾子をつける。
:::

### 抽象クラス
継承を使うことを前提に作られたクラスのこと。
インスタンス化はできない。`abstract`をつける。

```scala
abstract class Creature(var name: String) {
  def isAlive(): Boolean = true
}

class Human(_name: String) extends Creature(_name) 
```

## オブジェクト
```scala
object MyApplication extends App {
  println("Hello!")
}
```
:::note
`object`キーワードで宣言されるオブジェクトは、現JVMの実行環境でたった一つだけの`MyApplication`型のオブジェクト。
:::

シングルトンオブジェクトという。

## ファクトリメソッド
:::note
クラスのインスタンスを生成するメソッドのこと
Scala のオブジェクトの中で、 `apply`というメソッドを定義すると、そのメソッドは特別扱いされ、オブジェクト名(`apply`メソッドの引数) の形式で呼び出すことが可能となる
:::

```scala
class Cat(private val name: String) {
  def greet(): Unit = println(s"吾輩は${name}である")
}
object Cat {
  def apply(name: String) = new Cat(name)
  def apply(id: Int) = new Dog(s"ねこID:${id}")
  def printName(cat: Cat): Unit = println(cat.name)
}
```

クラスと同名のオブジェクトを「コンパニオンオブジェクト」という。
同名クラスのプライベートメンバーにもアクセスできる。

```scala
val taro = new Cat("太郎")
Cat.printName(taro)
```

## ケースクラス
```scala
class Point(val x: Int, val y: Int) {
  override def toString = s"Point($x, $y)"
}
object Point {
  def apply(x: Int, y: Int): Point = new Point(x, y)
}
```

これが、

```scala
case class CPoint(x: Int, y: Int)
```

となる。
メンバーフィールドの公開や、`new`の代わりとなるファクトリメソッドなどを自動的に用意してくれる。

## sealed
:::note
Scalaで宣言されたファイルの中でしか利用できないクラス
:::

パターンマッチの際に、継承されたクラスから漏れがあると警告を出してくれる。(コンパイル時に警告をイベントログに出力)
ケースクラスと併用して列挙型のように使う。

```scala
sealed abstract class Animal
case class Cat(name: String, age: Int) extends Animal
case class Dog(name: String, age: Int) extends Animal
case class Bird(name: String, age: Int) extends Animal

object Animal {
 def introduce(animal: Animal): String = {
    animal match {
      case Cat(name, age) => s"ねこのなまえは${name}、${age}さいです"
      case Dog(name, age) => s"いぬのなまえは${name}、${age}さいです"
      case Bird(name, age) => s"とりのなまえは${name}、${age}さいです"  
    }
  }
}
```

呼び出しは、

```scala
Animal.introduce(Dog("小次郎", 3))
```

## まとめ
オブジェクト指向、雰囲気は大体わかるんですが、実際に抽象クラスだったりどう使い分けていくのか、頭の中がまだ整理できてません。
なんか実際に作らないとわからないかも。
クラス設計ってどうやってやる？どんなこと考えるべき？

# なぜ「クラス設計」について学習したいと思ったか？
## 理由１：「クラス設計」が適切に行われていないと、可読性が低くなると思ったから
１つのクラスに多くの処理（メソッド）が含まれていると、クラスが肥大化してしまい、処理を追うのが難しくなる。
（※というか、読む気が起きなくなってしまう...）

## 理由２：「クラス設計」が適切に行われていると、処理の流れがわかりやすくなるから
それに引き換え「クラス設計」がちゃんと行われているソースは、
各クラスやメソッドが非常に簡潔に実装されているため、処理全体の流れがわかりやすい。
（「データ取得」してから「加工」して「登録」、みたいな流れが一目でわかる）

# オブジェクト指向の機能
## 「継承」
「親クラス（抽象クラス／スーパークラス）」　＞ 「子クラス（具象クラス／サブクラス）」という関係を作ることができる。
複数のクラスで記述されていた「共通処理」を親クラスにまとめられるため、「**コードの再利用**」ができる

## 「インターフェース」
「このクラスは、こういうメソッドを持つ」ということを定義した、「規格」のようなもの。

```:ex)「動画・再生ソフト」だったらこんな規格（メソッド）を持つインターフェースになる
・再生
・停止
・一時停止
・早送り
・早戻し
```

インターフェースを実装するクラスは、インターフェースに定義されているメソッドが必ず含まれていないといけない（「**メソッドの実装強制**」）。
これにより、新しくクラスを追加する際にも、「あまりにも現在存在するプログラムとかけ離れたクラス」になることを防ぐことができる。

インターフェース自体には「処理」は実装されていない。
そのため、インターフェースの役割は「**振る舞いを共通化**」すること。

# クラス設計のやり方（個人の見解）
## 1.インターフェースを作成する
「どういう振る舞いが必要か」という、一番大きな視点からインターフェースを設計する。

## 2.インターフェースを実装するクラスを作成する
まずはこの時点で「継承」とかを考えない。

## 3.共通化できる処理があれば、抽象クラスを作成する
共通処理を抽象クラスに持たせて「コードの再利用」を行うことで、コード量を減らすことができる。

## 「継承は、『共通の機能があるからやる』のではなくて、根本は『同じものだからやる』」
いつだったか会社の同僚にこんなコメントをいただいたことがあり、今でもよく覚えている。（非常に勉強になったので）
「継承」が適切に行われていないクラス設計のプログラムで、「共通しているから抽象クラスに持たせよー」とかやっていると、「抽象クラスが肥大化」してしまう。
今回記述した、「インターフェースから実装した上で、共通処理を抽象クラスに持たせる」という手法であれば、この考え方は取り入れられているのでは、と思う。

# 考え方／原則
## 単一責任原則
「変更する理由が同じものは集める、変更する理由が違うものは分ける。」
出来るだけ「１つのクラスに役割を持たせすぎない」ように...
[単一責任原則　｜ プログラマが知るべき９７のこと](https://xn--97-273ae6a4irb6e2hsoiozc2g4b8082p.com/%E3%82%A8%E3%83%83%E3%82%BB%E3%82%A4/%E5%8D%98%E4%B8%80%E8%B2%AC%E4%BB%BB%E5%8E%9F%E5%89%87/)

# 参考URL
[どのようにしてクラス設計を行うのか？クラス設計の考え方とコツ](https://www.deep-rain.com/programming/java/717)
[継承によってコードを再利用する](https://www.gixo.jp/blog/5016/)
[インターフェースとは？～継承とは役割が違う～](https://www.gixo.jp/blog/5159/)
MariaDB：不正日付でより大きい検索したら全件となります 

既知の内容かもしれませんが、MariaDBを使用していてつまづいた部分になります。
使用していたMariaDBのバージョンは10.3.27なのでバージョンよって動きが違うかも
しれません。

# 日付型の項目に不正日付でより大きい検索
日付型の項目の検索で、日付と認識されない文字でより大きい検索を行うと全件検索となる。

サンプル例
```
MariaDB [test]> desc test_info;
+-------------+-------------+------+-----+---------+-------+
| Field       | Type        | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+-------+
| test_id     | varchar(20) | NO   |     | NULL    |       |
| create_date | date        | NO   |     | NULL    |       |
+-------------+-------------+------+-----+---------+-------+
2 rows in set (0.006 sec)

MariaDB [test]> select * from test_info;
+----------+-------------+
| test_id  | create_date |
+----------+-------------+
| A0000001 | 2020-12-01  |
| A0000002 | 2021-01-01  |
| A0000003 | 2021-09-01  |
+----------+-------------+
3 rows in set (0.000 sec)

```
日付でない文字、例えばAAAAでより大きい検索を実施する。

```
MariaDB [test]> select * from test_info where create_date > 'AAAA';
+----------+-------------+
| test_id  | create_date |
+----------+-------------+
| A0000001 | 2020-12-01  |
| A0000002 | 2021-01-01  |
| A0000003 | 2021-09-01  |
+----------+-------------+
3 rows in set, 1 warning (0.000 sec)

```
こんな検索はしないとは思いますますが、sqlの実行する前に検索文字について日付型チェックをしていなかったことで想定していない結果（全件出力）となってました。またwarningが出力されるので内容の確認をすると以下の内容が確認できます。
```
MariaDB [test]> SHOW WARNINGS ;
+---------+------+----------------------------------+
| Level   | Code | Message                          |
+---------+------+----------------------------------+
| Warning | 1292 | Incorrect datetime value: 'AAAA' |
+---------+------+----------------------------------+
1 row in set (0.001 sec)

```

ちなみに日付としては正しくなくても、このような場合は０件で結果が返ります。
```
MariaDB [test]> select * from test_info where create_date > '2022-02-31';
Empty set (0.000 sec)

```

日付型項目の検索する場合は、日付の型チェックが必須だと思います。
## 【2022年版】 Raspberry Pi Zero(WH) のセットアップ

![Zero.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452335/4be4f76d-f2b9-7f75-abf3-c5b76991a00f.jpeg)

モニタ、キーボード、ACアダプタが不要で、wifi設定が必要なく、USBケーブル1本でセットアップする方法です。
Raspberry Pi Zero 2 W でも、有効と思いますが、まだ、入手できていません。

## 必要なもの
- Rsspberry Pi Zero WH
- microSDカード
- USBケーブル

## Raspberry Pi OS Lite (2022年3月26日時点の最新版)
Release date: January 28th 2022
System: 32-bit
Kernel version: 5.10
Debian version: 11 (bullseye)
Size: 482MB
Raspberry Pi公式ダウンロードページから、OSのイメージファイルをダウンロードします。
https://downloads.raspberrypi.org/raspios_lite_armhf/images/raspios_lite_armhf-2022-01-28/2022-01-28-raspios-bullseye-armhf-lite.zip

## イメージファイルの書き込み
Raspberry Pi公式のイメージ書き込みツール（Raspberry Pi Imager）のMac版を使いました。
https://downloads.raspberrypi.org/imager/imager_latest.dmg

## Macのターミナル操作
microSDをリーダーに差します。
Macのターミナルを起動します。
ssh接続を有効にして、USB-OTGのネットワーク接続するコマンドを入力します。
※No such file or directoryと表示される場合は、microSDカードが認識していません。
```bash
touch /Volumes/boot/ssh
echo "dtoverlay=dwc2" >> /Volumes/boot/config.txt
sed -i -e '1s/rootwait/rootwait modules-load=dwc2,g_ether/' /Volumes/boot/cmdline.txt
```
FinderからmicroSDカードを取り出します。

## Raspberry Pi OSの起動
microSDをRaspberry Pi Zero本体へ差し込みます。
USBケーブルをUSB端子に差し込みます。
※PWR(電源)の接続は不要です。

## ssh接続
USBケーブルをMacに差し込みます。
緑のLEDがチカチカするので、しばらく待ちます。
```bash
ssh pi@raspberrypi.local
```
※初期パスワードは raspberry です。
※ログイン後にパスワードを必ず変更してください。

## トラブルシューティング
1. ssh接続できない。
Macの共有設定のインターネット共有を確認します。
![internet.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452335/0c3bb9ec-cce8-475c-6b4a-0080182ab978.jpeg)

2. イメージファイルを書き換えた場合など、警告表示でssh接続できないことがあります。
その時は、.ssh/known_hosts ファイルの raspberrypi.localが含まれる行を削除します。

```
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@       WARNING: POSSIBLE DNS SPOOFING DETECTED!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
The ECDSA host key for raspberrypi.local has changed,
and the key for the corresponding IP address 
is unknown. This could either mean that
DNS SPOOFING is happening or the IP address for the host
and its host key have changed at the same time.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
SHA256:xxxxxxxxxxxxxxxxxxxxxxxx.
Please contact your system administrator.
Add correct host key in /Users/xxxx/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /Users/xxxx/.ssh/known_hosts:39
ECDSA host key for raspberrypi.local has changed and you have requested strict checking.
Host key verification failed.
```
ShiftJISファイル名が交じるガラケー時代のディレクトリ内のファイルの名前をUTF-8に一括変換

# 環境
- Amazon Linux
- ガラケー時代にFTPでアップロードされた名前がShiftJISでエンコードされたファイルが多数
- Amazon Linux では、 `sudo yum install convmv` は `No packages`となる

# 手順
1. `CentOS6 convmv` で RPMパッケージを検索
2. RPMをダウンロード
2. RPMからインストール `sudo yum install -y <ダウンロードしたRPM>.rpm`
2. `cd <ファイルを一括変換するルートディレクトリー>`
2. 変換のテスト `convmv -r -f cp932 -t utf-8 * ~/convmv.log`
2. 文字コードの想定があっているかチェック `less ~convmv.log`
2. 変換 `convmv --notest -r -f cp932 -t utf-8 * ~/convmv.log`
VirtualBoxで動いるUbuntu18.04でmultipassを使いdockerを使った件

dockerが条件によっては有料になるとネットで知ったこともあり、multipassのチュートリアルでdockerを見つけたので、試してみました。

https://multipass.run/docs/docker-tutorial

VirtualBoxのホストOSは、MacOSです。

```bash
multipass launch docker
```
で、dockerを準備しました。

![VirtualBox_Ubuntu0319_26_03_2022_13_53_55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20977/f6535e2f-ce58-d4f9-2b7c-7aeb2799511f.png)

チュートリアルを進めて、ghostのブログの表示ができました。
![VirtualBox_Ubuntu0319_26_03_2022_13_48_41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20977/cb11761d-0647-b291-9dcf-48d699a5249f.png)

Portainerの中に、WordPressやデータベース、nginxなどがあったので、直ぐに使えると思いました。
PythonのListの作成速度調査

# 始めに
最近AtCoderを始めたのですが、なかなか処理速度を考えて処理を書くまでには至らず、
書き方ごとの処理速度に関する当たりをつけるため、とりあえずよくあるリスト作成の速度を調査してみた。

## 検証するケース

1 - forループでinfをN個持ったリストを作成
```python
import time

def cal_for_inf(count):
  start = time.perf_counter()
  inf = float('inf')
  arr = [inf for i in range(count)]
  end = time.perf_counter()
  return end-start
```

2 - *でinfをN個持ったリストを作成
```python
def cal_multi_inf(count):
  start = time.perf_counter()
  inf = float('inf')
  arr = [inf] * count
  end = time.perf_counter()
  return end-start
```

3 - forループで0をN個持ったリストを作成
```python
def cal_for_zero(count):
  start = time.perf_counter()
  arr = [0 for i in range(count)]
  end = time.perf_counter()
  return end-start
```

4 - *でinfをN個持ったリストを作成
```python
def cal_multi_zero(count):
  start = time.perf_counter()
  arr = [0] * count
  end = time.perf_counter()
  return end-start
```

## 検証
検証したデータはpandasのDataFrameに入れて確認する

```python
import pandas as pd
count = 1000000 ## 作成するListの要素数
data = pd.DataFrame(
  [[
    cal_for_inf(count),
    cal_multi_inf(count),
    cal_for_zero(count),
    cal_multi_zero(count)
  ] for i in range(1,1001)],
  columns=["cal_for_inf","cal_multi_inf","cal_for_zero","cal_multi_zero"]
)
```

## 検証結果

```python
data.describe()
```

|  | cal_for_inf | cal_multi_inf | cal_for_zero | cal_multi_zero |
|:------|:-------:|:-------:|:-------:|:-------:| 
|count|	1000.000000	|1000.000000|	1000.000000|	1000.000000|
|mean|	0.029765|	0.003394|	0.029859|	0.003449|
|std	|0.002517	|0.001754|	0.002755	|0.001216|
|min|	0.024995	|0.002467|	0.025293|	0.002451|
|25%|	0.028420	|0.002672|	0.028401|	0.002722|
|50%|	0.029345|	0.002796|	0.029270|	0.002853|
|75%|	0.030675|	0.003115|	0.030712|	0.003177|
|max|	0.060927|	0.045249|	0.053833|	0.008475|

![スクリーンショット 2022-03-26 13.47.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328944/cc616465-c7c5-6dff-2490-44b4d0873336.png)

## 結論
中に入れるものが一定なのであれば*で入れたほうが早い。
アーキテクチャの必要性

# はじめに
アーキテクチャを導入した方がいいのかどうかについて、よく議論が交わされると思うので、1つの指標として記事にしました。

# 本文

マーチン・ファウラー先生の内部品質の影響を可視化したグラフが参考になりました。

https://bliki-ja.github.io/IsHighQualitySoftwareWorthTheCost/

このグラフでは、内部品質への投資に対する生産性のリターンが1か月以内に損益分岐点に達することを表しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309633/fbd2dbb7-88c3-191e-cc95-baaade7add47.png)

**大規模・小規模に関わらず、1か月以上続くサービスの開発を想定しているのであれば、なにかしらアーキテクチャを導入した方が良さそうに思います。**
[InnoDB]ネクストキーロックとは、あるいはSELECT FOR UPDATEの注意点

# スコープ
MySQL / InnoDB

# ネクストキーロックとは

例えば、以下のコマンドを実行すると、100以上のidを挿入・更新できなくなりそうだが、そうとは限らない。

```sql
SELECT id FROM tbl_name WHERE id > 99 FOR UPDATE;
```

理解するヒントは、InnoDBは、式にロックを掛けるのではなく、「行」と「ギャップ」にロックを掛けるという点にある。

「行」とは実際にテーブルに保存されている行のことである。「ギャップ」とは、行と行の間を表す空間である。

実際のInoDBの挙動としては、「SELECTした行」と「その行の前後のギャップ」にロックを掛けるのである（行ロック・ギャップロック）。行ロックとギャップロックを合わせて「ネクストキーロック」という。以下具体例を使って説明する。

## 具体例

テーブルに以下のデータが入っているケースを考える。

```
+------------+
| id         |
+------------+
| 105        |
| 95         |
+------------+
```

このケースで冒頭のクエリを実行した場合、ロックが掛かる範囲は以下の通りである。
 - `id=105` の行
 - `id=105` の行の前後のギャップ、すなわち
     - `id=95 ~ 105` のギャップ
     - `id=105 ~ inf` のギャップ、すなわち id=105 より大きい全ての空間

よって、 `id=105` の行は更新できないし、 `id=106` の挿入もできない。が、それに加えて、 `id=96` のような値も挿入できなくなる。 

冒頭の式の挙動の回答としては、具体的にどのような値の挿入がロックされるかは、テーブルのレコードによる、ということになる。式では `WHERE id > 99` と指定しているが、それより小さい値を挿入できなくなることもあるということである。

これがネクストキーロックというものの特性である。

# 補足情報

 - id=95の行にはロックがかからないので、この行を更新することはできる
 - ネクストキーロックが掛かる条件については公式情報を参照してもらうのがよいが、ざっくり言うと、一意の行を指定してロックを掛ける場合を除き全てのクエリで掛かる
    - 例えば上記の例の場合、 `WHERE id=105` で指定するとネクストキーロックは掛からず、id=105の行のみにロックが掛かる
    - 一方、 `WHERE id=99` で指定すると、 `id=95~105` の間にギャップロックがかかり、例えば `id=100` などを挿入できなくなる
 - トランザクション分離レベルを READ COMMITTED に変更すると、ネクストキーロックは無効になる
    - ネクストキーロックは、トランザクション分離レベルに密接した概念であり、REPEATABLE READ(InnoDBのデフォルト)では防げないファントムリードを防ぐためにある。
 - 以上のルールは、SELECT FOR UPDATEだけでなく、トランザクション中で実行したUPDATE, DELETE文でも同様である

# 資料

 - https://dev.mysql.com/doc/refman/5.6/ja/innodb-record-level-locks.html
 - https://dev.mysql.com/doc/refman/5.6/ja/innodb-next-key-locking.html
 - https://dev.mysql.com/doc/refman/5.6/ja/innodb-locks-set.html
fontawesome の アイコンを円の線で囲む

この方法なら文字も囲める。

参考
https://codepen.io/noixip/pen/mWYeBa


リンクあり

```hoge.css
<style>
.maru {
    display: inline-flex;
    justify-content: center;
    align-items: center;
    border-radius: 50%;
    flex-flow: column;
    vertical-align: top;
    font-size: 24px;
    color:#ea3f60 !important;
}
/* 円の大きさ */
.heart{
    width: 50px;
    height: 50px;
    color: #ea3f60;
    border: 2px solid #ea3f60;
    background-color: #fff;
}
</style>
```

今回はリンクボタンにしたいので、以下にする。

```hoge.html

//一般
<a class="maru heart">
<i class="far fa-heart"></i>
</a>

//vue.js
<router-link :to="{ path: '/login'}" class="maru heart">
<i class="far fa-heart"></i>
</router-link>

```
[Laravel]assertExactJsonが勝手にsortしちゃう...

## TL;DR

- コレクション渡したときに自動でキーを昇順でsortするため、実際にAPIで用意した順番通りにならない
- 配列値に渡したときにassertExactJson使った際の取得値が配列に置き換えられている

## Controllers

```php
    return response()->json([
        'success' => true,
        'orders' => $orders->map(function ($order) {
            return [
                'uuid' => $order->uuid,
                'name' => $order->name,
                'phone_number' => $order->phone_number,
                'updated_at' => $order->updated_at->format('Y-m-d H:i:s.u'),
            ];
        }),
    ]);
```

uuid, name, ...の順が想定値

## ControllerTest.php

```php
$response = $this->actingAs($user)->getJson(route('api.orders.index'));

$response->assertExactJson([
    'success' => true,
    'orders' => $orders->map(function ($order) {
        return [
            'uuid' => $order->uuid,
            'name' => $order->name,
            'phone_number' => $order->phone_number,
            'updated_at' => $order->updated_at->format('Y-m-d H:i:s.u'),
        ];
    });
]);
```

## テスト結果

```php
--- Expected
+++ Actual
@@ @@
// APIで渡している内容
-'{"success":true,"orders":[{"uuid":"a6ba578e-8a5c-4a50-8f49-ba21bb53c6d2","name":"\u8061\u592a\u90ce","phone_number":"\u8061\u592a\u90ce",updated_at":"2022-03-11 10:36:07.416040"}]}'
// 勝手にABC順でソートされている
+'{"success":true,"orders":[{"name":"\u8061\u592a\u90ce","phone_number":"\u8061\u592a\u90ce", updated_at":"2022-03-11 10:36:07.416040","uuid":"a6ba578e-8a5c-4a50-8f49-ba21bb53c6d2"}]}'
```

テストでget送信して取得した内容がbuildingから始まっている

　→勝手にソートしている

## 対策

テスト時に配列を渡すようにする

```php
$response->assertExactJson([
    'success' => true,
    'orders' => $orders->map(function ($order) {
        return [
            'uuid' => $order->uuid,
            'name' => $order->name,
            'phone_number' => $order->phone_number,
            'updated_at' => $order->updated_at->format('Y-m-d H:i:s.u'),
        ];
    });
		->toArray();
]);
```

これもassertExactJsonの仕様だが、**配列を渡すと想定値も配列に変換され、コレクションの様にソートされない**ので、配列を使う

## テスト結果

しっかりテスト通る
UDPヘッダ

送信元ポート番号・・・16bit アプリケーションを指定する番号
TCPとの違いは送信元ポート番号がオプションになっている
返事をがいらない通信の場合は送信元ポート番号を全部０として通信することも可能

宛先ポート番号・・・16bit アプリケーションを指定する番号

パケット長・・・UDPヘッダ＋UDPデータ(ペイロード)の合計値　(byte単位)　パケットの長さ

チェックサム・・・16byte ヘッダとデータが壊れていないか確認する為のデータ
※TCP、UDP共にチェックサムがあるので注意　　　
UDPにはチェックサムが無いという引っ掛け問題がある

データ(ペイロード)・・・データ本体
【プリンシプルオブプログラミング】 第1章（1.1~1.3）「前提」要点抜粋

この記事は「プリンシプルオブプログラミング」という書籍の、特に重要だと感じた部分を紹介します。この書籍は全部で7章あります。1記事につき1章（項目が多い章は分割）を取り上げていき、今回は第1章の部分です。

### 第1章 「前提」 〜プログラミングの変わらぬ真実〜

> 「どの港へ向かうのかを知らぬ者にとっては、いかなる風も順風たりえない。」
ルキウス・アンナエウス・セネカ

# 1.1 プログラミングに銀の弾丸はない
- これさえあれば必ずうまくいくという「特効薬」はない
- 1つのツールや技法が何にでも当てはまることはない
- ソフトウェアには「複雑性」「同調性」「可変性」「不可視性」の4つの困難性がある

# 1.2 コードは設計書である
- 「製造」はコードを書くことではなく、リリースビルドのことを指す
- 「基本設計」「詳細設計」「プログラミング」「テスト」「デバッグ」までが設計という不可分な作業
- 設計のアウトプットが設計書である「コード」
- それらの作業を分担するのはうまいやり方ではない
- プログラマ全員が仕様を作成し、コードを書く。設計者がそのままコードを書いた方がうまくいく
- コードはなるべく早く書く。コードを書かないと不明瞭な部分だらけで、いつまでも設計が終わらない
- アジャイル開発手法は無駄なドキュメントを作らないというだけで、「ドキュメントを作らなくてよい」と主張しているわけではない
###### 関連
- 継続的なプログラミング活動において、特に重要なのが「ロゼッタストーン（将来の保守担当者に対する簡潔な手引書）」と呼ばれるドキュメント
- コードには「How」や「What」はよく表現されているが、「Why（設計理由）」がない　-> 設計理由をドキュメントに記述しておくと、多くの機会で役に立つ

# 1.3 コードは必ず変更される
- プログラミングにおける1つ1つの判断は「そのコードが変更される」という前提で行う -> 変更に強いコードを書く
- そのために「コードが読みやすい」ことが一番重要
【Laravel】バリデーションのアクションを指定する

# やりたいこと
Laravel はMVCベースのフレームワークにもかかわらず、モデルの扱いは良い意味で適当で7.x以前までは配置するディレクトリすらも適当でした。そのせいもあってか、4.xまではバリデーションはコントローラにアドホックに記述するしかなくロジックが分散しがちでした。5.xからはフォームリクエストバリデーションという仕組みが導入され、リクエストにバリデーションロジックを付加しカプセル化することが可能になりました。Ruby on Rails等のフレームワークに親しい人はこの仕組を用いて、例えば`UserRequest`とか`ArticleRequest`といった具合にモデル毎にバリデーションロジックをまとめる事ができるようになって安堵したことでしょう。

バリデーションロジックをまとめたことで、次に出てくる当然の要求はRuby on Railsのバリデーションの`on`オプションの様に**アクションによってそのバリデータを使い分けたい**ということです。つまり、例えば`Article`モデルでは記事のタイトル（`title`）は`store`の時点では必須（`required`）としたいが、`update`のタイミングでは空でも良い（つまりタイトルは更新しないことを意味する）といった状況です。これはRuby on Railsでは
```ruby
validates: title, presence: { on: create }
```
のように、バリデータ`presence`を`on`オプションで`create`（Laravelでいうところの`store`）時に限定しています。これです。これが Laravel でもやりたいのです。

# 結論
Laravelには（少なくとも9.xまでには）Railsの`on`オプションのような便利な機能はなさそうです。でも殆どのバリデータは共通なのに、そのうちの限られたフィールドに関するバリデータが異なるからといって`ArticleStoreRequest`、`ArticleUpdateRequest`のようにアクション毎にフォームリクエストを分けていては本末転倒です。（それならコントローラに直接バリデーションを記述した方がよっぽどわかりやすいと筆者は考えます。）

Laravelでこの`store`時のみもしくは`update`時のみに作用するバリデータを記述するには、`Route`ファサードを使用するのが便利だと思います。書き方は以下のようになります。
```php
return [
    'title' => \Route::uses('*store') ? 'required' : 'filled',
];
```
もちろんフォームリクエストの`rules`メソッドの返り値として記述することを想定しています。`Route`ファサードの`uses`メソッドは`App\Http\Controllers\ArticleController@store`のような「コントローラ@アクション」という文字列に対して`Str::is`ヘルパで検査をしますのでワイルドカード（`*`）が使用できます。詳しくは[API](https://laravel.com/api/9.x//Illuminate/Routing/Router.html#method_uses)を確認してください。

ちなみに上記の`filled`バリデータは、そのフィールドが存在しなくてもOKだが存在するならば空であってはならないという検証を実行します。つまり上記のようなルールを設定すると、新規作成時には`title`フィールドは指定されなければならず、さらに空文字や空白のみで構成されるような文字列も却下しますが、更新時には`title`フィールドは指定されなくても許容します。ただし、指定された時にはそれは空文字や空白のみの文字列では許されません。

# 参考文献
https://readouble.com/laravel/9.x/ja/validation.html#form-request-validation

https://qiita.com/kd9951/items/abd063828e33a61c8c58
TCPヘッダ

送信元ポート番号・・・16bit 送信元のアプリケーション(プロセス別)

宛先ポート番号・・・16bit 宛先のアプリケーション

ポート番号・・・論理的なアプリケーションを識別する番号

シーケンス番号・・・32bit 分割したデータの順序や順番を管理するための番号

確認応答番号・・・32bit　次に受信するべきデータのシーケンス番号を伝える番号

データオフセット・・・4bit TCPで混んでるデータの先頭　TCPヘッダの長さを表す

オプションなし・・・0101 20byteを表す　4*5=20

予約・・・3bit 将来拡張用に用意
基本的には0000　現在は使われていない

コントロールフラグ・・・8bit 該当パケットがSYN、ACK,FIN等の判断に使用する
先頭から8bit 1が入ったところが意味を持つ
1(0)・・・CWR
2(0)・・・ECE
3(0)・・・URG
4(1)・・・ACK
5(0)・・・PSH
6(0)・・・RST
7(1)・・・SYN
8(0)・・・FIN
この場合SYN　＋　ACK

ウィンドウサイズ・・・16bit 受信可能なデータサイズ　（バッファ容量）
まとめて受け取ることのできるデータサイズ

チェックサム・・・16bit ヘッダとデータが壊れていないかの確認するためのデータ

緊急ポインタ・・・16bit 緊急のデータの場所を表す情報
通信を途中で中断する際などに使用

オプション・・・可変長　最大４０byte　３２bitの整数倍にする必要がある　TCPの通信性能を向上させるための情報
例：MSSオプション・・・セグメントの最大長

パディング・・・可変長　オプションが32bitの整数倍にならない場合に調整する情報

データ(ペイロード)・・・データの本体
フォルダ命名規則の提案

使うと便利なフォルダ命名規則の提案

規則は至ってシンプル。
下記のようにフォルダの最初の3文字に英字をつけます。
aaa_あじさいの写真
aba_秋田犬の写真
aca_abort-task-list
.
.
.
a8a_adware
a9a_アプリケーションその1
a9a_アプリケーションその2
a9a_アプリケーションその3
a0a_applet
aab_apple1
aab_apple2
abb_愛らしい猫写真
acb_ascii
.
.
.

baa_バブルソート性能測定
bba_ビックエンディアンリトルエンディアン比較
bca_bugLog1
bca_bugLog2
.
.
.
b8a_バックエンドプログラム
b9a_BlueScreen
b0a_ビックボス
bab_bin
bbb_big3
bcb_ブルドッグ
.
.
.
0が切り替え最後の数字なのは、キーボードの配列の都合です。

便利な理由その1
lsやdirコマンドで確認が必要になるものの、
コマンドプロンプトやターミナルでのフォルダ移動が高速化できます。

便利な理由その2
漢字、カタカナ、ひらがな、英字を使ってフォルダを新規に作成しても位置が変わりません。

欠点その1
まじめに運用しようとすると、いちいち重複の確認をしなければならない。

欠点その2
dba_
tea_
といったように、規則でつけているだけなのに意味のある3文字になってしまいます。
その結果いらぬ誤解を招くことがあります。
アプリケーションサーバーについて

# はじめに
アプリケーションサーバーについて調べたところ、「Unicorn」や「Puma」などのワードが出てきたので、どんなものかと気になったので調べて見ました。

# アプリケーションサーバーとは
Ruby、Javaなどのプログラミング言語で構築されるアプリケーション（プログラム）を動作させるためのサーバサービスのことです。

# Unicornとは
マルチプロセス型であります。
マルチプロセス型は、私なりの解釈で言うと「一人の作業者が、複数の顧客に向けた製品を並行で制作している」と言う感じだと思います。
![スクリーンショット 2022-03-26 12.39.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2594478/26307307-16eb-510e-ce29-ef67a65ac886.png)

# Pumaとは
マルチスレッド型であります。
マルチスレッド型とは、私なりの解釈で言うと「一人の作業者が、一つの製品を制作する時に、同時並行で複数の作業を行う」と言う感じだと思います。
![スクリーンショット 2022-03-26 12.42.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2594478/7c5b1be0-63d6-1e73-4855-2859c2b50101.png)

# まとめ
現在、マルチスレッド型が主流になっていますが、アプリケーション毎に違いがあると思うので、そのアプリケーションにあったサーバーを使用すると良いと思います。
GKE Autopilot 関連ブログまとめ

随時更新予定。
よくある機能解説だけのブログは除いています。

# 中の人が書いた系
### 完全マネージドな k8s ! GKE Autopilot を解説する

https://medium.com/google-cloud-jp/gke-autopilot-87f8458ccf74

### Introducing GKE Autopilot: a revolution in managed Kubernetes

https://cloud.google.com/blog/products/containers-kubernetes/introducing-gke-autopilot


# 企業ブログ

### GKE Autopilotで作るMLリアルタイム推論基盤

https://tech.plaid.co.jp/ml_realtime_inference_with_gke_autopilot

### GKE Autopilotをデータ基盤に導入してみた

https://tech.hey.jp/entry/2021/06/29/141435

### GKE Autopilotの可視性とセキュリティ

https://www.scsk.jp/sp/sysdig/blog/container_security/gke_autopilot.html

### 就業型インターンで行ったGKE Autopilotの性能検証

https://engineering.dena.com/blog/2022/01/intern-2021-ishikawa-gke-autoscaling/

### 楽々スケール Digdag on GKE Autopilot の紹介とその運用Tips

https://techblog.zozo.com/entry/digdag-on-gke-autopilot

### FAANSにおけるCloud RunからGKE Autopilotへのリプレイス事例

https://techblog.zozo.com/entry/faans-replacement-to-gke-autopilot

# 個人ブログ

### EKS FargateとGKE Autopilotの違いを外野から解説してみる

https://blog.inductor.me/entry/2021/03/07/011811
Dartでデザインパターン-Strategy Pattern編

以前勉強しかけたデザインパターンを改めて学んでいるため、最近使っているDartでサンプルを書きながら説明していきたいと思います。
今回はStrategy Patternです。

# Strategy Patternってどんなの？
Strategy Patternとは、振る舞いに対してコンポジションを使うパターンのことです。
サンプルを見てみましょう。下はそれぞれ、犬が吠えるための `bark` メソッドを、それぞれ継承・Strategy Patternで書いたものです。
### 継承
```dog.dart
abstract class Dog {
  void bark();
}
```

```toy_poodle.dart
class ToyPoodle extends Dog {
  @override
  void bark() => print('ワン！');
}
```

```bulldog.dart
class Bulldog extends Dog {
  @override
  void bark() => print('バウ！');
}
```

### Strategy Pattern
```dog.dart
abstract class Dog {
  const Dog({required this.bark});

  final BarkBehavior bark;
}
```

```toy_poodle.dart
class ToyPoodle extends Dog {
  ToyPoodle() : super(bark: TinyBarkBehavior);
}
```

```bulldog.dart
class Bulldog extends Dog {
  Bulldog() : super(bark: StrongBarkBehavior);
}
```

```bark_behavior.dart
typedef BarkBehavior = void Function();
final StrongBarkBehavior = () => print('バウ！');
final TinyBarkBehavior = () => print('ワン！');
```

# 何が嬉しいの？
パッと見た限り、Strategy Patternのほうが煩雑に見えるかもしれません。ただ、変更には圧倒的にStrategy Patternのほうが強いです。
具体的なメリットとしては下記があげられます。
- 特定の犬どうしで振る舞いを共通化できる
- 機能追加で副作用を与えない

それぞれ説明させていただきます。

## 特定の犬どうしで振る舞いを共通化できる
新しい犬 `ドーベルマン` を追加することになりました。それぞれ対応してみましょう。
### 継承
```doberman.dart
class Doberman extends Dog {
  @override
  void bark() => print('バウ！');
}
```

### Strategy Pattern
```doberman.dart
class Doberman extends Dog {
  Doberman() : super(bark: StrongBarkBehavior);
}
```

いかがでしょう？
継承を使ったパターンだと、ブルドックと同じ鳴き方をする(諸説ある)ドーベルマンにたいして、同じ処理を繰り返し書いてしまっています。これでは保守性が悪くなってしまいますね。

## 機能追加で副作用を与えない
犬は走るでしょ！という要望があり、機能の追加が入りました。それぞれ対応してみましょう。
### 継承
```dog.dart

abstract class Dog {
  void bark();
  void run() => print('犬が走っています');
}
```

### Strategy Pattern
```dog.dart
abstract class Dog {
  const Dog({
    required this.bark,
    required this.run,
  });

  final BarkBehavior bark;
  final RunBehavior run;
}
```

```toy_poodle.dart
class ToyPoodle extends Dog {
  ToyPoodle()
      : super(
          bark: TinyBarkBehavior,
          run: NormalRunBehavior,
        );
}
```

```bulldog.dart
class Bulldog extends Dog {
  Bulldog()
      : super(
          bark: StrongBarkBehavior,
          run: NormalRunBehavior,
        );
}
```

```run_behavior.dart
typedef RunBehavior = void Function();
final NormalRunBehavior = () => print('犬が走っています');
```
はい。完了です。
あれ？Strategy Patternは改修多くない？と思われたかもしれません。
ですがこのあと継承をつかったパターンではバグが発生しました。 `以前追加した、走ることのできないおもちゃのトイプードルのことを忘れていた` のです。

↑には書いていませんでしたが、StrategyPatternを使っていたパターンではこれに気づき、対応できていました。
```dart
class ToyToyPoodle extends Dog {
  ToyToyPoodle()
      : super(
          bark: TinyBarkBehavior,
          run: CanNotRunBehavior,
        );
}

final CanNotRunBehavior = () => print('この犬は走れません');
```

# まとめ
いかがだったでしょうか？Strategy Pattern、かなり便利そうですね。
今後も頑張って書きます。LGTMやTwitterで感想・フォローいただけるともっとがんばれます。

# 参考文献から変更した部分
- Behavior毎にクラス用意されてましたが、Dartには `typedef` があるのでそちらを使うほうが良いと判断し変更しました。
- 参考文献ではBehavior毎にクラス分けされていたため、Behaviorの関数を呼び出すための関数が別途用意されていましたが、そもそもクロージャで渡すことにしたので用意していません。

# 参考文献
[Head Firstデザインパターン ―頭とからだで覚えるデザインパターンの基本]( https://amzn.to/36Nf14u)
pyenv install xxx が失敗する(Killed: 9)

## 環境
- macOS 11.6, 12.3(arm64)
- homebrew
- pyenv 2.2.5
- gcc Apple clang version 13.1.6 (clang-1316.0.21.2)

homebrewのバージョンはメモ取ってませんでした。ごめんなさい。
## 事象
`pyenv install 3.10.3`としてインストールを試みたところ、ビルドの途中で失敗した。
`/bin/sh: line 1: 24309 Killed: 9 ...(略)... make: *** [sharedmods] Error 137`
ビルドの途中で強制終了されているみたい。

## 解決方法
***homebrewをインストールし直す。***
pyenvリポジトリに[issue](https://github.com/pyenv/pyenv/issues/2289)が立っていて、このissueに「homebrewを入れ直したら直った」とのコメントがあった。
試したところ、なぜか分からないが本当に直った。
homebrewのインストール/アンインストールスクリプトは[こちら](https://github.com/homebrew/install)からどうぞ。再インストール後のhomebrewのバージョンは3.4.3でした。

## 終わりに
原因がわからないのが悔しいところ。再インストール前のhomebrewのバージョンを控えておけばよかったです。
なお、アンチウイルスを追加でインストールしている方は以下の記事も参考になるかと思います。

[Pythonのビルドに失敗する原因がアンチウィルスソフトだった件](https://zenn.dev/todesking/scraps/d79e6d943da1b7)
git_config設定

よく忘れるのでメモ。

# gitのconfig設定

```terminal:一覧表示
$ git config --list
```

```terminal:セットしたい時
$ git config --global {設定値}
```


```terminal:外したい時
$ git config --global --unset {キーの名前（=より左側）}
```
##### `{キーの名前（=より左側）}`の補足

* `git config --list`で表示させた時の、`=`より左側のことだよ！
    * 下記で言うと、`alias.ci=commit`が消えます。

![スクリーンショット 2022-03-26 13.33.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696641/2fad262a-d8da-4699-de0e-1ede787825f1.png)



# よく使う設定

## 初期設定

```terminal:名前
//登録
$ git config --global user.name "{githubのユーザー名}"
//確認
$ git config user.name
```

```terminal:email
//登録
$ git config --global user.email "{githubのemail}"
//確認
$ git config user.email
```

```terminal:editor
//登録（下記はVSCode)
$ git config --global code.editor "code --wait"
//確認
$ git config core.editor
```

## 設定しておくと便利な設定

```terminal:エイリアス（コマンド短くなって楽）
$ git config --global ailias.ci commit
$ git config --global ailias.st status
$ git config --global ailias.br branch
$ git config --global ailias.co checkout
```

```terminal:masterにpullするときはリベース型にする
$ git config --global branch.master.rebase true
```

```terminal:FastForwardせず、マージコミットを作るようにする
$ git config --global merge.ff false
```
IPv4ヘッダ

バージョン・・・4bit　IPv4なのかIPv6なのか
IPv4・・・0100 IPv6・・・0110 十進数だと4と6になる

ヘッダ長・・・4bit ヘッダの長さ
基本的に0101の20byteになることが多い(1bit=4byte)4*5=20byte　横４縦５の２０byte

サービスタイプ(Tos)・・・サービス品質
現在では使われていない。DSCPフィールドやECNフィールドなどで使用したりする

パケット長・・・16bit パケットの長さ
IPで運べるのは65536byte
イーサネットで運べるのが1518byte
フラグメントして送る

--------------------フラグメント処理に使用--------------------------------

識別子・・・16bit フラグメントを再構成する際に使用

フラグ・・・3bit 分割する時の制御情報
分割不可能にしたり今は混んでるパケットが最後なのか

フラグメントオフセット・・・13bit 分割されたデータの位置情報

--------------------フラグメント処理に使用--------------------------------

TTL・・・8bit  ルータを通過できる回数
最大255 TTLを超えた場合破棄される

プロトコル・・・8bit IPヘッダの次のプロトコルを表す
TCP・・・６　　　UDP・・・１７

ヘッダチェックサム・・・16bit IPヘッダが壊れていないか確認する為の情報

送信元IPアドレス・・・３２bit TCP/IPで必須の情報　送信元の住所
宛先IPアドレス・・・32bit TCP/IPで必須の情報　宛先の住所

オプション・・・可変長 32bitの整数倍　基本的に使わない
パティング・・・可変長　オプションが32bitの整数倍にならなかった際に調整する
config/database.php

SynogyのNASにはMariaDBがのっている。
config/database.phpの初期設定はutf8mb4という絵文字対応の文字コードになっているため そのままphp artisan migrateすると文字コードがおかしくなる。
```config/database.php
'mysql' => [ 
'driver' => 'mysql', 
'url' => env('DATABASE_URL'), 
'host' => env('DB_HOST', '127.0.0.1'), 
'port' => env('DB_PORT', '3306'), 
'database' => env('DB_DATABASE', 'forge'), 
'username' => env('DB_USERNAME', 'forge'), 
'password' => env('DB_PASSWORD', ''), 
'unix_socket' => env('DB_SOCKET', ''), 
※ここを変更する 'charset' => 'utf8', 
※ここを変更する 'collation' => 'utf8_general_ci', 
'prefix' => '',
'prefix_indexes' => true, 
'strict' => true, 
'engine' => null, 
'options' => extension_loaded('pdo_mysql') ? array_filter([ PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
 ]) : [], 
],
```
configファイルにさわったので
```bash
php artisan cache:clear
php artisan config:clear
```

私は文字化けは経験してないのだがこの設定で今まで問題になったことはない。
Work around for VS Code Issue: Error authenticating the refresh token due to: expired access/refresh token

FROM:
https://www.greytrix.com/blogs/salesforce/2021/11/24/work-around-for-vs-code-issue-error-authenticating-the-refresh-token-due-to-expired-access-refresh-token/

Work around for VS Code Issue: Error authenticating the refresh token due to: expired access/refresh token

対策：
Firstly, delete the “.sfdx” folder from the project folder (which gets created automatically for Salesforce project)

Secondly, re-authorize the org.
And finally refresh/Deploy metadata from Salesforce.
［AWS］今週の問題5週目

皆様お久しぶりです。
最近コロナに罹っていたので、前回の投稿から間が空きましたのでテーマを決めずに有用な問題をいくつか記載します。

# 問題
問1. RDSのマイナーバージョングレードは[A]でAWSが行なってくれるが、メジャーバージョンのアップグレードは[B]で行わなければならない。何か答えよ。

問2. 外部サーバが固定IPアドレスからしか通信を許可していない場合、何を利用すれば簡易的に解決できるか答えよ。

問3. SESでメールを送信する場合は、EventBridgeから[A]へメール送信を指示する。また[A]でメールの文面も作成可能ある。何か答えよ。

問4. IPv6版の[A]は存在しないが、代わりに[B]を用いて固定のIPから通信を行える。何か答えよ。

問5. RedHat系のディストリビューションにデフォルトでインストールされており、大量の容量をコピーする際など長時間のコマンド実行する際にバックグラウンドで実行してくれる便利なコマンドは何か答えよ。

問6. 急激なアクセス増に対してELBのスケールアウトを事前に申し込むことをなんというか答えよ。

問7. SESは設定を行わないと[A]ログを確認できない。何か答えよ。

# 解答
問1. [A]自動 [B]手動
問2. NATゲートウェイ
問3. [A]Lambda
問4. [A]NATゲートウェイ [B]Egress-only インターネットゲートウェイ
問5. screnn
問6. 暖気申請
問7. メール配信
初心者ブロックチェーンに挑戦する　20

# My Sweet NFT

## 迂闊と推理

　NFT作成サイトの課題も最終段階だ。GitHubに上げる前に、gitignoreやら、.envやらをつくる。私のウォレットには、今はおもちゃのお金しか入っていないけれど（そろそろちょっと本物も買おうかしら）、でも情報が漏れるのは金庫の鍵を窓の外にぶら下げるようなものだから、テキストの要所要所に、このkeyはだれにも教えてはいけません！、と書いてある。そういう大事なkeyを何種類もまとめてあるファイルを隠しファイルにしたのはいいが、それが読めないからrunできないは困るでしょうよ。

- あなたのHardhat.configの文字列はまちがっています。
- だってそれ、わざわざ.envに移したのよ。だから、.envを読んでねって書いたでしょう。

 いや、わかった。つまり.envが読めないといっているのね。つまり、.envを読むためのコードが足らないんだ。ビンゴ。ファイルの一番上には、読み込み関係の一覧がある。ここでdotenvを呼ばないといけない。ああ、発音しにくい、変な名前ばっかり。

- dotenv

　ああ、ドット、env、か。envってなに。環境変数？　エンバイロメント？ なんだ、そのまんまか。こういう迂闊な性格だけれど、これができないならここ、ここがだめならここ、とエラーを読みながら推理する能力は少しついた気がする。迂闊でなければ、最初からちゃんと一行一行丁寧に書いてれば、要らん能力かもしれないけれど、でも結局、常にどこかにミスはあるのだから、推理力が不要になることはないだろう、と思う。そう思っとくことにしよう。

- [Etherscan](https://etherscan.io/) で コントラクトの Verificationを行いましょう。

 これにまた失敗する。失敗するが、これはオプションだ、いや、課題的にはオプションじゃないのとだけれど、サイトを構築する上では、一応オプションだ。質問をDiscordに投げておいて、いったんスルーしよう。

- GitHubに上げる。
- Vercelで公開する。

　あれ、Vercelで今回のリポジトリを読めない。ああ、前回、このリポジトリだけを読む、に設定してたのか。全てのリポジトリを読む、に変更。はい、出た出た。

　deploy行け〜。終了！

## おもちゃのイーサをお持ちの方は、遊んでやってくださいませ。

https://nft-collection-starter-project-two.vercel.app/
TypeScriptとExpressの環境構築

# はじめに
Webアプリケーションでよく利用されているExpressというフレームワークをサーバ側に、
TypeScriptをクライアント側にする環境構築の手順をまとめた

# 前提条件
npmがインストールされていること

# 手順
ターミナルを開き、ターミナルで次のコマンドを実行していく

1.TypeScriptをインストール

```command
npm install -g typescript
```
2.次のコマンドを実行してpackage.jsonを作成します

```command
npm init
```
※コマンド実行後は色々質問が来ますが、ここでは説明を省き、Enterキーを押していきます

3.package.jsonを作成したら、次のコマンドを実行します

```command
yarn install
```

4.次のコマンドを実行し、tsconfig.jsonを作成します

```command
tsc --init
```

5.VSCODEのエディタなどでpackage.jsonを開き次の1行を追加します

```package.json
"moduleResolution": "node",
```
（例）package.json
![スクリーンショット 2022-03-26 11.12.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/d4865e96-4e1c-7922-1ab5-65d25d41f471.png)

6.tsconfig.jsonを開き、 "noUnusedParameters"のコメントアウトを外し、true→falseに変更します

```tsconfig.json
"noUnusedParameters": false,
```
（例）tsconfig.json
![スクリーンショット 2022-03-26 11.12.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/462a4971-7e52-327f-26a2-3aa7f54d7764.png)

※tsconfig.jsonに下記のエラーが発生している場合

```
　　tsconfig.json で入力が見つかりませんでした。指定された 'include' パスは '["**/*"]' で、'exclude' パスは '["node_modules"]' でした。
```
→tsconfig.jsonの最後に"include"を追加すると解消できました
![スクリーンショット 2022-03-26 11.46.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603047/b46c7a21-8cb3-18bb-faf6-39ab02fcba6f.png)
それでも解決しない場合は調べてください
（検索ワード「tsconfig.json 入力が見つかりませんでした」など）

以上で環境構築が終わりです
【Ruby】特異メソッドについて

## 特異メソッドについて

```ruby
class C
  class << C
    def hoge
      'Hi'
    end
  end

  def hoge
    'Goodbye'
  end
end

p C.new.hoge
```

```
"Goodbye"
```
このように表示される。

```
p C.new.hoge
```
上記の記述では、インスタンスを作成してその中のメソッドを呼び出ししているため```"Goodbye"```と表示される。

### 特異メソッドの宣言方法
特異メソッドの宣言方法には2つあるらしい。

```ruby
## 1つめ
  class << C
    def hoge
      'Hi'
    end
  end

## 2つめ
  def C.hoge
    'Hi'
  end

```
このように2つの宣言方法があるらしい。

そしてこの特異メソッドを呼び出したい時は、```p C.hoge```というようにすればいい。
そうすると```Hi```と表示される。
config/app.php

タイムゾーンと言語<br>
Laravelをインストールしたフォルダの中の config/app.php ファイルを開く。
<br>
70行目ぐらいに ‘timezone’ があるので、(Asia/Tokyo)と変更する。
```config/app.php
'timezone' => 'Asia/Tokyo',
```
83行目ぐらいに’locale’ があるので、(ja)と変更する。
```php
'locale' => 'ja',
```
configファイルにさわったので
```bash
php artisan cache:clear
php artisan config:clear
```
conda コマンドの整理

## conda コマンド一覧
自分の備忘録として作成しました..

* 仮想環境を作成する
* condaのアップデート
* 仮想環境一覧を出す
* 現在の仮想環境のパッケージの確認
* 仮想環境の名前を変更する
* 作成した仮想環境への切り替え
* 仮想環境から出る
* 仮想環境の削除
* 現在の仮想環境の設定ファイルを書き出す


~~~
# 仮想環境を作成する
conda create -n env-x python=3.8
# conda アップデート
conda update conda
#仮想環境一覧を出す
conda info -e
#現在の仮想環境のパッケージの確認
conda list
# 仮想環境の名前を変更する
conda create -n NEW_NAME --clone PREVIOUS_NAME
conda remove -n PREVIOUS_NAME --all
#作成した仮想環境への切り替え
source activate ENV
# 仮想環境から出る
source deactivate 
# 仮想環境の削除
conda env remove -n env
conda remove --all

#現在の仮想環境の設定ファイルを書き出す
conda env export > env.yaml
~~~


### 参考文献
+ [[備忘] python / conda環境構築の基本コマンド一覧](https://qiita.com/yampy/items/4e89cd97179bbd20f726)
+ [Anacondaで作成した環境の名前を変更する](https://paper.hatenadiary.jp/entry/2017/05/02/110302)
（備忘メモ）Nginx + uWSGI なアプリサーバーの同時処理性能

Nginx + uWSGI なアプリサーバーの同時処理性能がどうやって決まるのか、
設定値を調べたので備忘メモ。

## 構成

![timeout_infra構成-プロセス数構成図.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529884/f592db14-8fa7-3a64-6239-521959f2666c.jpeg)


## Nginx

* worker_process;
  * ワーカーのプロセス数
  * デフォルト 1
  * `auto` にすると、CPU のコア数と同じになる
* worker_connections;
  * 1 プロセスが同時に受けつけられるコネクション数
  * デフォルト 512
* クライアントから見ると、**プロセス数 * コネクション数**だけ口があることになる
* なお、総コネクション数がファイルディスクリプタの上限数を超えないようにする必要があります。
  * こちらの記事が分かりやすかったです。
  *　https://qiita.com/mikene_koko/items/85fbe6a342f89bf53e89

## Uwsgi

* processes (または workers)
  * プロセス数を定義
  * 必須パラメータ（デフォルトなし）
* threads
  * スレッド数を定義
  * 必須パラメータ（デフォルトなし）
* nginx から見た時は、**プロセス数 * スレッド数**だけの口があることになる
Phaser.jsで、CPU対戦4人大富豪を作りました。

先週のポーカーに続き、大富豪も作りました。
CPUがバカチョンです（笑）が、
自分＋CPU3人の4人対戦です。

https://www.new-doumeishi.me/vsDaihugou_v1/public/
うっかりrmを防ぐために

# 要約
- 間違えて`rm`コマンドでファイルを削除してしまうミスを防ぐために、簡単な関数をシェルの設定ファイルに書いてみました。処理内容としては、`mv`コマンドで`/tmp`に移動させているだけです。
- おまけとして、この`rm`コマンドで削除したファイルを復元する`rs`関数も書いてみました。

# はじめに
`rm`コマンドでファイルを削除するとき、タイプミスなどでうっかり消したくないファイルまで削除していまう時があります。運が良ければそのファイルを復元できるみたいですが、そうでなければ...あまり考えたくありませんね。

というわけで、できるだけ簡単にその操作ミスを防ぐことができる方法を考えてみました。（何か間違いがあればコメントでご指摘いただけるとありがたいです！）

# どうすれば良いか？
以下の関数をシェルの設定ファイルに追記すれば良いです。`zsh`を使っているなら、`.zshrc`に追記してください。

関数の処理内容としては、`mv`コマンドを呼び出し、`/tmp`ディレクトリに移動させているだけです。引数が複数の場合でも対応したかったので、`for`文を使って一つずつ移動させています。`*`で引数を渡すと警告が出ますが、`RM_STAR_SILENT`で抑えることができます。お好みで設定してください。

`/tmp`ディレクトリのファイルは、一定期間経過すると削除されるので、移動先に選びました。

``` sh
setopt RM_STAR_SILENT
rm () {
	for e in "$@"
	do
		mv "$e" /tmp
	done
}
```

ついでに、この`rm`コマンドで削除したファイルを復元する`rs`関数も書いてみました。restoreから名前をとってみました。削除する`rm`と復元する`rs`でなかなか綺麗な名前な気がします。処理内容は上記と似ているので割愛します。

``` sh
rs () {
	for e in "$@"
	do
		mv /tmp/"$e" .
	done
}
```

# まとめ
- 操作ミスしてもすぐに復元できる`rm`関数を書いてみました
- もしかしたら既に誰かが考えているかもしれませんが、意外と使える関数だと思います

おしまい
いまだにviエディタを使っている私

## 現在、
私は運用・監視業務に携わっており、ここに書かれているテクニカルなこと(プログラミングとかで何かを生み出す)とはおおよそ無縁の仕事をしている。
それでも昔、社会人になって9年ほどはC言語やVisual Basicでプログラムを書いてたことがあり、特にUNIX上でソースファイルを作成した頃に覚えたviエディタの操作は、今でも多少なりとも役に立っている。
現在の業務で時折、Linux上のテキストファイルを編集する時に使用している。

## いま、
Linuxで使用するエディタって何が主流なんだろうか。まあ、特に知らなくてもまだviが使えるし、新たに覚えなくてもいいかなあーと思っている。

## そういえば、
UNIXでCのソースファイルを作ってた頃、viでのカーソル移動に「カーソルキーは使うな」と当時の先輩に言われていた。なぜだかは忘れてしまったが、「k(上)」「j「下」」「h(左)」「l(右)」キーでカーソルを移動させていた。Linuxでは平気でカーソルキーを使っているが...

## あと、
vi内で正規表現を使用した操作がいまだにできない、というより覚えられない。
それができれば、いろいろできるかもしれないが、まあ特に今の業務に就いているうちは覚えなくても特に困ることは無い。

## 終わりに
このコミュニティの中で、今もバリバリにviエディタを使用している人がいたら、なんかうれしいなあ。
再帰処理


最近、ちょっとボケ気味なのでメモっとく。

children に子要素を再帰的に持つデータに対しての処理関数。
```js: データ構造
let item = {
 children = [],
 ...parameter,
}
let items = [item]
```
```js
recursive(items, args) {
  let return_value = null
  items.forEach(item => {
    return_value = proc_statement(item, args)
    if (!exit_recursive_condition(item, args)) {
      // 条件に一致しなければ子要素に対して処理をする
      return_value = recursive(item.children, args)
    }
  });
  return return_value
}
exit_recursive_condition(item, args) {
  // 再帰処理を抜ける条件
  return item.parameter == args
}
proc_statement(item, args) {
  // 要素に対する処理
  return item
}
```
args は再帰処理を抜ける条件や要素に対して処理を行うための引数。
全ての要素に対して処理を行うのであれば exit_recursive_condition()は不要でforEach をmapに変えればよいかと。
セレクタを並べて記述【CSS】対象を絞り込む

**HTML**
```
<p class="item _current">サンプル1</p>
<p class="item">サンプル2</p>
```
**CSS**
```
.item._current { color: red; }

.item { font-style: italic; }
```
![スクリーンショット 2022-03-26 10.39.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1130361/c7e17487-a9f7-ca3c-fbec-b2efc30cbe4f.png)


セレクタを区切り文字・空白なしで記述（結合・連結）すると、対象を絞り込むことができる。

例：クラスセレクタ「item」とクラスセレクタ「_current」を並べて、「サンプル1」だけを赤文字にしている。
JetpackComposeを使ってFlutterの初期プロジェクトと同じものを作ってみる

# 初めに
こんにちは。Androidエンジニアのバナナです。今日もJetpack Composeを触っていきます。
今回はカウントアップアプリを作ってみます。
Flutterで自動生成されるアプリと同様のアプリですね。
<img width="300" alt="Screenshot_1648080971.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2466399/c38ffe08-e4bb-dc41-1970-726f792b26dc.png">

# レイアウト作成
まずはレイアウトを作っていきます。
要素としては下記の3つがありますね

- ①トップバー
- ②画面中央のカウントを表示するテキスト
- ③右下のアクションボタン

次のように実装します。
`Scaffold` を使うことで、レイアウト指定がなくてもマテリアルデザインに沿った配置にしてくれるのに感激しました。

```kotlin:MainActivity.kt
@Composable
fun Counter() {
    Scaffold(
        // ①トップバー
        topBar = {
            TopAppBar(
                title = {
                    Text(
                        textAlign = TextAlign.Center,
                        text = "Count Up App",
                    )
                },
            )
        },
        // ③右下のアクションボタン
        floatingActionButton = {
            FloatingActionButton(onClick = { /* ... */ }) {
                /* FAB content */
                Icon(Icons.Filled.Add, "Add")
            }
        }
    ) {}

    // ②画面中央のカウントを表示するテキスト
    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(
            text = "You have pushed the button this many times:",
            fontSize = 12.sp
        )
        Text(
            text = "0",
            modifier = Modifier.padding(8.dp),
            fontSize = 24.sp
        )
    }
}
```

忘れずに、Previewメソッドも実装しておきます。
```kotlin
@Preview(showBackground = true)
@Composable
fun CounterPreview() {
    Counter()
}
```
画面はこのようになりました。
<img width="300" alt="Screenshot_1648080971.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2466399/79aee71f-5bd6-3a72-cadf-988f84098286.png">

# カウントアップ機能を実装する

カウントアップ機能実装のために、カウント保持用の変数とインクリメント用のメソッドを作っておきます。
```kotlin:CountViewModel.kt
    var currentCount = mutableStateOf(0)

    fun onClickCounter() {
        val currentValue = this.currentCount.value
        this.currentCount.value = currentValue + 1
    }
```

あとは、Counterメソッドで以下の二つを実装すれば完了です。
- アクションボタンタップ時にインクリメントメソッドを呼ぶ
- viewModelのカウントを画面に表示する

```kotlin:MainActivity.kt
@Composable
fun Counter(viewModel: CountViewModel) {
    // 省略
    floatingActionButton = {
        FloatingActionButton(onClick = {
            viewModel.onClickCounter()
        }) {}
    }
    // 省略
    Text(
        text = "${viewModel.currentCount.value}",
        // 省略   
    )
}
```
これで、カウントアップアプリが完成しました。
一応[こちら](https://github.com/bananarizumu/compose-sample-count-up-app)にコードをプッシュしておきます。
今日はここまでにします。
<img width="300" alt="Screenshot_1648080971.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2466399/58e6f50a-06e2-2db6-e918-60d06b6e8ea4.gif">¥
（備忘録）AWS認定試験テキストSAP本のデモ(IAMロール、クロスアカウントアクセス)

# 1. はじめに
2022年3月26日に[ヤマムギ](https://yamamugi.connpass.com/)様主催にて開催された[ヤマムギ vol.28 AWS認定試験テキストSAP本のデモ(IAMロール、クロスアカウントアクセス)](https://yamamugi.connpass.com/event/241508/)でのAWS学習内容について、自分への備忘録としてまとめてみました。ご参考になれば幸いです。

# 2. 学んだ内容
- IAMロールの作成
- コンソールでクロスアカウントアクセス
- CLIでクロスアカウントアクセス
- SDK(Python boto3)でクロスアカウントアクセス
- AWS SSOでクロスアカウントアクセス

# 3. 学習サイト
- [YouTube：]()

# 4. 参考サイト
- [Twitterヤマムギ](https://twitter.com/search?q=%23yamamugi) ハッシュタグ #yamamugi
- [YouTubeヤマムギ](https://www.youtube.com/c/YAMAMUGI/videos)
- [AWS複数アカウントのリソースをLambda(Python)から一括操作したくて](https://www.yamamanx.com/aws-multi-account-resource/)
- [AWS CLIを使用したIAMロールの引き受けコマンドのメモ](https://www.yamamanx.com/aws-cli-iamrole-assumerole/)
- [AWS SSOのIDソースをAD Connectorにしました](https://www.yamamanx.com/aws-sso-id-ad-connector/)
- [Active Directory認証でAWSマネジメントコンソールにSSO](https://www.yamamanx.com/active-directory-aws-sso/)

# 5. ハンズオンで得た豆知識
- 2つのAWSアカウントを用意する（アルファアカウント、ベータアカウント）
- アルファアカウントにはIAMユーザを用意
- ベータアカウントにはIAMユーザを用意せず、AssumeRoleでアクセスする
- AWS Single Sign-Onを用いるとクロスアクセスを簡単に実現できる
- IDソースの選択肢は3つある
- AWS CloudShell


```

// AWS CloudShellでのコマンド
$ role_credentials=$(aws sts assume-role --role-arn "arn:aws:iam::056922243809:role/S3ReadOnly" --role-session-name yamashita)

$ export AWS_ACCESS_KEY_ID=$(echo $role_credentials | jq -r '.Credentials.AccessKeyId')

$ export AWS_SECRET_ACCESS_KEY=$(echo $role_credentials | jq -r '.Credentials.SecretAccessKey')

$ export AWS_SESSION_TOKEN=$(echo $role_credentials | jq -r '.Credentials.SessionToken')

// 確認コマンド
$ aws sts get-caller-identity

// 確認コマンド
$ aws s3 ls

// 環境変数を開放すると元のアカウントに戻る
$ unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN

```

# 6. おわりに
AWS学習の参考になれば幸いです。
ハンズオン開催してくださいました[ヤマムギ](https://yamamugi.connpass.com/)様、感謝いたします。

2022/03/26 NISHIZONO Takahiro
コピペチェッカーでレーベンシュタイン距離を使わない理由

# レーベンシュタイン距離とは
レーベンシュタイン距離とは比較的歴史のある、文字列間の類似度を求めるためのアルゴリズムです。
特定の言語に依存しているわけではないため、様々な言語で解く方法が紹介されています。

以下記事などで詳しく紹介されており、アルゴリズムを理解するためには一度目を通した方が良いです。

[[PHP][マルチバイト対応]レーベンシュタイン距離を求める(解説つき)](https://qiita.com/alwayspringreen/items/2e4d2a28a319e26cc837)
[レーベンシュタイン距離の編集操作を統合してグラフ化する](https://qiita.com/yut-kt/items/54b7b8bca759b8636345)
[文字列間の距離を測るレーベンシュタイン距離がシンプルで美しかった](https://qiita.com/3000manJPY/items/c28ed74d2d06971c34ef)
[『レーベンシュタイン距離』で2つの文字列の類似度を計算してみた](https://qiita.com/shoku-pan/items/befa11396a7c3cc10f6c)


## レーベンシュタイン距離の簡単な説明
既に有識者によるレーベンシュタイン距離の説明は出ていますので、詳細は説明は省きますが
以下のような文章があった場合、
1. `今`日の天気は何ですか？
2. `明`日の天気は何ですか？

先頭の一文字、で 今　と　明　のような異なる文字を確認して、一致させるためにはどの程度の計算量が必要になるかを数えて、どれぐらいこの数字が少ないかを考える手法です。
※変更・追加・削除

しかし、このレーベンシュタイン距離の算出は正確すぎるがゆえに、剽窃チェックで用いた場合、課題になると思いました。
今回は解く方法ではなく、この課題に関して記したいと思います。

# レーベンシュタイン距離をコピペチェックで用いた場合の課題について

今回、コピペチェッカーを開発したのですが、実装した上でレーベンシュタイン距離を求めた場合、何点か課題がありました

[コピペチェッカー](https://top.plagiarism.win/)

### 高精度・正確すぎる剽窃チェックになってしまう。
一見良い話にしか聞こえませんが、日本語及び、日本語と同じ文字体系の例えば韓国語などでは、これは問題になるのではないかと思います。
英語などであればよいかもしれませんが、正確すぎると時に、困ったことになる場合もあります。
冒頭の以下の例のように１文字違う場合は良いかもしれません。
1. `今`日の天気は何ですか？
2. `明`日の天気は何ですか？

しかし、以下のような例だとどうでしょうか

1. `今日`の`天気は何ですか？`
2. `冬山`の`寒さで凍えてしまう。`

【の】　の、一文字が一致しますね。
なので、二つの文書間でこの一文字のせいで**似ている**ことになります。

人間の目で見れば一目瞭然で、この二つの文章は**似ていません**が、プログラムはそのような人間側の事情などお構いなしでうごいてくれますので、これほど全く異なる文章であっても、たったの一文字の為、とっても距離が離れた状態で**似ている**といった判断[^1]をしてしまいます。
違和感しかないかもしれませんし、レーベンシュタイン距離の問題ではないかもしれませんが、プログラムで見たときはこの一文字は一致している文字扱いになります。
すべて異なる文字であれば、全く似ていないとNG判定を出せますが、n文字（例の場合は1文字）一致して残り▼▼離れていると判断しなければなりません。

[^1]: 実際には距離が5以上は慣れていれば、**似ていない**といったロジックを組み入れればよいだけですので問題にはなりません。

### 遅すぎる
これは、アルゴリズム的に致し方なしという判断をせざるをえない観点ですし、そもそも速さを求めるものではないので、構わない話です。
レーベンシュタイン距離の算出は非常にシンプルなアルゴリズムで、コードは非常に短いです。
上記の参考記事でプログラムを紹介してもらっていますが、ほんの数十行レベルの内容になっています。

しかし、その中で for分の二重ループになっています。
マトリックスで説明できる話は、おおよそ、for分の二重ループが解く方法になる場合がありますが、時間がかかります。
とはいっても、プログラムでやれば一瞬ですので、30文字と30文字の文章間で用いる場合は気にならないでしょう。

しかし、これが剽窃チェックといった1000文字と1000文字といった分量になると話は変わってきます。
さすがに時間がかかりますね。

### 不得意な場合
1. レモン
2. 神奈川

この二つは誰がどう見ても似ていないです。
しかし、レーベンシュタイン距離を求めると３文字異なるという点が評価されるので、計算距離が短くなります。
このような短い文字列で剽窃を確認するのはそもそもが不適切ですが、ロジック的には共通にしなければならないため、
例外処理を盛り込む必要が出てきます。


# 100点を目指さない剽窃を確認するためのコピペチェッカー

開発した[コピペチェッカー](https://top.plagiarism.win/)では今回レーベンシュタイン距離を求めることはしませんでした。
途中まで実装しているため、コメントアウトして残っているのですが、有効化する事は無いでしょう。

正確すぎる点は、そのあとのロジックで何とでもなる問題ですが、計算量が多すぎて時間がかかる問題は対応が難しいからです。
計算機側のスペックを上げることにより解決はできますが、コストが増大してしまいます。

100点を目指す場合、レーベンシュタイン距離算出は活用すべき機能ですが、バーターで必要となる計算時間の問題は許容できないレベルです。

90点の精度になり、実装したアルゴリズムでは判定が難しい文字列比較のパターンが発生してしまう事にはなるのですが、
今回作成したコピペチェッカーでは、その分、高速での文字列比較を実現しています。

レーベンシュタイン距離の考え方は自然言語処理の分野では非常に有効・重要なテーマにはなるでしょうが、上記の通り取り扱いに注意が必要な場合もあります。※まぁなんでも一緒だと思いますが、使いようってやつですね。