OmniAICreator/Qiita-1.07M huggingface dataset:
【Rails】バリデーションをスキップ

# validate: false

- https://railsguides.jp/active_record_validations.html
>saveにvalidate: falseを引数として与えると、saveのバリデーションをスキップすることが可能です。この手法は十分注意して使う必要があります。
save(validate: false)

- こんな時に使用
  - データパッチをする必要があるが、バリデーションが走り登録できない
  - 仕様上、Modelに定義したバリデーションは変更したくない
```sample.rb
ActiveRecord::Base.transaction do
  # 更新
  contract.assign_attributes(contract_kind: MONTHLY, updated_system: SYSTEM_NAME, updated_user: UPDATED_USER)
  contract.save!(validate: false)
end
```
Spring Beanのスコープについて

## 発生した問題
SpringのBeanのスコープ理解不足から発生した問題。
複数ユーザーが同時にPDFファイルをダウンロードした際に、異なるユーザーのファイルが取得される事象が発生。

### 問題の影響
- ユーザーA: 発注書をダウンロード要求
- ユーザーB: 見積書をダウンロード要求（同時刻）
- 結果: ユーザーAに見積書が誤って配信

## 原因: スコープ設定の誤り

### 問題のあるコード構造
```java
@Component  // デフォルトでsingleton
public class FileBean {
    // クラス変数でファイルパスを保持
    private String downloadFilePath;  // スレッドセーフでない

    public void setDownloadFilePath(String path) {
        this.downloadFilePath = path;
    }

    public void downloadFile() {
        // downloadFilePathを使用してファイルをダウンロード
    }
}
```

### 設計上の問題点
1. シングルトンBeanでの状態保持
   - デフォルトのシングルトンスコープを使用
   - クラス変数で状態を保持
   - 複数スレッドで共有される変数が保護されていない

2. スレッドセーフ性の欠如
   - 並行アクセスに対する考慮がない
   - 変数の可視性が適切に制御されていない

## SpringのBeanスコープ解説

https://spring.pleiades.io/spring-framework/reference/core/beans/factory-scopes.html

| スコープ | 説明 | 用途 |
|----------|------|------|
| singleton | コンテナごとに1インスタンス | 状態を持たないサービス |
| prototype | 取得ごとに新規インスタンス | 状態を持つ必要がある場合 |
| request | HTTPリクエストごとに1インスタンス | リクエスト固有の処理 |
| session | HTTPセッションごとに1インスタンス | ユーザー固有の処理 |
| application | ServletContextごとに1インスタンス | アプリケーション共通処理 |

## 正しい実装パターン

### 1. スコープの適切な設定
```java
@Component
@Scope("prototype")  // または @RequestScope
public class FileBean {
    private String downloadFilePath;
    // ... 他のメソッド
}
```

### 2. スレッドローカル変数の使用
```java
@Component
public class FileBean {
    private ThreadLocal<String> downloadFilePath = new ThreadLocal<>();
    
    public void setDownloadFilePath(String path) {
        downloadFilePath.set(path);
    }
    
    public String getDownloadFilePath() {
        return downloadFilePath.get();
    }
    
    public void clearDownloadFilePath() {
        downloadFilePath.remove();  // 重要: リソースの解放
    }
}
```

### 3. メソッドパラメータでの受け渡し
```java
@Component
public class FileBean {
    public void downloadFile(String filePath) {
        // filePathを直接使用
    }
}
```

## 実装時の注意点

1. シングルトンBeanの原則
   - 状態を持たない設計を心がける
   - 必要な状態は適切なスコープで管理

2. スレッドセーフ性の確保
   - 共有リソースへのアクセスを保護
   - 適切な同期メカニズムの使用
   - 不変オブジェクトの活用

3. リソース管理
   - ThreadLocalを使用する場合は確実な解放
   - メモリリークの防止

## 参考文献
https://docs.spring.io/spring-framework/reference/core/beans/factory-scopes.html

https://docs.oracle.com/javase/8/docs/api/java/lang/ThreadLocal.html
CircleCI + AWS(StepFunctions)でmigrationの成功を待つ

## 経緯
- CircleCIの[update-service](https://circleci.com/developer/ja/orbs/orb/circleci/aws-ecs#commands-update-service)を使って、Fargateにデプロイするのですが、migrationを事前に実施したくなります。

## 実現方法

| 環境 | 内容 |
|:---|:---|
|AWS | migration用のタスク定義 + StepFunctionsのStateを作成　|
|CircleCI|migration用のStepFunctionsを起動し、実行ステータスを監視|


### migration用のタスク定義
- 基本的にはfargate（web）のタスク定義と同じです。 

### migrationを実行するStepFunctionsのstates
- Railsだと以下のようにコマンドを書いておきます。
```json
"Overrides": {
  "ContainerOverrides": [
    {
      "Name": "app",
      "Command": ["bundle", "exec", "rails", "db:migrate"]
    }
  ]
}
```
※　migration専用のState＋CloudwatchLogのロググループを用意しておくと障害の時に探し易くなります。

### CircleCI側で実行ステータスを監視
- 以下のようなコマンドを用意して、jobの中で呼び出せば、migrationが完了した後に、fargateへのデプロイを実行できます。

```yaml
commands:
　　start_migration:
　　　　　parameters:
 　　　　 state_machine: { type: string }            
　　　　steps:
    - aws-cli/setup
    - run:
        name: Start State machine
        command: |
            EXECUTION_ARN=$(aws stepfunctions start-execution \
              --state-machine-arn arn:aws:states:${AWS_DEFAULT_REGION}:${AWS_ECR_REGISTRY_ID}:stateMachine:<< parameters.state_machine >>\
              | jq -r ".executionArn")

            STATUS="RUNNING"
            while [ "$STATUS" = "RUNNING" ]
            do
              echo "実行中..."
              sleep 10s

              STATUS=$(aws stepfunctions describe-execution --execution-arn ${EXECUTION_ARN} | jq -r ".status")
            done

            echo "STATUS=${STATUS}"
            if [ "${STATUS}" != "SUCCEEDED" ]; then
              exit 1
            fi

```

## 参考
- https://circleci.com/developer/ja/orbs/orb/circleci/aws-ecs#commands-update-service
【Rails】メモ化

- 一度呼び出されてから結果が変わらないものはメモ化してしまう
  - 呼び出されるたびにロジックやSQLが実行されるのを防ぐため、実行結果を丸々キャッシュする

```sample1.rb
def target_member
  @member ||= Member.find(rand(10))
end

p target_member # <Member id: 5, name: "Five">
p target_member # <Member id: 5, name: "Five">
```


```sample2.rb
def invoice?
  @invoice ||= pay_date >= Time.new(2023, 10, 1)
end
```

`||=`により
- **nil** または**false**であれば、右辺を代入する
- **nil** または**false**以外であれば、2回目以降の呼び出し時は変数に格納された値を実行する


:::note
メモ化によって再実行を避けることが出来る為、**特にコストの高い計算** や、**データベースアクセス** といった場合においてパフォーマンスの向上が期待できる。
:::
WScript.Shellオブジェクトについてのメモ

AIにVBAから外部プログラム（batファイル）を動作させるために聞いてみたことのメモ

・外部プログラムを実行するために、CreateObject("WScript.Shell").ExecとCreateObject("WScript.Shell").Runの両方とも使用することができる

・CreateObject("WScript.Shell").Execメソッドは、外部プログラムを実行し、そのプロセスにアクセスするためのオブジェクトを返す。このオブジェクトを使用することで、プロセスの標準入力、標準出力、および標準エラー出力にアクセスすることができる

・CreateObject("WScript.Shell").Runメソッドは、外部プログラムを実行し、そのプロセスIDを返す
ただし、このメソッドではプロセスの標準入力、標準出力、および標準エラー出力にアクセスすることはできない


【動作確認用】

```TestExecMethod.
Sub TestExecMethod()
    ' WScript.Shellオブジェクトの作成
    Dim wsh As Object
    Set wsh = CreateObject("WScript.Shell")
    
    ' Execメソッドを使用してbatファイルを実行
    Dim exec As Object
    Set exec = wsh.exec("test.bat")
    
    ' 標準出力からデータを読み取り
    Dim output As String
    output = exec.StdOut.ReadAll
    
    ' 結果を表示
    MsgBox output
End Sub
```

```TestRunMethod.
Sub TestRunMethod()
    ' WScript.Shellオブジェクトの作成
    Dim wsh As Object
    Set wsh = CreateObject("WScript.Shell")
    
    ' Runメソッドを使用してbatファイルを実行
    wsh.Run "test.bat", vbNormalFocus, True
    
    ' 結果を表示（標準出力は取得できない）
    MsgBox "Done"
End Sub
```

このVBAファイルには、TestExecMethodとTestRunMethodという2つのサブプロシージャが含まれています。TestExecMethodサブプロシージャは、Execメソッドを使用してbatファイルを実行し、その標準出力からデータを読み取ります。一方、TestRunMethodサブプロシージャは、Runメソッドを使用してbatファイルを実行しますが、標準出力からデータを読み取ることはできません。

これらのサブプロシージャを実行すると、それぞれがbatファイルを実行し、その結果が表示されます。ただし、Execメソッドでは標準出力からデータを読み取ることができますが、Runメソッドでは標準出力からデータを読み取ることができません。

以上が、CreateObject("WScript.Shell").ExecとCreateObject("WScript.Shell").Runの違いを確認するためのVBAファイルとbatファイルの例です。どうぞよろしくお願いします。
Ionic/Angular/SQLiteとcordova(Android)

AndoroidモバイルアプリでSQLiteにデータを格納したく、サンプルアプリを作ってみました。
他のWebサイトでも多くの先輩方が掲載をしてくださっていましたので参考にさせていただきました。
今回は、今現在最新のバージョンでサンプルアプリを作成してみました。
ソースコードはGithubに公開していますのでなにかの参考にしていただければ幸いです。

## ライブラリのバージョン
* ionic/angular Version 7
* Angular version 16
* Ionic version 7
* cordova plugin SQLite database version 6.4
* cordova SQLite Porter version 6.4

:::note
動作確認はAndroidのエミュレータを使用します。
:::

## 主な機能
* アプリ起動時のデータベースファイルの作成（サンプルレコードのINSERT）
* Person情報の登録、更新、削除

## UI/画面構成
* Person一覧画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3514304/6895fa0c-6fb2-8b9d-8a98-49a739fa139a.png)

* 特定のPerson編集画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3514304/e6af1745-341c-8a16-46b7-5c4b65d3e653.png)


##  起動方法
* Android プラットフォームを追加します。
```
> npm install -g ionic cordova
> npm install
> ionic cordova platform add android
```
* ビルドします。
```
> ionic cordova build android
```
* Androidエミュレータを起動します。
```
> ionic cordova emulate android
```

## ソースコード
こちらからダウンロードすることができます。
Github : [Ionic7-Angular16-SQLite](https://github.com/qiita-mobileapps/ionic7-angular16-SQLite)

以上です。
RAMLで道を切り開く：API設計の最初の一歩

# はじめに
みんなさん、こんにちは。
今回はRAMLについて、紹介していきたいと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343120/b789d130-d22c-1647-ee05-2fb2badd3991.png)

# RAMLとは
RAMLは、Anypoint Plarform上RESTful APIを設計する言語です。
YAMLベースで、APIの設計、構築、テスト、ドキュメンテーションを行うことができます。

# そもそもなんでRAMLが必要なのか
結論から申し上げますと、三つあると考えております。

1. **設計優先の思考**： コードの実装前に潜在的な設計問題を特定し、対処することができます。

2. **広い範囲の可読性**： 開発者、プロジェクトマネージャー、ステークホルダーなど、誰でもAPIの振る舞いを容易に理解することができます。

3. **自動化されたドキュメンテーション生成**： RAMLはAPIのドキュメンテーションを生成するために使用できます。これにより、APIの使用者がAPIを理解し、使用するのがより容易になります。

4. **実装前にセキュリティが設定できる**： RAMLをExchangeにパブリッシュ後、直接API Managerと紐付けるため、セキュリティ関連の設定も同時にできるので、更に工数削減ができます。

これにより、RAMLがないと、直接Anypoint Studioにで実装を飛び込んでしまうと、潜在問題の発見が遅くなり、余計な工数がかかってしまいます。建築物の設計図みたいなもので、Mulesoftに不可欠な存在です。

# RAMLの作成手順
https://qiita.com/qiguang-fang/items/947fddff49edc5dd8ef3
# 書き方
HP:
https://raml.org/developers/raml-200-tutorial

各コンポーネント：
**Data Type:**  データ型フラグメントは、APIで使用する特定のデータ構造を定義します。これらは一般的にJSONまたはXMLスキーマで表現され、リクエストやレスポンスのボディで利用されます。

**Security Schemes:**  セキュリティスキームフラグメントは、APIがサポートする認証メソッド（OAuth、Basic認証など）を定義します。これはAPI全体、または特定のエンドポイントに対するセキュリティ要件を表現します。

**Traits:** トレイトフラグメントは、APIエンドポイントに共通の特性や振る舞いを定義します。これはエラーメッセージ、ページネーション、レート制限などの一般的なパターンを再利用可能にします。

**Resource Types:**  リソースタイプフラグメントは、API内の特定のリソース（エンドポイント）の振る舞いを定義します。リソースタイプは、特定のリソースのGET、POST、PUT、DELETEなどのHTTPメソッドの振る舞いを一元的に定義します。

**Examples:**  例フラグメントは、特定のリクエストまたはレスポンスの具体的な例を提供します。これは一般的にAPIドキュメンテーションで使用され、開発者がAPIの使用方法を理解するのに役立ちます。

**Annotation Types:** アノテーションタイプフラグメントは、API定義にメタデータを追加するために使用されます。これにより、ドキュメンテーション、ツール、ライブラリなどに追加情報を提供できます。

**Library:** ライブラリフラグメントは、再利用可能な要素（データ型、トレイト、リソースタイプなど）をグループ化します。ライブラリは他のRAMLドキュメントから参照され、再利用されます。

**User Documentation:** ユーザードキュメンテーションフラグメントは、APIの使用方法に関する情報を提供します。これは一般的に非技術的なユーザーに対する説明や、APIの背後のビジネスロジックを説明するために使用されます。

# デモリンク
https://github.com/qiguang-fang/raml-demo

# 終わりに
最後までお読みいただき、本当にありがとうございました。
RAMLに関する、すこし理解できましたら嬉しいです。フィードバックが頂きましたら幸いです。
Dockerを使ったReact+Express+MySQLのCRUDアプリの作成


# 目的
Dockerを使用した開発を行ったことがなかったので、
一からdockerを使用し環境構築をし、
React+Express+MySQLを使用したCRUDアプリ作成を行いました。

# 開発環境
* Windows10（WSL2）
* DockerDesktop

# 使用フレームワーク
* Express
* React
* MUI
* MySql2
* axios
* react-modal
※くわしくはpackage-lock.jsonを参照

# ソースコード
https://github.com/link9080/ReactProject

# ファイル構成
以下構成でプロジェクトを作りました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2214838/e39d86d1-2615-9b70-23eb-7dc653eb6ccb.png)
* api
Expresソースフォルダ
* db
DDLやMySQL設定ファイル
* react
Reactソースフォルダ
* .envファイル
環境変数

# 画面
ユーザー一覧
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2214838/138dfc25-3a26-c79f-ffe1-48987d29a2af.png)

ユーザ作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2214838/3936c134-5f60-58ac-f3cf-402075573311.png)

ユーザー編集・削除
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2214838/e7bd6a09-6f3e-2b75-1ca4-67677b17d117.png)

デザインはmuiの基本構成を丸パクリで作成しました。
簡単な記述で、整ったデザインになるので
デザインセンスのない自分にとっては助かりました。

作成・編集はモーダル画面で作成をしました。
react-modalを使えば
とても簡単にモーダルを作ることができました。
```javascript:index.js
import Modal from "react-modal";
import New from './new/new';
<div>
    <Modal
    isOpen={modalIsOpen}
    onRequestClose={closeModal}
    style={customStyles}
    contentLabel="Example Modal"
    >
      <New  setIsOpen={setIsOpen} />
    </Modal>
</div>

```
とすることで、new.jsxの内容をモーダル表示することができます、
表示は、ユーザー一覧のユーザー追加を押下することで
modakISOpenのstateをonClickイベントで、trueに変更することで
表示処理が動く様になってます。

# 躓いた点

* Dcoker環境でのDBホスト指定
Docker環境以外の場合は、localhostにDBを立てている場合は、
```javascript:index.js
  host: 'localhost',
  user: 'username',
  password: 'password',
  database: 'appname'
```
の設定で接続できるが、
Dockerの場合は挙動が異なるため、
apiのコンテナからdbのコンテナを指定する場合は
```javascript:index.js
  host: 'ｄｂ',
  user: 'username',
  password: 'password',
  database: 'appname'
```
とコンテナ名を指定する必要がありました。

# 開発をおこなって
dockerの環境構築はネットの情報を参考につくったので
一度作ってしまえばとくに迷うことはなかったです。

今回はすべてJavaScriptをつかって開発してみようと、
api部分はnode.jsのExpressを使用し
JSXの記述もはじめて挑戦しましたが、
最初はこの記述がどうhtmlになるのか理解ができていなかったです。。

書いていくとだいたい分かってきて、応用がきくようになってきました
今後もいろいろ拡張して機能を作っていきたいです。
Laravelを学んでいるエンジニアがPHPの基礎を勉強する

![PHP](https://upload.wikimedia.org/wikipedia/commons/2/27/PHP-logo.svg)

## はじめに
私は普段、Laravelを使ってWebアプリケーションを開発していますが、PHP自体をきちんと勉強したことがあまりありませんでした。そこで、プログラミングPHP 第4版というオライリーの書籍を手に取り、PHPの基礎を学ぶことにしました。

## 今日学んだこと
今日は字句構文や変数、配列の基本について学びました。

## 初めて知ったこと

### 1. 可変変数
PHPでは可変変数という特殊な機能があります。これは、変数の中身の値を別の変数として利用できるというものです。以下に簡単なコード例を示します。

```
$foo = 'bar';
$$foo = 'Hello, World!';

echo $bar; // 出力結果: Hello, World!
```

この例では、<code>$foo</code>の値が<code>bar</code>であり、それを可変変数として利用して新しい変数<code>$bar</code>を作成しています。そして<code>$bar</code>の値を出力しています。このような機能は他の言語ではあまり見られないもので、ちょっとした驚きでした。

### 2. sortとasortの違い
配列をソートする際、<code>sort</code>関数と<code>asort</code>関数がありますが、これらの違いを学びました。

- <code>sort</code>: 配列の要素を昇順にソートしますが、キーと値の関係が崩れ、要素のインデックスが振り直されます。
- <code>asort</code>: 配列の要素を昇順にソートしますが、キーと値の関係が保持され、要素のインデックスは変更されません。

以下は、<code>sort</code>と<code>asort</code>の使用例です。

```
$fruits = array('banana', 'apple', 'orange');
sort($fruits);
print_r($fruits); // 出力結果: Array ( [0] => apple [1] => banana [2] => orange )

$colors = array('c' => 'blue', 'b' => 'green', 'a' => 'red');
asort($colors);
print_r($colors); // 出力結果: Array ( [a] => red [b] => green [c] => blue )
```

## 今後の展望
引き続きPHPの基礎知識を身につけて、近いうちに簡単なWebアプリケーションを作成してみたいと思っています。これからも学習の記録を大切にし、成長していく姿を振り返れるようにしたいと思います。
ありがとうございました。
【Rails】DRYなコード

# DRY原則－二重化の過ち
`DRY原則`（**Don't Repeat Yourself** = 繰り返しを避けること）

:::note
システム内の二重化を最小限に抑えることを目的としている
:::

:::note warn
DRY原則を破るということは、同じ知識を2箇所以上に記述すること。
この場合、片方を変更するのであれば、もう片方も変更しなければいけなくなる。
:::

開発自体の理解とメンテナンスを容易にする唯一の方法は、DRY原則に従うこと。
「すべての知識はシステム内において単一、かつ明確な、そして信頼できる表現になっていなければならない」

:::note
既にあるものを簡単に見つけ出して再利用できるようにし、同じものを何度も作成しないような環境を構築すること
:::


# 重複しているクエリを修正する

## 最後の条件だけ違うパターン

```共通コード.rb
transaction_arel      = Transaction.arel_table
credit_arel           = Credit.arel_table
shop_arel             = Shop.arel_table
shop_association_arel = ShopAssociation.arel_table

# 条件
condition_shop = ... # ここ

credit = Credit
           .joins(:transaction)
           .where(credit_arel[:member_id].eq(nil))
           .where(condition_shop)
```

```修正前.rb
if sample?
  condition_shop = Shop
                     .joins(:shop_associations)
                     .where(shop_arel[:identifier].eq(SAMPLE_IDENTIFIER))
                     .where(shop_association_arel[:shop_id].eq(transaction_arel[:shop_id]))
                     .exists
else
  condition_shop = Shop
                     .joins(:shop_associations)
                     .where(shop_arel[:identifier].eq(SAMPLE_IDENTIFIER))
                     .where(shop_association_arel[:shop_id].eq(transaction_arel[:shop_id]))
                     .exists.not
end
```

```修正案1.rb
shop = Shop
         .joins(:shop_associations)
         .where(shop_arel[:identifier].eq(UNIQLOPAY_IDENTIFIER))
         .where(shop_association_arel[:shop_id].eq(transaction_arel[:shop_id]))

condition_shop = sample? ? shop.exists : shop.exists.not
```

```修正案2.rb
condition_shop = Shop
                   .joins(:shop_associations)
                   .where(shop_arel[:identifier].eq(UNIQLOPAY_IDENTIFIER))
                   .where(shop_association_arel[:shop_id].eq(transaction_arel[:shop_id]))
                   .exists

condition_shop = condition_shop.not unless sample?
```

:::note
Shopモデルに対するクエリの定義が重複せず、コードが簡潔になる。
:::


## 途中の条件が違うパターン
```修正前.rb
if sample?
  contracts = contract_arel
                .project(contract_arel[column_name], contract_arel[:start_date].maximum.as('start_date'))
                .group(contract_arel[column_name])
                .as('contracts')
else
  contracts = contract_arel
                .project(contract_arel[column_name], contract_arel[:start_date].maximum.as('start_date'))
                .where(contract_arel[:start_date].lteq(target_date))
                .group(contract_arel[column_name])
                .as('contracts')
end
```

```修正後.rb
contracts = contract_arel.project(contract_arel[column_name], contract_arel[:start_date].maximum.as('start_date'))
contracts = contracts.where(contract_arel[:start_date].lteq(target_date)) unless sample?
contracts = contracts.group(contract_arel[column_name]).as('contracts')
```

:::note
- クエリの定義が重複していない。
- 条件結果の結果に応じてクエリの一部を条件付きで追加している。
:::

# 関連
- [【メモ】達人プログラマー](https://qiita.com/reraise/items/7d50140718ffe7650e24)
[SQL] SELECT文でWHEREを使う

# はじめに
- SQLの学習に着手したので、SELECTとWHEREを中心にまとめておく
- SQL入門1日目

# SELECT
```SQL
SELECT カラム1, カラム2, カラム3
FROM テーブル名
```
このようにして、テーブルからカラムを取得する

##### [カラムを計算する]
前提：gdp（国民総生産）とpopulation（人口）についてのカラムがある
###### ①gdp/population（国民一人当たりの国内総生産）として取得できる
```SQL:例
SELECT (gdp/population) FROM world
```

###### ②数値で割ることも可能
```SQL:例
SELECT population/1000000 FROM world
```

###### ③端数を丸めることができる
`ROUND(カラム/数値, 桁数)`
```SQL:例
SELECT ROUND(population/1000000,2） FROM world
```
意味：人口（100万人単位）を小数点以下2桁

# SELECT文におけるWHERE
##### WHEREについていくつかまとめておく

##### [比較演算子]
```SQL
SELECT カラム
FROM テーブル
WHERE 条件 = 1000
```
`条件 = 数値`とすれば良い
>意味
「=」両辺等しい
「<」右辺が大きい
「<=」右辺が大きいか両辺が等しい
「>」左辺が大きい
「>=」左辺が大きいか両辺が等しい
「<>」両辺が等しくない

##### [IN/NOT IN演算子]
```SQL
SELECT カラム
FROM テーブル
WHERE カラム IN ( '値1', '値2', '値3')
```
指定のカラムの値が指定の値のいずれかと合致するレコードを抽出
`NOT IN`の場合は、一致しないレコードを抽出

##### [LIKE文]
```SQL
SELECT カラム
FROM テーブル
WHERE カラム LIKE ’％任意の文字列％’
```
任意の文字列を含むレコードの指定

##### [OR/AND]
```SQL
SELECT カラム
FROM テーブル
WHERE 条件 OR 条件

SELECT カラム
FROM テーブル
WHERE 条件 AND 条件
```

###### 排他的論理和も可能
前提：area（面積）とpopulation（人口）についてのカラムがある
```SQL:例
SELECT カラム
FROM テーブル
WHERE (area >= 3000000 AND population < 250000000) OR (area < 3000000 AND population >= 250000000)
```

次のいずれかを満たす（*いずれかしか満たさない）
- 面積が3000000以上
- 人口が250000000以上

##### [LENGTH関数]
前提：first_nameとfamily_nameについてのカラムがある
```SQL
SELECT カラム
FROM テーブル
WHERE LENGTH(first_name) = LENGTH(family_name)
```
文字数が同じレコードを抽出

# 最後に
⚠️学習4ヶ月目の初学者による投稿です。
⚠️間違いがあるかもしれません。ご容赦ください。
⚠️ご指導、ご教授いただけると幸いです。
今流行の分散型SNS 「Threads」


<h1>今流行の分散型SNS 「Threads」

今回はなぜThreadsが分散型SNSの一員になろうとしているのか、歴史をもとに調べてみました




巷で話題のThreadsは現在twitterの代替物として、Metaがリリースしているアプリである。その急速な伸びもさることながら、そこにはさまざまな思いや工夫が込められている。

「優しさが集まる空間にしたい」とMetaはいう。そのために、政治の話や時事ニュースがアルゴリズムでおすすめされにくくされている。そしてより注目しているのが分散型SNSに参加しようという動向である。分散型SNSとは、中央集権的なTwitter、Instagramのような一つの企業のサービス、サーバーで運用され情報をすべて支配している形態とは違い、脱中央集権を目的としたSNSである。

「activityPub」という通信プロトコルを利用することで、サーバー間で相互に通信できる。そのため、ユーザーに応じたサーバーが多数存在し、ユーザーの自由をより体現しようと試みが行われている。
もちろんデメリットもあり、OSS(オープンソースソフトウェア)ということもあり、マネタイズやサーバー維持、セキュリティなど難しい点である。そのため、この分散型SNSを維持することは難しい。

分散型SNSとはよりユーザーの自由度を高めるために生まれたものだ。そういった中にThreadsを運用するGAFAの一角、Metaが分散型SNSに参加するというのは非常に心強くより自由を促進すると期待する声もあるが、僕はそうはとらえていない。

 歴史を辿るとこのようなオープンスタンダードな技術を大手企業が採用し、独自に改良した後に中央集権的な形に変え、オープンスタンダードの技術を本来の思想と目的の意に反することをすることがある。

例えば、GoogleとXMPP（Extensible Messaging and Presence Protocol）の関係がそうである。Googleが2005年にGoogle Talkをリリースし、XMPPというプロトコルを用いて開発を進めていたが、ある日、Google はXMPPとは別のプロトコルを独自に作り、新たなサービスを提供し、XMPPのサポートを段階的に打ち切った。最初は大手企業の参入によりオープンスタンダードな技術が広く使われていたが、大手企業がそこに改良を加えて新たなプロトコルをもとにサービスを提供したことで、XMPPは急速に落ちてしまい、XMPPの思想を踏襲せず利用した形となった。

そのように大手企業がオープンスタンダードなものに同調していたにも関わらず、独自に拡張しより差別化したサービスを提供するという本来の目的とは異なることをすることは今回のThreadsがactivityPubプロトコルを利用することにも同様の現象が起こるように考えられる。そのため我々は、Metaの動向を注視する必要があり、オープンスタンダードの使用方法に公正かつ透明な行動をとることを求める必要がある。
いいコード悪いコードまとめ14章モデリング　リファクタリング　既存コードを成長に導く技

# 条件は読みやすいか
以下のように論理否定を使ったりすると読み替えるのが面倒
```
if customer.isEnabled?
if !customer.isEnabled?
```
したがって以下のように書き換える
```
if customer.isEnabled?
if customer.isDisabled?
```

# ベタ書きロジックを目的を表すメソッドに置き換えているか
以下のように書いていると、理解に手間がかかる
```
if customer.posessionPoint.amount < comic.currentPurchasePoint.amount
```
したがって、以下のようにメソッドを用意すれば可読性が上がる。
```
def isShortofPoint(comic)
  return customer.posessionPoint.amount < comic.currentPurchasePoint.amount
end
```
# テストを使用しよう
テストコードを用いたリファクタリングの流れ
1. あるべき構造の雛形クラスをある程度作る
2. 雛形に対してテストコードを書く
3. テストを失敗させる
４. テストを成功させるための最低限のコードを書く
5. 雛形クラス内部でリファクタリング対象のコードを呼び出す
6. テストが成功するようあるべき構造へロジックを少しずつリファクタリングしていく

# 仕様化テスト
実際の現場では仕様がわからない開発も多々あります。そのような場合、仕様化テストが１つの有効な手段。

分析したいメソッドのテストを書き、そのメソッドがどんな挙動を示すかを明らかにする方法
いくつかメソッドに対するテストをかき、その結果からどのような挙動が類推し理解する。

# IDEのリファクタリング機能
リネームやメソッド抽出などを利用してリファクタリングに活用する。

# 機能追加とリファクタリングを同時にしていないか
バグが発生した場合問題の切り分けが難しくなったり、コミットの目的が分からなくなったりするので同時にやることは避ける。
【Elixir/Phoenix】AI対戦4目並べを作る（完成編）


[【Elixir/Phoenix】AI対戦4目並べを作る（AIの動作チェック編）](https://qiita.com/GeekMasahiro/private/09c96ccb8da13e445d70)で動作確認したAIの対戦相手を、GUIに組み込みます。

AI部分もGUI部分もElixirで記述されているので、簡単に組み込むことができます。

# Nx/Axonのモジュールを追加

```elixir:mix.exs
  defp deps do
    [
      {:phoenix, "~> 1.7.0-rc.0", override: true},
      {:phoenix_ecto, "~> 4.4"},
      {:ecto_sql, "~> 3.6"},
      {:ecto_sqlite3, ">= 0.0.0"},
      {:phoenix_html, "~> 3.0"},
      {:phoenix_live_reload, "~> 1.2", only: :dev},
      {:phoenix_live_view, "~> 0.18.3"},
      {:heroicons, "~> 0.5"},
      {:floki, ">= 0.30.0", only: :test},
      {:phoenix_live_dashboard, "~> 0.7.2"},
      {:esbuild, "~> 0.5", runtime: Mix.env() == :dev},
      {:tailwind, "~> 0.1.8", runtime: Mix.env() == :dev},
      {:swoosh, "~> 1.3"},
      {:finch, "~> 0.13"},
      {:telemetry_metrics, "~> 0.6"},
      {:telemetry_poller, "~> 1.0"},
      {:gettext, "~> 0.20"},
      {:jason, "~> 1.2"},
      {:plug_cowboy, "~> 2.5"},
      {:axon, "~> 0.2.0"},
      {:exla, "~> 0.3.0"},
      {:nx, "~> 0.3.0"},

    ]
  end
```

# DQNの処理ファイルを追加

lib/phx_gomoku/dqn.ex
lib/phx_gomoku/q_net.ex
gomoku-qnet-5x5-4-200k.axon
など、AI側の処理に必要なファイルを追加します。


# イベントハンドラーの変更

```Elixir:lib/phx_gomoku_web/live/gomoku_live.ex
  def handle_event("clicked", %{"x" => x, "y" => y}, socket) do
    x = String.to_integer(x)
    y = String.to_integer(y)
    socket = socket
     |> turn_human({y, x})
     |> turn_ai()
    {:noreply, socket}
  end
```

turn_aiは、Dqn.get_action()を呼び出して得られた位置に石を置きます。

```Elixir:lib/phx_gomoku_web/live/gomoku_live.ex
  def turn_ai(socket) when socket.assigns.ai_turn == socket.assigns.board.turn do
    update(socket, :board, &turn_ai(&1, socket.assigns.q_net))
  end

  def turn_ai(socket) do
    socket
  end

  def turn_ai(%Gomoku{done: true} = gomoku, _q_net) do
    gomoku
  end

  def turn_ai(%Gomoku{done: false} = gomoku, q_net) do
    pos = Dqn.get_action(gomoku, q_net)
    Gomoku.put!(gomoku, pos)
  end
```

# まとめ

- 強化学習で作成した対戦相手と対戦できる、四目並べを作成する事が出来た。
- Liveviewの動的なHTMLのレンダリングにより、盤面の表示を簡単に行えた。
- 対戦相手部分がゲームエンジンと同じElixirで記述されているので、プロジェクトへのファイルコピーレベルで、結合できた。
- Javascript/Pythonを使う方法がありがちだが、Elixirだけでもできることを確認できた。

# 関連記事

https://qiita.com/GeekMasahiro/items/0cc62af5bcc67cbb2b3e

https://qiita.com/GeekMasahiro/items/68396a71aa9408a1c485

https://qiita.com/GeekMasahiro/items/09c96ccb8da13e445d70

https://qiita.com/GeekMasahiro/items/603f1f845018988ec7a7
JavaScriptの連想配列の要素を合計した配列を返す

次のような連想配列を１つの配列にまとめ、キーごとに要素をまとめたい場合にどうすればいいのか、少し悩んだのでその方法を残しておきます。

```
////////////////////////
// Before
////////////////////////
facet: {
 apple: {
  '1': 10,
  '2': 20
 },
 orange: {
  '1': 30,
  '2': 40,
  '3': 50
 }
}

////////////////////////
// After
////////////////////////
[
 {
  'id': '1',
  'sum': 40 // 10+30
 },
 {
  'id': '2',
  'sum': 60 // 20+40
 },
 {
  'id': '3',
  'sum': 50 // 50
 }
]
```

今回は `JavaScript` で実現するので、何かと便利な `lodash` を使います。
`_.transform(..)` を使うことで連想配列を配列に変換し、内部でキーの比較を行っています。

```
_.chain(facet)
  .transform((result, value) => {
    _.forEach(value, (v, k) => {
      if (result[k]) {
        result[k].sum += v;
      } else {
        result[k] = {
          id: k,
          sum: v ? v : 0
        };
      }
    });
  })
  .sortBy([ 'id' ])
  .value();
```

それなりにシンプルに作れましたが、もっとよい方法があったらコメントください。
docker + nextjs + React + typescriptで開発環境を整える

# 開発環境を作る

## dockerでnodeの開発環境を作成する

### 任意のフォルダの以下のsrcディレクトリとdocker-compose.yamlを作成する

#### 以下の作業はWindows上の作業
--
 ├ src/
 ├ docker-compose.yaml
 
```docker-compose.yaml
version: '3'

services:
  app:
    image: node:lts # バージョン指定も可能 ex. node:12.16.1
    container_name: nextExpressTest  # コンテナ名は任意
    environment:
            - DEBUG=app:*
    tty: true
    # ホスト側のポート：コンテナのポート
    ports:
            - '3000:3000'
    # ホスト側のsrcをコンテナのappにマウント
    volumes:
      - ./src:/app
    working_dir: "/app"
    # 起動後に実行するコマンド
    # command: npm run dev
```

## Git等からnextjsのプロジェクトを取得する場合

### Gitからプロジェクトを取得
srcディレクトリ以下に移動する
```
>cd src
```

gitからnextjsプロジェクトを取得する
```
>git clone https://github.com/HKurakami/nextjs-app.git
```

### コンテナの起動とシェルの起動
```
>docker-compose up -d            コンテナの起動
>docker-compose exec app bash    シェルの起動

# node --version
v18.14.0
上記の様にnodeのバージョンが表示されればOK（バージョンは2203/2/16現在）
```

#### ここからはdockerのlinuxでの作業
取得したnextjsのプロジェクトディレクトリへ移動して、npm install する

```
# cd nextjs-app/
# npm install
```

nextjsのプロジェクトを起動する
```
# npm run dev
```

http://localhost:3000
へアクセスして、nextのデフォルトページが表示されればOK

## 新規にnextjsのプロジェクトを作成する場合

### コンテナの起動とシェルの起動

```
>docker-compose up -d            コンテナの起動
>docker-compose exec app bash    シェルの起動

# node --version
v18.14.0
上記の様にnodeのバージョンが表示されればOK（バージョンは2203/2/16現在）
```

### TypeScriptを適用したnextjsのプロジェクトを作成する
＊プロジェクト名には大文字が含まれるとエラーになるので注意
```
# npx create-next-app --typescript newproject

# cd newproject
# npm run dev
```

http://localhost:3000
へアクセスして、nextのデフォルトページが表示されればOK
いいコード悪いコードまとめ13章モデリング　クラス設計の土台

モデルとは、特的の目的達成のために最低限考慮が必要な要素を備えたもの
# 目的別にモデリングしているか
例えば、Userというモデルだけでは対応できないことが多々ある。Userと言ってもさまざまな性質を持つわけなので、それに応じたモデルを検討すること。

# モデルの見直し
* そのモデルが達成しようとしている目的を全て洗い出す
* 目的それぞれ特化したモデリングをし直す
* 目的駆動名前設計に基づき、モデルに命名する
* モデルに目的外の要素が入り込んでいる場合、さらに見直す

# クラスや実装の中での気づきをモデルにフィードバックしたか
実装を進めたりする中で、モデルの過不足に気づくことは多い。それを必ずすぐに反映させること。

# 設計を繰り返し改良しているか
クラス、メソッド、変数で勘違いが起こらないような命名にするための方法

ソフトウェア開発において誤解を招かないような名前の付け方について、具体的な方法と例を用いて解説します。特に、クラス、メソッド、変数の命名について注目し共有します。

### 1. 抽象的な名前を避ける

明確な名前付けは、コードを読みやすく、保守しやすいソフトウェアを作るための重要な要素です。可能な限り抽象的な名前は避け、何をするためのものなのかを表現できる具体的な名前を選びましょう。

例えば、クラス名にはそれが何を表すのかを、メソッド名には何をするのかを、変数名には何を保持するのかを反映させるようにします。

**良い例:**

クラス名: `UserAccount`, `DatabaseConnection`
メソッド名: `calculateTotalPrice`, `saveToFile`
変数名: `currentTemperature`, `maximumSpeed`

**悪い例:**

クラス名: `Manager`, `Handler`
メソッド名: `process`, `run`
変数名: `data`, `info`

### 2. ドメインの言葉を使う

業務のドメイン（ビジネスルールやその背景となる業界）に基づいた言葉を使用すると、コードがビジネスルールをより正確に表現できます。これにより、他の開発者がコードを理解しやすくなります。

例: `Invoice`、`Inventory`、`ShippingAddress`など

### 3. 長すぎる名前は避ける

名前が長すぎると、その名前をタイプしたり、覚えたり、読んだりするのが困難になります。一方で、名前が短すぎると、その名前が何を表すのかが不明確になる可能性があります。適切なバランスを見つけることが重要です。

### 4. 一貫性を保つ

全体のコードベースで一貫した命名規則を使うことは、コードの可読性と保守性を向上させます。例えば、boolを表す変数には `is` を接頭辞として使用する、配列型の変数には複数形の名前を使用するなど、一貫した規則を設けることが有効です。

開発者間で命名規則について議論し、全員が納得できるガイドラインを作成しましょう。

### 5. 用語の一貫性を保つ

同じ概念に対して、プロジェクト全体で一貫した用語を使用します。たとえば、「ユーザー」を示す場合、一部では「user」、他の部分では「account」、「client」などと表現しないようにします。これにより、混乱を避け、コードの全体的な理解を促進します。

### 6. 名前に情報を含める

変数やメソッドの名前に型情報やスコープ情報を含めると、それがどのように使用されるべきかのヒントを提供できます。例えば、メソッド名に`get`、`set`、`calculate`などの動詞を含めることで、それが何を行うのかを明示できます。

また、`numStudents`や`employeeList`のように、変数名にそのデータ型（数値、リストなど）を含めることも有用です。

### 7. ブール型の変数は肯定形で命名する

ブール型の変数名には肯定形の言葉を使用します。例えば、`isAvailable`、`isEnabled`、`hasPermission`などです。これにより、その変数が`true`である場合の状態が自明になります。

### 8. 名前に具体的な値や単位を含める

数値を扱う変数の場合、その変数名に単位を含めることで、その数値が何を表しているのかを明確にすることができます。例えば、`timeoutMilliseconds`や`weightKilograms`のようにします。

また、特定の範囲や具体的な値を期待する変数名には、その情報を含めます。例えば、`maxAttempts`や`minPasswordLength`のようにします。

### 9. 名前が長くなる場合は略語を使う

名前が長くなりすぎる場合は、一般的に理解できる略語を使うことが有用です。ただし、その略語が共通語として広く理解されていること、またはそのプロジェクト内で一貫して使用されていることを確認してください。

例えば、`HTTP`、`URL`、`ID`などは広く理解されている略語です。しかし、`fn`（functionの略）や`btn`（buttonの略）などの略語は一部の人にしか理解できない可能性があるため、注意が必要です。

### 10. 無意味な単語や冗長な単語を避ける

特に`data`や`info`といった単語は抽象的すぎて、その変数が何を表しているのかが明確でなくなる可能性があります。また、`nameString`や`priceFloat`のように、その変数の型を示す冗長な単語も避けます。代わりに、その変数が何を表しているのかを具体的に示す名前を選びます。

### 11. 不要なコンテキストの排除

クラス、メソッド、変数の名前はそれ自体で自己説明的であるべきですが、それらが所属するクラスやモジュールのコンテキストを繰り返す必要はありません。例えば、`Car`クラスの`getColor`メソッドを`getCarColor`とする必要はありません。ただし、メソッドが親クラスやインターフェースをオーバーライドしている場合は、一貫性のために元の名前を維持することが推奨されます。

### 12. 副作用を明示する

メソッドが副作用を持つ場合（つまり、状態を変更する、ファイルに書き込む、データベースに情報を保存するなど）、それを明示する名前を選びます。これにより、そのメソッドを呼び出す開発者は予期しない副作用に驚かなくて済みます。例えば、`saveChanges`や`deleteUser`などが該当します。

### 13. テストメソッドの名前

テストメソッドの名前には、何をテストしているのかとその期待結果を含めます。これにより、そのテストが失敗したときに何が間違っているのかを容易に理解することができます。例えば、`shouldReturnTrueWhenUserExists`や`doesNotThrowExceptionIfFileNotFound`のようにします。

### 14. コードのリファクタリング

名前付けは一度に完璧に行う必要はありません。初期の開発フェーズでは、すべてが完全に定義されていないかもしれません。その後、コードのリファクタリングの一環として、より良い名前に変更することが可能です。
モダンアクティビティを使ってみた(Excel編Part14～MATCH関数アクティビティ？～)

## はじめに
①本記事は、2023年7月開催の「UiPathブログ 発信チャレンジサマー」の23日目のブログです。
ブログの詳細、参加方法については以下のブログを参照ください。

https://note.com/shumpei_w/n/nd082bdf28853

②このブログ情報は、2023/7時点の情報です。
③UiPathはCommunity Edition、Versionは2023.6.1を使用しています。

## MATCH関数とは
MATCH関数は指定する範囲内から検索値の相対的な位置を数字で出してくれる関数です。
<b>MATCH(検索値,検索範囲,[照合の種類])</b>
検索値：検索したい値を設定します。
検索範囲：調べたい値が入っている検索範囲を設定します。
照合の種類：値が完全一致(0)、検索値以下の最大値*(1)、検索値以上の最小値*(-1)を設定します。
*検索範囲ですが、最大値の時は昇順、最小値の時は降順への並び替えが必要です。

## MATCH関数アクティビティとは...
「MATCH関数」アクティビティはMATCH式をアクティビティで入力できるようにしたものです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/761439f3-0274-2bd0-3482-0060ff601405.png)
## やってみましょう
あるExcelの表があります。
趣味が"プログラミング"の人は、何行目にあるのでしょうか。
※今回は、1行目はヘッダーとしているので範囲に入れません。2行目からカウントします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/6c982fb4-3c3c-bf99-d3bf-8e07fdf36c3a.png)

上記の答えは見えている通りで<b>6</b>行目ですが、6行目はどうやって算出したのかはF5セルを見てみましょう。
F5セルに書いてある式は下記の通りです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/22cd6789-e6b5-99a1-c356-857db17766ef.png)

## プロパティ
では、この式をMATCH関数アクティビティに当てはめると、以下のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/79851be5-73e6-73b6-0165-1051c9c77530.png)
【入力】
検索値：検索したい値です。Object型です。
検索範囲：調べたい値が入っている検索範囲を設定します。
下記は、B2:B11の範囲を設定している場面です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/ac0e6fdc-45e0-911b-2f20-29156c0594ab.png)
照合の種類：等しいのか、最大値、最小値を設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/f32be0e6-3dc1-08ad-0154-9fffc7a8e3df.png)

【出力】
保存先：行数、列数を出力します。変数の型はInt32型です。


## 動かしてみよう
String変数のstrSearchに"プログラミング"が趣味の人が何行目にあるのか調べてみましょう。
今回照合の種類は完全一致(0)で設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/3771b974-db05-baab-87ce-de32ec6b9d0c.png)
結果は...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/740f2357-fb4e-43fd-f57c-1ff83a014b8d.png)
確認してみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/38a71711-05c2-a9b3-453d-3576cbe874ed.png)
このアクティビティだけで行の位置が算出できていますね！

## まとめ
MATCH関数は自分はあまり使わないので、使用する際は毎回あたふたしています。
アクティビティになったことでよりMATCH関数が身近になり、取得した行数・列数はInt32変数に格納できる点は魅力的に移りました。
VLOOKUPもですが、関数が得意でない方にも専用アクティビティの登場は大きな意味があると思っています。

最後までお読みいただきありがとうございました。


## 参考URL
ExcelのMATCH関数の使い方｜検索値の範囲内での相対的な位置を返す

https://office-hack.com/excel/match/
いいコード悪いコードまとめ12章メソッド（関数）　良きクラスには良きメソッドあり

# 自分のクラスのインスタンス変数を使っているか
あくまでも原則だが、他のクラスのインスタンス変数を変更するメソッド構造にしては行けない。変更したいインスタンス変数を持つクラスに変更メソッドを実装しよう。

# コマンド・クエリ分離になっているか
コマンド（変更）とクエリ（問い合わせ）のどちらか一方だけを行うように設計しよう。
同時に行うことをモディファイアといい、避けられないケースもあるが、なるべく避けるようにしよう。

# 引数は可能な限り少なくなっているか
多くなりそうな場合、別クラスへの分割を検討しよう
いいコード悪いコードまとめ11章コメント

# 退化コメントになっていないか
開発が進むにつれて元あったコメントは更新されずに退化していくことが多い。コメントは劣化コピーに過ぎないことを理解しよう。

# ロジック更新時にコメントも更新したか

# 可読性の悪いロジックを捕捉説明するようなコメントを書いていないか
上述の通り、コメントは退化しやすい。メソッド名を改善しよう。

# ロジックの意図や仕様変更時の注意点をコメントしたか

# ドキュメントコメントを使用しているか
YARD,RDocなどrubyでもドキュメントコメントを使用できる。
https://qiita.com/kmats@github/items/0c8919a65afbe18e9e37
オールNVMEで記憶域プールのパリティしたときの速度メモ

WindowsのRAID5相当で使える記憶域スペースのパリティですが、以下のような特徴があります。

:::note info
**メリット**
- リード速度は列数に応じて増加
- 列数を適切に指定すればリードを早めつつ耐障害性が高まる
:::

:::note warn
**デメリット**
- ライト速度は最低速度のSSDの半分になる
- ランダムリードは必ず低下する
:::


ライトが遅いので「ミラーリングによって高速化されたパリティ」といった中間技術が使用されていました。

# SSD単体

今回、これくらいの速度が出るSSDを4枚でパリティディスクを作ります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790864/1c3a7bf3-2125-48a7-d7c2-c4a31254806f.png)
あらかじめGUIで任意の名前で記憶域プールを作ります。

# パリティ

NumberOfColumnsは台数と一致させます。

```.ps1
New-VirtualDisk -StoragePoolFriendlyName パリティプール -friendlyname パリティディスク -Provisioningtype Thin -NumberOfColumns 4 -ResiliencySettingName Parity -size 930GB
```
列数が4なのでシーケンシャル6000くらいはいくかなと思いましたが、伸びませんでした。ライトは半分以下となっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790864/b6212d2a-9a3e-a7d1-496f-ecbf23f3cf6d.png)

# コツ
**パリティによるライトの速度低下は、単体SSDの中での最低速度の半分程度になる**と覚えておくといいです。なので古いSSDやSATA SSDと混ぜて使ったりするのはあまりおすすめできません。

もしシーケンシャルライトが単体で6000Mb/s出るものを使えば、3000程度は期待できるということですね。ちなみにSATA SSDでパリティを作ると上限250Mb/s、HDDだと100程度となります。

# まとめ

- アップルがキャンセルしたYTMCのNANDがダブついているようでNVME全体の価格が急落しているそうです。
- **SATA SSDのメリットがポート数以外になくなってきている**状況です。
- 速度低下を加味しても、オールNVMEでのパリティ記憶域プールが実用的になってきました。


# 参考にさせて頂いたサイト

なんとNVME9枚で記憶域プールを試しています。参考になりますね。
https://blog.one-off.info/?p=4125
シングルトンクラスを作る（SwiftUI）

SwiftUIでシングルトンクラスを作る方法です。

シングルトンクラスとは、アプリ内で一意に存在するクラスのことで、アプリ内のどこからアクセスしてもただ一つのインスタンスを返します。

# EnvironmentObjectとの違い
SwiftUIには、EnvironmentObjectという、どこのViewからアクセスしても同じインスタンスを参照できるプロパティラッパがありますが、あえてシングルトンクラスを作る理由はなんでしょう。

それは、View以外からも参照したいからです。
EnvironmentObjectは、Viewを継承したビュー構造体にしか定義できません。
MVVMで開発している場合で言えば、Model、あるいはViewModelからEnvironmentObjectのインスタンスにアクセスしたいことが出てくるでしょう。そんな時に解決してくれるのがシングルトンクラスです。

# 実装

以下のように定義します。
```swift:Singleton.swift
class Singleton{
    static var shared = Singleton()
    var hoge = "hoge"
}
```
Viewから呼んでみましょう。
```swift:ContentView.swift
struct ContentView: View {
    var body: some View {
        Text("hoge")
            .onAppear(){
                print(Singleton.shared.hoge)
            }
    }
}
```
**結果**
`hoge`

# EnvironmentObject×Singleton

EnvironmentObjectとしても使えるようにするには、ObservableObjectに準拠させれば良いです。
```swift:Singleton.swift
class Singleton: ObservableObject{
    static var shared = Singleton()
    @Published var hoge = "hoge"
}
```
mainスレッドで、EnvironmentObjectとして登録します。
```swift:[プロジェクト名]App.swift
@main
struct FuerMoneyNextApp: App {
    let persistenceController = PersistenceController.shared

    var body: some Scene {
        WindowGroup {
            ContentView()
                .environment(\.managedObjectContext, persistenceController.container.viewContext)
                .environmentObject(Singleton.shared)
        }
    }
}
```
こうすれば、Viewで呼び出したSingletonクラスが更新された際には、自動で再描画してくれます。

今度はEnvironmentObjectとして、Viewで呼び出してみましょう。
```swift:ContentView.swift
struct ContentView: View {
    @EnvironmentObject var env: Singleton
    
    var body: some View {
        Text("hoge")
            .onAppear(){
                print(env.hoge)
            }
    }
}
```
**結果**
`hoge`

ViewModelから呼び出す場合はSingleton.sharedです。
```swift:ContentView.swift
struct ContentView: View {
    @ObservedObject var vm = ContentViewModel()
    
    var body: some View {
        Text("hoge")
            .onAppear(){
                vm.callHoge()
            }
    }
}

class ContentViewModel: ObservableObject{
    func callHoge(){
        print(Singleton.shared.hoge)
    }
}
```
**結果**
`hoge`

超簡単なコードで、両方の使い方ができるので便利です。

終わり
Log Analytics のコストを調べて、コスト削減を図る

## はじめに
Log Analyticsのコストは見積もりづらく、実際に構築したら意外と高額になっていたりなんてことも発生するため
以下のDocsを参考しながら、どこにコストがかかっているかを調べ、実際にコスト削減に向けた手順を備忘のためにまとめる。

https://learn.microsoft.com/ja-jp/azure/azure-monitor/logs/analyze-usage


## 全体の利用量

Log Analyticsで取得しているデータは各テーブルに格納される。

https://learn.microsoft.com/ja-jp/azure/azure-monitor/reference/tables/tables-category

テーブルごとに過去1カ月でどの程度のデータが出力されているかを確認する。

```メモ:各テーブル利用量
search *
| extend Type = $table
| where TimeGenerated > ago(31d)
| summarize AggregatedValue = count() by Type 
| order by AggregatedValue
```

Azureの診断情報の多くが格納される AzureDiagnosticsテーブル
Azure VM（Windows）を構築し、Azure Monitor Agent経由でデータ収集している場合は
Eventテーブル や Security Eventテーブル あたりが上位にあがってくる。

## テーブルごとの利用量

全体の利用量の中で特に格納される情報が多いテーブルについては、テーブルごとに細かく分析してみる。
以下は検出頻度が高いテーブルをサンプルで記載する。

### Event
```メモ:Windows イベントログ 利用量
Event
| where TimeGenerated > ago(31d) 
| summarize AggregatedValue = count() by EventID
| order by AggregatedValue
```
### SecurityEvent
```メモ:Windows セキュリティログ 利用量
SecurityEvent
| where TimeGenerated > ago(31d) 
| summarize AggregatedValue = count() by EventID
| order by AggregatedValue
```
### AzureDiagnostics
```メモ:Azure診断情報 利用量
AzureDiagnostics 
| where TimeGenerated > ago(31d) 
| summarize AggregatedValue = count() by ResourceId
| order by AggregatedValue
```

## コストを削減する方法

各テーブルに格納されている情報が分かったところで実際にログを削減する方法を確認する。

### 保存期間を見直す

Log Analyticsのデータ保持期間を見直すことが一番手っ取り早い。

https://learn.microsoft.com/ja-jp/azure/azure-monitor/logs/data-retention-archive?tabs=portal-1%2Cportal-2#configure-the-default-workspace-retention-policy

企業での利用では監査などの関係で長期にログを保存するケースが多い。
その場合、アーカイブ機能を利用して利用頻度の低いデータをアーカイブ化することでコストが削減できる。

https://learn.microsoft.com/ja-jp/azure/azure-monitor/logs/data-retention-archive?tabs=portal-1%2Cportal-2#set-retention-and-archive-policy-by-table

例えば以下のような設定の場合は90日までが通常のログ検索、それ以降1年以内のログがアーカイブのログ検索で閲覧可能。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2739358/61ee10bf-8c7b-1383-e2f7-12fd56be3426.png)

### 受信データをフィルタリングする

Log Analyticsワークスペースにデータを格納する前にデータの内容をフィルタリングする機能も存在する。
テーブルの中には変換ルールを設定できるものがあり、ここで取得するデータを絞り込むことが可能となる。

https://learn.microsoft.com/ja-jp/azure/azure-monitor/essentials/data-collection-transformations

変換をサポートしているテーブルはこちら。

https://learn.microsoft.com/ja-jp/azure/azure-monitor/logs/tables-feature-support

データを絞り込むことでコストの削減が可能となるが、変換後のデータが一定量を超えるとこれまた課金が発生するので注意。
（ログ データ インジェストと変換 を参照）

https://azure.microsoft.com/ja-jp/pricing/details/monitor/

Azure Monitor Agentを導入している場合は、データ収集ルールを変更することで削減が可能。
いいコード悪いコードまとめ10章悪魔を呼び寄せる名前

目的駆動名前設計：名前から目的や意図が読み取れることを特徴とする

# 命名が関心を分離できているか
例えば、商品というクラスという名前にreservationsやorders、shipmentsなどのような関心ごと全てが含まれていては密結合となりよろしくない。命名したときにこれではカバーする範囲、つまり関心ごとが広すぎる。

したがって、関心の分離をすることが重要。「関心ごと、つまりユースケースや目的、役割ごとに分離する」わけである。

例えば、商品クラスにいろいろなロジックが含まれている場合
予約品、注文品、在庫品、発送品のように分割して行けば良い。

# 大雑把で意味が不明瞭な命名になっていないか
先ほどの商品という名前はさまざまな状況をフォローできそうな名前だが、裏を返せばなんでも欠けてしまうクラスとなり、目的が不明なオブジェクトとなってしまう。

# 命名のポイントを押さえているか？
## 可能な限り具体的で、意味範囲が狭い、特化した名前になっているか
このメリットとしては
* 名前とは無関係なロジックを排除しやすくなる
* クラスが小さくなる
* 関係するクラスの個数が少なくなり、結合度が低減する
* 関係クラスの個数が少ないため、仕様変更時に考慮を要する影響範囲が小さくなる
* 目的に特化した名前なのでどこを変更すればいいかすぐ探し出せる
* 結果として開発生産性が向上する

## 存在ベースではなく、目的ベースの名前になっているか
住所：配送元、再送先に変更
金額：請求金額、消費税額、延滞保証料、キャンペーン割引料金など
ユーザー名：アカウント名、表示名、本名など

## どんな関心ごとがあるか分析したか
ホワイトボードなどに書いてチームメンバーと登場人物や事柄を列挙したり、関係性を整理したり、分析したりしてみましょう。

## 声に出して話してみたか

## 利用規約を読んだか

## 違う名前に置き換えられないか検討したか
顧客：宿泊客と支払者に分割するなど

## 疎結合高凝集になっているか点検したか

#　会話には登場するがコード上に登場しない名前はないか

# 形容詞で区別が必要なときはクラス化のチャンス
「元々の〜」「補正された〜」などのように形容詞をつけて説明していることがあればクラス化できないか検討する。

#　意図がわからない名前はないか
tmp, file, dataなどそれを見ただけで意図がわからない名前は避けよう。

# 驚き最小の原則を守っているか
メソッドの名前を見て、こう動くと思っていて蓋を開けたら予想外のことをやっていた...などとはならないように、名前に沿ったメソッドを記述すること

# クラスが巨大化する名前になっていないか
例えば、〜Manager、〜Processor、Controllerのような名前は意味が広すぎて秩序がない状態に陥る。単一責任を忘れずにクラス定義すること。
#　状況によって意味や扱いが異なる名前になっていないか
# 連番命名になっていないか

#　メソッドが不自然な場所に置かれていないか
Enemyクラスの中にパーティにアイテムを追加する、ゲームを終了するなどEnemyに関係のない、関心ごとがずれたメソッドが置かれていないか気をつけること。

#　動詞一語で済む名前になっているか（可能な限り）
動詞＋目的語になっている場合以下のようにできにか検討する
目的語の概念を表現するクラスを作る
そのクラスに動詞一語のメソッドを追加する

要は「〜がメソッド名する」という形が理想的なのかも。

#　名前の省略で意図が分からなくなっていないか（基本的に省略しない）
省略形が一般名称なら良いが、基本的には省略しないこと
『もういい加減「nullチェックをしたら安全」とかわけのわからないことを言うのはやめよう』をうろ覚えで書いた記事

## 前書き

昔のQiitaに「Nullチェックはいらない。むしろNullPointerExceptionは前向きに発生させるべきだ。」みたいな簡潔な内容の記事（※）があって感銘を受けたのですが、それが今現在全く見つからない（多分消えた）のでうろ覚えで書き起こしてみます。

※
・2019年くらい？に見た記憶。記事自体はそれ以前に書かれたかもしれない。
・ブラウザの1画面で完結するような短い内容。

（追記）
見つけた。いい記事なので読みましょう。消えたのが残念。

https://web.archive.org/web/20170605024132/https://qiita.com/hecateball/items/e0a8f8902ee7f5adda39

https://b.hatena.ne.jp/entry/s/qiita.com/hecateball/items/e0a8f8902ee7f5adda39

## 本文

最近の言語はNull安全が取り込まれているのに対し、JavaはいちいちNullチェックをしないといけないから面倒と言われている。

```java
public void func(String param) {
    if (param == null) {
        return;
    }
    System.out.println(param.toUpperCase());
}
```

だが、そもそもこう書けばいいだけではないだろうか。

```java
public void func(String param) {
    System.out.println(param.toUpperCase());
}
```

NullPointerExceptionはNullではいけない変数を教えてくれる大切な例外であり、
変数の実体がないというバグの発見を教えてくれるものだ。

Nullではいけない処理はNullでも動くようにするのではなく、むしろ積極的にNullPointerExceptionを発生させるべきだ。（意訳）

## 個人の意見

（予防線：最近のJavaは全く詳しくないです！！）
そもそもNullPointerExceptionが発生するということは本来は実体があることを想定している処理の可能性が高く、Nullのオブジェクトが存在することが異常でバグの可能性が高いと思われます。
そのため「JavaのようなNull安全ではない言語」はNullPointerExceptionを隠蔽させる行為はすべきではないでしょう。（もちろんNullが来ることが想定されているなら別ですが）
pythonのpandasで、データフレームをN件ずつに分割して処理する

# 結論
pandasのデータフレームをdfという変数に入れていたとします。N件ずつに分割したい場合は`[df[i:i+N] for i in range(0, len(df), N)]`で分割できます。

# サンプルコード
dfには既に205件のデータ(「商品番号」「単価」)が入ったデータフレームであるとします。
```.py
import pandas as pd

# ...

# データフレームをN件ずつに分割
N = 10 
splited_df = [df[i:i+N] for i in range(0, len(df), N)]

for part in splited_df:
    print(part)
```

### 結果
```
       商品番号     単価
0  9QYSNZB1  16000
1  IK7H29YP  15000
2  W5X9B5YL  27000
3  2GU990CA  15000
4  U67GM6E5  17000
5  1ORHZ5ZA  29000
6  C8EIXRZZ  10000
7  GG62Y92U  30000
8  7TNHTAVP  18000
9  2SHES5QY   8000
        商品番号     単価
10  K7P414PJ   5000
11  JNGQ8LZC  30000
12  WUPUZSB5  20000
13  HQYZQVD7   8000
14  JIKNL5RT  28000
15  FSWG9LOI   2000
16  AUQJJ9BC  17000
17  DYKUV6N6   5000
18  0KABUAOV   5000
19  6VDDMRPY   4000
...
         商品番号     単価
190  4HM62T2P   7000
191  TRNHYDSP  25000
192  F2G6SPY0  13000
193  A9RV72U0  27000
194  QXSS6GHA  16000
195  FKR56OE2  22000
196  IHEV3TU2  28000
197  D9KWQLM4   1000
198  MHORUEJP   2000
199  N423U8BC  29000
         商品番号     単価
200  F4ABFN26  15000
201  QXN3L9ML   4000
202  5XEC4SHW   7000
203  W1JOXZS4  29000
204  D6NWMVFI  22000

```

以上です。
RWKVで量子化を試す

![SS 192.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565043/a41cd967-f549-8677-1efa-2e99bf69518d.png) こんどはうまく行った。

## やること
[前回の記事](https://qiita.com/Ninagawa_Izumi/items/c74726f2c230693018cc)で、RTX-3090とCUDAを使って、フリーの大規模言語モデルであるChatRWKVが使えるようになりました。

今回はその性能をUPしていく作業に入りたいと思います。

## 作業環境

* Windows10 Home 22H2 (64bit x68ベース)
* RTX3090 24GB
* CPU i7-4770 CPU @ 3.40GHz
* メモリ 16GB

## 最大サイズの14Bをいきなり試す

[Hugginface](https://huggingface.co/BlinkDL)から[RWKV-4-Raven-14B-v12-Eng98%25-Other2%25-20230523-ctx8192.pth](https://huggingface.co/BlinkDL/rwkv-4-raven/tree/main)をDLして、ローカルのChatRWKV/v2に置きます。
chat.pyの該当箇所を書き換えて起動してみます。
ひょっとしたらなんとかなるかもと思いましたが、14Bはそもそものモデルのファイルサイズが28GBあるので、RTX3090の24GBをもってしても無理でした。
なにか方法があるかもしれませんが、本体のメモリも少ないですし一旦諦めます。



## データの量子化とは？
量子化ってなんでしょう。とにかく響きはかっこいいですよね。

ここで大規模言語モデルを非常にざっくり説明します。

気が遠くなるほど大量のテキストデータを、何億という数の **単語に分類**し、その単語の一つ一つに何十億、何千億という個数の**パラメータ**をつけ、そのパラメータのそれぞれが**度合い**で表されるようにしたものです。
パラメーターは人智を超えた単語の関係性を示しており、その関係性に基づいて単語を並べていくと**意味が通じる文章**になる。というものです。（違ってたらすみません。）

この量子化という作業は、「度合い」の表し方を、16bitの細かさから8bitまでの度合い表現の解像度を荒くすることです。たぶん。
そうすると単純にデータが半分になり、軽量化します。

## データの量子化を実行する

ここで「RWKV-4-Raven-14B-v12-Eng98%-Other2%-20230523-ctx8192.pth」というファイルを8ビットに量子化し、Raven-14B98Eng-cudafp16i8.pthという名前で保存するとします。

まず、chat.pyの中身も、変更後のモデルを使うように指定しておきます。
（変換ツールの最後にchat.pyを確認しているような気がなんとなくしています）

```
（中略）
# args.strategy = 'cpu fp32'
# args.strategy = 'cuda fp16'
# args.strategy = 'cuda:0 fp16 -> cuda:1 fp16'
# args.strategy = 'cuda fp16i8 *10 -> cuda fp16'
# args.strategy = 'cuda fp16i8 *10 -> cuda fp16'
args.strategy = 'cuda fp16i8'
# args.strategy = 'cuda fp16i8 -> cpu fp32 *10'
# args.strategy = 'cuda fp16i8 *10+'
（中略）
CHAT_LANG = 'Japanese' # English // Chinese // more to come
（中略）
elif CHAT_LANG == 'Japanese':
    args.MODEL_NAME = 'Raven-14B98Eng-cudafp16i8'
```

変換を実行します。
ChatRWKV/v2のディレクトリに入り、
```
python convert_model.py --in RWKV-4-Raven-14B-v12-Eng98%-Other2%-20230523-ctx8192.pth --out Raven-14B98Eng-cudafp16i8.pth --strategy "cuda fp16i8"
```
と入力して実行します。
"cuda fp16i8"の指定については、**ダブルクォーテーションのほうがうまく**動いてくれました。ダブルクォーテーションもシングルクォーテーションも、コピペ元が形が似ている別の文字を使っている場合があります。その場合はエラーになります。
シングルクォーテーションでも問題なく動く方はそのままでよいと思います。

## 8bit化した14Bファイルを実行する
ファイルを指定してchat.pyで動きます。

7Bに比べてもかなり賢くなったような感じがありますし、なにより質問文を入力してから1秒程度で返信開始してくれるクイックレスポンスが小気味よいです。

![WS000150.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565043/a328a081-3f73-3ed4-6155-cb02335d7aa2.jpeg)

すぐ返答してくれるので、いろいろな会話を実験できます。


## RTX3090の24Gに乗るサイズにする

RWKVでは、データの量子化について単純に半分にする以外にも、何層目までの計算を8bitにするかを指定することができるようです。
ためしに10層まで量子化するという--strategy "cuda fp16i8 *10 -> cuda fp16"を試してみました。

結果として、無事に動いたものの、返答開始まで3~4秒ぐらいかかるようになり、文章の文字が出てくるスピードも格段に遅くなりました。手軽に楽しむには全層量子化のまま使うのがよさそうです。


## 次は実験しやすくしたい
chat.pyの起動に少し時間がかかるので、chat.pyをAPIのエンドポイントっぽく使えるように改造しておけると便利かな、と思いました。

では楽しいRWKVライフを。


## 参考

前回の記事

https://qiita.com/Ninagawa_Izumi/items/c74726f2c230693018cc
com0comで作成したポートがCOM10以上であることを失念していた

## 前置き

kernel32.dllの`CreateFile`でシリアル接続しているコードがあったので、勉強ついでに`System.IO.Ports.SerialPort`に置き換えようとしていた
COMポートはcom0comで用意したCOM11,COM12の2ポートを用いる
`SerialPort`では難なくテストができたのに`CreateFile`ではなぜかポートが見つからない、という初歩的な問題が発生していた

## 結論

https://support.microsoft.com/ja-jp/topic/%E6%96%B9%E6%B3%95-com10-%E4%BB%A5%E4%B8%8A%E3%81%AE%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%AB-%E3%83%9D%E3%83%BC%E3%83%88%E3%82%92%E6%8C%87%E5%AE%9A%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95-db9078a5-b7b6-bf00-240f-f749ebfd913e

上記に則ってprefixを与えるだけ。初歩的ですね…

```c#:ポート名
 portName = "\\\\.\\COM11";
```
com0comのReadMeにもそんなようなことが書いてあるという

>Q. The HyperTerminal test succeeds, but I get a failure when trying to open the port with CreateFile("CNCA0", ...). GetLastError() returns ERROR_FILE_NOT_FOUND.
>A. You must prefix the port name with the special characters "\\\\.\\". Try to open the port with CreateFile("\\\\\\\\.\\\CNCA0", ...).

## SerialPortの実装

特に上記のようなprefixなしに`SerialPort`は接続できていたので多分内部的につけてくれているのだろうと思って確認すると、付けてくれている
ただしポート番号のみで判断しているのでCOM**という名前のポートしか扱えなくなっている模様
ポート名を自由に定義してる場合は面倒ですね

```c#
// SerialStream.Windows.cs
internal SerialStream(string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits, int readTimeout, int writeTimeout, Handshake handshake,
            bool dtrEnable, bool rtsEnable, bool discardNull, byte parityReplace)
        {
            ArgumentNullException.ThrowIfNull(portName);

            if (!portName.StartsWith("COM", StringComparison.OrdinalIgnoreCase) ||
                !uint.TryParse(
#if NETCOREAPP
                    portName.AsSpan(3),
#else
                    portName.Substring(3),
#endif
                    out uint portNumber))
            {
                throw new ArgumentException(SR.Format(SR.Arg_InvalidSerialPort, portName), nameof(portName));
            }

            // Error checking done in SerialPort.

            SafeFileHandle tempHandle = OpenPort(portNumber);
        // 以下略
        }

// SerialStream.Win32.cs
namespace System.IO.Ports
{
    internal sealed partial class SerialStream
    {
        private static SafeFileHandle OpenPort(uint portNumber)
        {
            return Interop.Kernel32.CreateFile(
                @"\\?\COM" + portNumber.ToString(CultureInfo.InvariantCulture),
                Interop.Kernel32.GenericOperations.GENERIC_READ | Interop.Kernel32.GenericOperations.GENERIC_WRITE,
                FileShare.None, // comm devices must be opened w/exclusive-access
                FileMode.Open,  // comm devices must use OPEN_EXISTING
                Interop.Kernel32.FileOperations.FILE_FLAG_OVERLAPPED);
        }
    }
}
```

https://github.com/dotnet/runtime/blob/fa9f94d01bb0a4103058f7ceae27fe42613f2cf1/src/libraries/System.IO.Ports/src/System/IO/Ports/SerialStream.Win32.cs
C++が未ビルド状態になる

UE5でC++/Blueprintを作成した後セーブ→ロードすると、
なぜかBPが未コンパイル状態になってしまうようになってしまいました。
なってしまいましたというか、つい最近UE5を使い始めたばかりなので、
もしかしたらこれがデフォルトなのかもしれないですが。。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/76ddbdfb-acfb-2901-d529-f6f8b6085883.png)

そもそもC++ Classes下にあるはずのPublic/Privateフォルダ（とその中身）が表示されていません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/3c10c584-6bdf-7a13-14fe-2bb7905f9e73.png)

Buildすると表示されるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/57b495ef-647f-d535-9227-8d809fe2d054.png)

そしてリロードするとMap上にもBPが復活します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/f0d460e8-d4de-c5f7-f5f4-0988b1838f2e.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/058f00fc-20ed-541a-8355-25bf3419cfd3.png)


復活せず、クラッシュすることもあります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/0ea4bcba-020d-d98a-036f-cb407c6041c7.png)

これでは困るので、何とかならないか試行錯誤した結果、

１．uprojectをダブルクリックしてプロジェクトを開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/84ce5411-f185-2d53-954a-8ba0afc7b169.png)

２．ビルドしてPublic/Privateフォルダおよびその下のC++を表示する
３．C++ソースをダブルクリックしてVS2022を開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/e6293ec4-e190-80b1-144a-359c46406443.png)

４．ソリューションをリビルド
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/6096b888-cfbb-be84-3c64-5f9831abf966.png)

５．Mapをセーブして終了
６．再度uprojectをダブルクリックしてプロジェクトを開く
７．rebuildの警告が出るので、Yesを押してリビルドする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/3ed787c3-c9b5-4a9f-9445-8bd02729ceb6.png)
８．しばらく待つと(結構かかります)UE5のスプラッシュスクリーンが出るので待つ
９．正常な状態で立ち上がる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/5e0db009-05f0-9a67-45d6-104553e332b5.png)

・・・自分だけですかね？
もしかしたら再インストールしたほうがはやいのかな・・・。

追記：
Binariesフォルダを削除して再起動しても
rebuildになるので、こちらをためしてみるのもよさそうです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/af62938d-7a03-1c9b-ae43-2315ba22cf4f.png)