OmniAICreator/Qiita-1.07M huggingface dataset:
VScode デバッグ ブレークポイント止まらない事案【vscode-rdbg】

# 生じた問題
**VScodeでのデバッグ中、設定したブレークポイントで止まらない**
とあるRubyファイルをVScodeでデバッグしようとしたところ、設定したブレークポイントで止まってくれずスルーしてしまう問題が発生。
ファイルの実行自体は出来るが、標準入力を入れるとすぐに実行結果が返ってしまう状態に。
(実行デバッガ:**vscode-rdbg**)

# 【結論】解決法
**実行ファイル名、その実行ファイルを含むディレクトリ名(というよりパス)に全角文字を含まないようにする** 

# この問題が起こりそうなタイミング
・上階層のディレクトリを日本語で管理しており、その下階層のファイルをデバッグ実行するとき
・今までメモのように日本語で管理していたプログラムファイルをデバッグ実行するとき

# 経緯

先日アルゴリズムの学習をしている際、メモ扱いしていた「二分探索2-6」という名前のファイル（以下ファイルA）をvscode-rdbgでデバッグしたときに何故か設定したブレークポイントを通りぬけてしまう謎の現象が起こった。
他のRubyファイルはちゃんと止まるのに何故...と悩みながら試行錯誤。
初めはプログラム内容が影響しているのかと考え、ちゃんとブレイクできるファイル（以下ファイルB）をファイルAの内容に少しずつ近づけていった。
しかしまるっきり同じ内容になってもファイルAとファイルBのブレイクの可不可が変わらず。

この2ファイルの差を考えた際にファイル名やパスに全角文字（日本語）を含んでいることに気づき、Aのファイル名をアルファベットに、Bのファイルをひらがななど付け加えるとブレイクの可不可が入れ替わった。
ここでファイル名やパスに全角文字（日本語）を含んでいるとブレイク出来ないことに気づく。


# 終わりに

全角文字ファイル名が良くないのは知っていたが、実行自体は出来るし、見た目の管理もしやすいので実行時エラーが出てからで大丈夫だろうと思っていた。しかし分かりづらい形で不具合が出てしまい、思わぬ時間を食ってしまった。(PCのユーザー名を日本語にしてユーザーディレクトリ名が全角文字の人はちゃんとブレークポイントで止まれるのだろうか...)

日本語含むと何故根本的にダメなのか、他デバッガでの比較、どこまで現象を再現できるか、等の書かれてる厳密性の高い記事ではありませんが、Web検索しても当該事象についての記事が無いような気がしたので自分で記事にしてみました。
全角文字含みが問題の必要十分条件ではないと思いますが条件の一つではあるとは思います。
デバッグ中にブレークポイントが止まらない事象が起こった際（特にvscode-rdbg使用時）にはファイル名や上層のディレクトリ名を一度チェックしてみてください。

# 余談
本記事の内容とは外れますが、rdbg実行中にステップのボタンが押せない状態で止まったときは 標準入力のステップに入ってrdbgデフォルト設定により止まった可能性があります。
標準入力を受付させるためにはlaunch.jsonファイルのconfigulationsに "useTerminal": true を付け加えるとターミナルで入力を受け付けてくれます。
Go言語とは

# Go言語とは
Googleが2009年に開発したオープンソースのプログラミング言語

# Go言語の特徴
* シンプルな構文で記述しやすい
* 高速処理が可能
* 複数の処理を並行できる

# Go言語でできること
* Webサーバー・Webサービスの開発
* スマートフォンアプリの開発
* IoT開発
* CLIアプリケーションの開発
* APIサーバー開発

# コード例
Hello, Worldを出力するプログラム
```go
package main

import "fmt"

func main() {
    fmt.Println("Hello, World")
}
```


# 参考
- 公式サイト: [The Go Programming Language](https://golang.org/)
- 公式リファレンス: [Documentation - The Go Programming Language](https://golang.org/doc/)
- Wikipedia: [Go (プログラミング言語) - Wikipedia](https://ja.wikipedia.org/wiki/Go_(プログラミング言語))
- Go言語 解説記事: [Go言語（golang）とは？　特徴・できること・将来性を徹底解説](https://tech-stock.com/magazine/what_is_golang/)
React(Next)のディレクトリ構造を考える

## はじめに
Reactアプリケーション開発におけるディレクトリ構造は、アプリケーションのスケーラビリティ、保守性、および全体的なコード管理に大きな影響を及ぼします。適切なディレクトリ構造を選択することは、開発チームの生産性を高め、プロジェクトの成長に伴う複雑さを管理するのに役立ちます。
今回は、現在の流行で見られるDirectory構造について見ていきながら個人的な視点を元にどの設計をどのように利用するかを考えて行きます。

## 構造の種類と解説
構造タイプを分け，それぞれの解説を行う。

比較するために，設計するプロジェクトを定義する．
### 定義するプロジェクト
想定するプロジェクトは、複数の機能を持つある程度大規模なWebアプリケーションです。このアプリケーションには、ユーザー認証、記事投稿、コメント機能、ユーザープロファイル管理などの機能が含まれています。

### 1. ファイルタイプ別にグループ化
このアプローチでは、コンポーネント、コンテキスト、フックなどのファイルタイプごとにフォルダを作成します。各フォルダには、それぞれのファイルタイプに関連するサブフォルダやファイルが含まれます。例えば、components フォルダには、各コンポーネントとそれに関連するスタイルやテストが含まれます。

```sh
src/
├── components/
│   ├── Header/
│   │   ├── Header.jsx
│   │   ├── Header.test.jsx
│   │   └── Header.css
│   ├── Footer/
│   ├── LoginForm/
│   └── ...
├── contexts/
│   ├── AuthContext.jsx
│   └── ...
├── hooks/
│   ├── useAuth.jsx
│   └── ...
└── ...

```

### 2. ページ別にグループ化
ページごとにコンポーネントとロジックをグループ化します。例えば、HomePage フォルダには、ホームページに特有のコンポーネントとロジックが含まれます。

```sh
src/
├── HomePage/
│   ├── components/
│   │   ├── HeroSection.jsx
│   │   ├── Features.jsx
│   │   └── ...
│   ├── HomePage.jsx
│   └── HomePage.css
├── ProfilePage/
└── ...

```

### 3. 機能ベースの構造
機能や機能性に基づいてファイルやコンポーネントをグループ化します。例えば、authentication フォルダには、ログインやユーザー認証に関連するファイルが含まれます。

```sh
src/
├── features/
│   ├── authentication/
│   │   ├── components/
│   │   │   ├── LoginForm.jsx
│   │   │   └── ...
│   │   ├── hooks/
│   │   └── ...
│   ├── articles/
│   └── ...
├── shared/
│   ├── components/
│   └── ...
└── ...

```

### 4. 標準的な構造
このアプローチでは、srcディレクトリ内にソースコードを配置し、Reduxを使用する場合はactionsとreducersのフォルダ、components, styles, utils, viewsなどのフォルダを含めます。viewsフォルダにはアプリの特定のページまたはセクションをレンダリングするための上位レベルのコンポーネントが含まれます。

```sh
src/
├── actions/
├── reducers/
├── components/
│   ├── Header/
│   ├── Footer/
│   └── ...
├── views/
│   ├── HomePage/
│   ├── ProfilePage/
│   └── ...
├── styles/
└── utils/

```

### 5. タイプ別にコンポーネントをグループ化
componentsフォルダ内で、forms, tables, buttons, layoutなどのタイプ別にコンポーネントをグループ化します。各コンポーネントタイプごとにフォルダを作成し、その中にコンポーネント自体、スタイル、テスト、Storybookファイルなどが含まれます。

```sh
src/
├── components/
│   ├── forms/
│   │   ├── LoginForm.jsx
│   │   ├── RegisterForm.jsx
│   │   └── ...
│   ├── tables/
│   └── ...
└── ...

```

## 個人的に使っていきたい構造
私が好むディレクトリ構造は、「2.ページ別にグループ化」のアプローチですが、純粋なページ毎のグループ化ではなく、ページ固有のロジックに依存する要素のみを各ページの配下に配置する形式を採用します。この設計により、ページ間での再利用性が低いコンポーネントや情報は、それぞれのページ内で管理され、アプリケーション全体に影響を及ぼす機能（例えば認証やメモリ内プロセス）はページ外の別の場所で管理されます。このアプローチは、コードの整理と保守性を向上させるだけでなく、エディターでの作業効率も高めます。ファイルツリーを展開し、参照する際の移動が少なくなり、作業の流れがスムーズになるからです。


## 調べてみて
この調査を通じて得られた最も重要な洞察の一つは、ディレクトリ構造の設計において"one-size-fits-all"の解決策は存在しないということです。（大体の同じような記事に書いてありました）
従って、プロジェクトの特性や規模、チームの動向に応じて、最適な構造を選択する柔軟性はこれからも不可欠です。将来のプロジェクトでは、今回の学びを活かし、より洗練されたディレクトリ構造を目指していきたいと思います。
時の流れに身を任せてPMOへ....〜元、開発エンジニアが読み解くPMOとは、、、？〜

はじめまして、記事をチェックいただきありがとうございます❣️
初投稿というのもあり、拙い説明ばかりになるかもしれませんが、1人でも多くの人に読んでもらえたら幸いです❣️

突然すぎますが、社会人10年以上経験すると、″キャリアチェンジ″の1つ、2つあるもんだなぁー
新卒時の会社で開発エンジニアで採用いただき、あれやこれやと流れに身を任せていたら、
いつのまにかプロジェクト管理／PMO業務の職歴のほうが長くなりました笑

今回は元開発エンジニアが思う”PMOとは・・・？”をお届けできたらと思います🙇🏻‍♀️
（こんなキャリアチェンジもあるんだーへぇー）と気楽に読んでもらえたらと思います🙇🏻‍♀️

# contents:high_heel:
1.これまでの経歴やキャリア紹介 
2.開発経験者が読み解くPMOとは....
3.最後に

#### 1.これまでの経歴やキャリア紹介 
日本大震災のあった年である2011年4月に新卒で入社して、現在35歳で３社目です。
社会人歴12年目ですが、銀行系の金融システムに約８年在籍したのち転職し、
保険・自動車・送金アプリ・住宅・医療のライン機器のPJを転々と回り、
今現在はクレジットカード系システムに落ち着いてます。
結局、金融系に戻ってきました。
いろんな業務を転々としてましたが歴が長い金融系がしっくりくるようです。


`キャリア紹介`
開発経験は新卒から３年半くらい経験し、
組織あるあるの部署異動で「プロジェクト管理（以下、プロ管）」チームへ異動。
プロ管経験があったおかげで、転職後も”ＰＭＯ”を売りにして挑戦してみよう:punch_tone2:
ダメだったら、、、また考えるｗｗくらいの気持ちでした。
周りの環境に恵まれているおかげで今日も今の職につけております。

>以下は、部署異動のお達しで会議室へ呼ばれたときの率直な気持ち： 
「**なんで、私が！？できるわけないよ(;・∀・)**」
「**開発の敵役だぁ。。。(´;ω;｀)**」
「なんか水曜日の夕方にチームごとの開発案件のガントチャートをプロ管宛に提出して、たまに次の日の朝に指摘がきて、なんか焦ってもう１回ガントチャート再提出した記憶しかないｗ」
と、当時のことを今でも鮮明に思い出しますし、
上記の”プロ管へ異動直後に木曜日にガントチャートを指摘する係”を担当することになる、ゆくゆくはシステムの開発標準/構成管理のドキュメント（基準）見直しメインで担うこととなり、 後続でＰＭＯの作業紹介しておりますが、
**自分が”見えていること”しか理解していなかったなぁー**（イメージが違うな） と、恥ずかしくなった記憶があります。

#### 2.開発経験者が読み解くPMOとは....
> そもそもPMOとは・・・・？
「**P**roject **M**anagement **O**ffice（プロジェクト・マネジメント・オフィス）」の頭文字を取った言葉です。
組織内のグループであり、組織全体のプロジェクトマネジメントの標準とプロセスを定義し、設定し、維持することを支援します。

「ＰＭＯ」をググったことがあれば、こんな感じの内容が検索結果にでてくると思います。
・・・・プロジェクト？
・・・・・マネジメント？？
・・・・オフィス・・・・（会社？）
と、未経験の方は「なるほど！わからん！！」だと思います。



プロジェクトでは色々な職種、役職、所属組織の人がかかわり、それぞれの思惑があります。
PMはそれらをまとめて、プロジェクトの目標を達成することを目的に活動します。
PMOは、それを助けプロジェクトメンバが自身の役割をこなせるようにし、コミュニケーションを円滑にし、問題を整理解決する活動をサポートします。

![IMG_3528.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559491/d48739a6-c82d-40eb-8016-a282fffef65f.png)
　　　【図1】PJ組織図の一例

以下に私基準（経験した作業）で、ＰＭＯはこんなことをやってますよ。のご紹介をします。
- **顧客、メンバー内の情報収集→情報整理（交通整理）**
    - 進捗管理
        - タスク（ＷＢＳ）の調整、管理
    - 品質管理
        - レビュー、テストのデータ・情報分析
    - 課題管理
    - コミュニケーション管理
        - 会議のセッティング
        - 会議の司会進行
        - 議事録の作成、内容のチェック
    - 報告
        - 報告書の作成
            - プロジェクト計画書
            - 各開発工程の完了報告書
            - 週次のチーム内進捗報告資料。。。etc
        -  ＰＬ、ＰＭへの報告
        -  ＰＯへの報告（ごくまれに）
            ※（ここにあるＰＯ：プロジェクトオーナーの略であり、ＰＭの上役でプロジェクトには普段参加していないが責任を取る役割の人）
- **その他**
    - 各申請書の作成（ごくまれに）
        - 本番端末利用申請書
        - 開発環境の手配
        - 新規着任者用の手配
            - 作業用ＰＣ
            - アカウント
            - 初日のフォロー
        - 運用手順書の作成（ごくまれに）
        - 開発プロセスの制定（ごくまれに）
        - 本番作業の立ち合い/検証者（ごくまれに）

多岐にわたりいろんな作業あるのがＰＭＯだと思ってます。


さて、やっと本題の**開発経験者が読み解くPMOとは....?** の結論にもなりますが、私基準でＰＭＯをひとことで表すと・・・・
- ＰＭ（ＰＬ）の秘書
- なんでも屋
- **自分に非がなくとも（関係者の）代わりに謝ることができる人**

ですｗ


上記でもお伝えした通り、**ＰＭＯは社内外調整作業がメイン**です。
どの作業とっても相手がベンダさんなのか、社内プロパーなのか、、チーム関係なく代わりに会話して調整していく作業ばっかりです。
特殊スキルはぶっちゃけなくてもどうにでもなりますが、なかなか目に見えるアウトプットとして残りにくいのがＰＭＯ業務。
あとは開発経験がないと開発ならではの「大変さ」「難しさ」がわかってあげられないと、衝突するばかりで、うまく立ち回りができなくなると思ってます。
うまく立ち回るために **その人に代わって「ごめんね」を言うこと**で、どれだけ戦ってきたか。。。

#### 3.最後に
癖のある長文を最後までありがとうございましたm(__)m
もし、１つでも何かの参考にしていただけることがありましたら、幸いです。
またの機会に「ＰＭＯやっていてよかった」か「ＰＭＯはこんなことをやってますよ。のご紹介」をできたらいいかなと思ってます。
何かリクエスト・アドバイスなどありましたら、コメントいただけると励みになります🙇🏻‍♀️
RestAPI使ったアプリ作るサーバーサイドフレームワーク調べ

# WebアプリとREST APIの基本

## Webアプリケーションとは？

Webアプリケーションは、インターネットを通じて利用できるコンピュータプログラムです。これは、ウェブブラウザを介してアクセスし、操作することができます。例えば、SNSのFacebookやTwitter、動画共有サイトのYouTubeなどがWebアプリケーションの一例です。

## REST APIとは？

REST APIは、Webアプリケーションが他のプログラムと情報をやり取りするための方法の一つです。APIとは「Application Programming Interface」の略で、アプリケーションプログラミングインターフェースを意味します。これは、ソフトウェアやアプリケーションが他のソフトウェアやアプリケーションと通信するための「接続口」のようなものです。

RESTとは「Representational State Transfer」の略で、ウェブ上でデータをやり取りするための設計原則の一つです。REST APIを使うと、Webアプリケーションは他のアプリケーションと情報をやり取りすることができます。

## REST APIの動作

REST APIは、以下の4つの主要な操作を使用してデータを操作します。

1. **GET**: データを取得します。
2. **POST**: 新しいデータを作成します。
3. **PUT**: 既存のデータを更新します。
4. **DELETE**: データを削除します。

これらの操作は、HTTPメソッドと呼ばれるもので、インターネットを通じて情報を送受信するための方法です。

## REST APIの利用

例えば、あるWebアプリケーションが天気予報の情報を表示したいとします。そのWebアプリケーションは、天気予報の情報を提供する別のWebアプリケーションのREST APIを使用して、必要な情報を取得します。そして、その情報を自分のWebアプリケーション上でユーザーに表示します。

このように、REST APIはWebアプリケーションが他のアプリケーションと情報をやり取りするための重要なツールです。これにより、開発者は既存のリソースを再利用して新しいアプリケーションを作成することができ、効率的に開発を進めることができます。また、ユーザーはさまざまなアプリケーションからの情報を一つの場所で閲覧することができます。これがREST APIの力です。 

## GraphQLを利用しない理由

REST APIの友達にGraphQLというのがあります。
経営者の人にわかりやすく言うと、エンジニアが好きそうなREST APIです。
ビジネスサイドの人にとってはどっちでも良いので、GraphQLの知見がなく、アプリを確実に開発させたい場合はREST APIを選択すると良いです。
REST APIというかRESTですね。

## REST APIのサーバーサイドの選定

PHP出身のわたしが色々調べたところ、PHPはやっぱ遅めでした。
PHPというか、現在のPHPフレームワーク代表格のLaravel先輩が遅め。
一応、RailsとDjango（Python）も載せておきますが、本筋としてはJavaとJavaScriptです。

## JavaとJavaScript

ビジネスサイドの人にお伝えするとJavaとJavaScriptは全く違います。

https://qiita.com/nakamoto/items/c0dc1cc51284755fca70

今回REST APIのサーバーサイド開発をJavaとJavaScriptに絞ったのにはなんとなくの理由があります。

- Javaは早い
- JavaScriptがJavaぐらい早い
- Javaは型があって安全
- JavaScriptもTypeScriptで型があって安全
- あれ？JavaScript良くね？


## めぼしいフレームワークでの比較

ビジネスサイドの人にわかりやすく言うと

- RailsとLaravelとDjango（Python）は、おんなじぐらいに早くはない
- Spring boot(Java)とNest.js(JavaScript)はおんなじぐらい早い
- Rustでactixフレームワークはものすご早いけど自社にも他社にも現状の予算で確保できるエンジニアは居ない


![compareframework1111.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39256/559c50e7-a047-327c-497c-978553b71430.png)

https://web-frameworks-benchmark.netlify.app/

## まとめ

Spring boot(Java)とNest.js(JavaScript)で考えたらどうかなって夢を見た。


## 起業・転職・フリーランス・プログラミング研修・エンジニア採用コンサルティングのご相談


https://park.jp/service_menu/2491


- 60分の人生相談を行っております。
- 企業の方は初回限定割引はご利用できません。
- 企業向けDXコンサルティングは年間契約でお受けしております。


https://park.jp/service_menu/2491



## 自分でもサービスを販売したい方へ

副業として無形のサービス提供をする場合、できるだけ手数料を下げて、安心して支払ってもらうスキル販売ショップサービス、【PARK】のご紹介です。

- クラウドワークスが運営
- 販売手数料 3%・決済手数料 3.5% + 40円/件
- サービスを提供する予定がなくてもストレスを減らす方法で使える（⇠重要）
↓ご登録はこちらから↓

[クラウドワークス運営スキル販売ショップPark](https://park.jp/?outer_ref=INV-BU076T "クラウドワークス運営のスキル販売ショップPark")
ベイビーステップで学ぶマップリストの値の操作② -Ectoスキーマからパラメータを取り出して更新する(iex内のみ)

こんにちは！
プログラミング未経験文系出身、Elixirの国に迷い込んだ？！見習いアルケミストのaliceと申します。
今回はEctoスキーマからパラメータを更新する方法について学んだことをまとめます。

# 目次
1.[Ectoスキーマからパターンマッチを使用してパラメータを取り出す](https://qiita.com/Alicesky2127/items/480816252525e9ae45ed)
2.Ectoスキーマからパラメータを取り出して更新する(iex内のみ)(本記事)
3.[Enum.mapの紹介](https://qiita.com/Alicesky2127/items/34c751267a254522bae6)
4.[Enum.filterの紹介](https://qiita.com/Alicesky2127/items/a9069ee013c3b1603920)
5.[String.contains?の紹介](https://qiita.com/Alicesky2127/items/ca81efcf8cca6907364a)
6.[Enum.intoの紹介](https://qiita.com/Alicesky2127/items/b399d2a6dde4f4129ece)
7.[Map.putの紹介](https://qiita.com/Alicesky2127/items/4700d913c6df3b81a1a5)
8.[(番外編)元データがマップ→リスト→マップのもう一段深い入れ子構造だったらどうするか？(Map.getの紹介)](https://qiita.com/Alicesky2127/items/23c8d9ed8d47c22fd6aa)


# 目的 
リストの要素がマップ(あるいはその逆)になっている場合に値を取り出して操作できるようになりたい。

## 実行環境
Windows 11 ＋ WSL2 ＋ Ubuntu 22.04
Elixir v1.14.3
Erlang v26.0.2
Phoenix v1.7.10

# 今回やりたいこと
Ectoスキーマからパラメータを更新したい。

# 今回やったこと
## Ectoスキーマの作成
[前回の記事](https://qiita.com/Alicesky2127/items/480816252525e9ae45ed)で作成したLiveViewのプロジェクトを引き続き使用します。

```bash
iex -S mix phx.server
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677280/640dca53-9c38-6b58-bdcb-934641a26525.png)

この画面上に表示されている1件のデータのnameの値を更新したいです。

## :nameの値を更新する
### Ectoスキーマからデータを取り出して変数userにバインドする
```diff_elixir:【iex上で実行】
iex()> user = Nov11.Users.get_user!(1)
[debug] QUERY OK source="users" db=1.4ms idle=1150.7ms
SELECT u0."id", u0."name", u0."age", u0."inserted_at", u0."updated_at" FROM "users" AS u0 WHERE (u0."id" = $1) [1]
↳ :erl_eval.do_apply/7, at: erl_eval.erl:746
%Nov11.Users.User{
  __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
  id: 1,
  name: "hogehoge",
  age: 10,
  inserted_at: ~U[2023-11-11 14:34:43Z],
  updated_at: ~U[2023-11-11 14:34:43Z]
}
```
前回と同じです。

### マップの値を更新する
```diff_elixir:【iex上で実行】
iex()> %{user | :name => "fugafuga"}        
%Nov11.Users.User{
  __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
  id: 1,
  name: "fugafuga",
  age: 10,
  inserted_at: ~U[2023-11-11 14:34:43Z],
  updated_at: ~U[2023-11-11 14:34:43Z]
}
```
`%{変数名|キー => 値}` で更新します。[^1]

更新できました(^▽^)/
ただし、今はiex上でパラメータを取り出して、それに対しての更新を済ませただけにすぎないので、画面上の値は更新されていません。
画面上の値を更新するには`Ecto.Changeset`の形にして、それを`Repo.update()`に渡すことで更新する必要があります。



# ～Elixirの国のご案内～
↓Elixirって何ぞや？と思ったらこちらもどぞ。Elixirは先端のアレコレをだいたい全部できちゃいます:laughing::sparkles::sparkles:

https://qiita.com/piacerex/items/09876caa1e17169ec5e1

↓ゼロからElixirを始めるなら「エリクサーチ」がおすすめ！私もエンジニア未経験から学習中です。

https://elixir-lang.info/topics/entry_column


↓[We Are The Alchemists, my friends!:bouquet:](https://qiita.com/torifukukaiou/items/6bcd5bbb80df9e594e9e "Awesome-san's Awesome article")[^10]
Elixirコミュニティは本当に優しくて温かい人たちばかり！
私が挫折せずにいられるのもこの恵まれた環境のおかげです。
まずは気軽にコミュニティを訪れてみてください。[^11]


https://speakerdeck.com/elijo/elixirkomiyunitei-falsebu-kifang-guo-nei-onrainbian


[^1]: @Yoosuke さんのこちらの動画が非常にわかりやすいです。https://youtu.be/wdmsRuzYPW0?si=FaNEyRpo2kW8ImlA

[^10]: @torifukukaiouさんのAwesomeな名言をお借りしました。Elixirコミュニティを一言で表すと、これに尽きます。


[^11]: @kn339264さんの素敵なスライドをお借りしました。Elixirコミュニティはいろんな形で活動中！
JavaとJavaScriptが違うことをビジネスサイドに伝える例

## JavaとJavaScriptが違うことをビジネスサイドに伝える例

受講生の方にも、コンサル先の社長にも、わかり易い例はいくつ有っても足りない


1. **インドとインドネシアぐらい違う**：両方とも国名で、名前に「インド」が含まれていますが、地理的位置、文化、言語などが全く異なります。同様に、JavaとJavaScriptは両方ともプログラミング言語ですが、構文、用途、動作環境などが全く異なります。

2. **メロンとメロンパンぐらい違う**：両方とも食べ物で、名前に「メロン」が含まれていますが、一つは果物で、もう一つはパンです。同様に、JavaとJavaScriptは両方ともプログラミング言語ですが、Javaは一般的にサーバーサイドやデスクトップアプリケーションで使用され、JavaScriptは主にウェブブラウザ内で動作するスクリプト言語です。

3. **カエルとカエルアンコウぐらい違う**：両方とも動物で、名前に「カエル」が含まれていますが、一つは陸生の両生類で、もう一つは海に生息する魚類です。同様に、JavaとJavaScriptは両方ともプログラミング言語ですが、Javaは静的型付け言語であり、JavaScriptは動的型付け言語です。

4. **ハチとハチドリぐらい違う**：両方とも動物で、名前に「ハチ」が含まれていますが、一つは昆虫で、もう一つは鳥類です。同様に、JavaとJavaScriptは両方ともプログラミング言語ですが、JavaはOOPプログラミング言語であり、JavaScriptは主にウェブページの動的な要素を制御するためのOOPスクリプト言語です。

5. **カレーとカレーパンぐらい違う**：両方とも食べ物で、名前に「カレー」が含まれていますが、一つはご飯の上にかける料理で、もう一つはパンの中にカレーが入っている食べ物です。同様に、JavaとJavaScriptは両方ともプログラミング言語ですが、Javaは一般的にサーバーサイドの開発やAndroidアプリの開発に使用された歴史もあり、JavaScriptはウェブブラウザ上で動作するプログラムを作成するために使用されます。

6. **ハンバーグとハンバーガーぐらい違う**：両方とも食べ物で、名前に「ハンバーグ」が含まれていますが、一つはソースをかけて食べる料理で、もう一つはパンの間に肉や野菜を挟んだ食べ物です。同様に、JavaとJavaScriptは両方ともプログラミング言語ですが、Javaはコンパイルが必要な静的型付け言語であり、JavaScriptはブラウザで直接実行できる動的型付け言語です。

7. **エビとエビフライぐらい違う**：両方とも食べ物で、名前に「エビ」が含まれていますが、一つは海で獲れる生の食材で、もう一つは揚げた料理です。同様に、JavaとJavaScriptは両方ともプログラミング言語ですが、Javaは一般的に大規模なシステムの開発に使用され、JavaScriptはウェブページの動的な要素を制御するために使用されます。

8. **サラダとフルーツサラダぐらい違う**：両方とも食べ物で、名前に「サラダ」が含まれていますが、一つは野菜を主成分とした料理で、もう一つはフルーツを主成分としたデザートです。同様に、JavaとJavaScriptは両方ともプログラミング言語ですが、Javaは一般的にバックエンドの開発に使用され、JavaScriptはフロントエンドの開発に使用されます。

9. **チョコレートとホワイトチョコレートぐらい違う**：両方とも食べ物で、名前に「チョコレート」が含まれていますが、一つはカカオを主成分としたお菓子で、もう一つはカカオの成分を一部除いたお菓子です。同様に、JavaとJavaScriptは両方ともプログラミング言語ですが、Javaは一般的にエンタープライズレベルのアプリケーションの開発に使用され、JavaScriptはウェブサイトのインタラクティブな要素の開発に使用されます。

10. **ワインとワイングミぐらい違う**：両方とも食べ物で、名前に「ワイン」が含まれていますが、一つはアルコール飲料で、もう一つはお菓子です。同様に、JavaとJavaScriptは両方ともプログラミング言語ですが、Javaは一般的に大規模なアプリケーションの開発に使用され、JavaScriptはウェブページの動的な要素を制御するために使用されます。

11. **チーズとチーズケーキぐらい違う**：両方とも食べ物で、名前に「チーズ」が含まれていますが、一つは乳製品で、もう一つはデザートです。同様に、JavaとJavaScriptは両方ともプログラミング言語ですが、Javaはジャバやジャヴァなど表記を違えるとJava警察がやってきて、JavaScriptはJavaと言われても文脈から「あーJavaScriptだろうけど指摘せず話を合わせよう」という雰囲気です。

12. **ハムとハムスターくらい違う**：なにもかも違う。名前以外似通ったところなど一つもない。(standard software様ご提供情報)

13.  **京都と東京都くらい違う**：名前の由来になっていますが、今となっては全くの別物（recordare(くま しろ)様ご提供情報）

14. **東京と東京ディズニーランドくらい違う**：全く何の関係もない言語なのに当時流行の Java の名前を借りて JavaScript になったわけで、東京と東京ディズニーランドの関係に似ていますかね。
パクった方の知名度も高いところも含めて。
京は元々中国で都という意味合いのあった字で、北京や南京もあるし、日本でも平城京や長岡京があり、首都が京の名を持つのは自然なことで、私としては「東京都の名前は京都を由来にしている」というのはウリジナル的な違和感を覚えます。
東京の方は「東京-都」であるのに対し、京都の方は「京都-府」「京都-市」ですし。(@Zuishin 様ご提供) 


## 起業・転職・フリーランス・プログラミング研修・エンジニア採用コンサルティングのご相談


https://park.jp/service_menu/2491


- 60分の人生相談を行っております。
- 企業の方は初回限定割引はご利用できません。
- 企業向けDXコンサルティングは年間契約でお受けしております。



[https://park.jp/service_menu/2491](https://park.jp/service_menu/2491)


## 自分でもサービスを販売したい方へ

副業として無形のサービス提供をする場合、できるだけ手数料を下げて、安心して支払ってもらうスキル販売ショップサービス、【PARK】のご紹介です。

- クラウドワークスが運営
- 販売手数料 3%・決済手数料 3.5% + 40円/件
- サービスを提供する予定がなくてもストレスを減らす方法で使える（⇠重要）
↓ご登録はこちらから(PR)↓

[クラウドワークス運営スキル販売ショップPark](https://park.jp/?outer_ref=INV-BU076T "クラウドワークス運営のスキル販売ショップPark")
【VSCode】Ruby on Rails開発を向上させるための必須エクステンション

# 概要
Visual Studio Code（VSCode）には生産性やコード品質を高めるためのさまざまなエクステンションが用意されています。ここでは、Railsで開発する際に使用すると助かるVSCodeエクステンションを紹介します。

# コード品質とフォーマッティングツール
1. [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint
): JavaScriptコード品質を維持するために不可欠なツールで、コーディング基準に従って問題を強調表示し、修正します。

2. [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode): 複数の言語に対応した汎用コードフォーマッターで、機能的であるだけでなく、一貫性のある美しいコードを保証します。

3. [Haml Lint](https://marketplace.visualstudio.com/items?itemName=aki77.haml-lint): Hamlを使用している場合、このツールはHamlファイルのスタイルと構文の問題を特定します。

# RubyとRails専用の拡張機能
1. [Ruby LSP](https://marketplace.visualstudio.com/items?itemName=Shopify.ruby-lsp): Rubyのコード理解と品質を高めるための拡張機能です。セマンティックハイライト機能によりコードの可読性を向上させ、RuboCopを使用したエラーと警告の表示により、コードの品質管理をサポートします。さらに、クラスやモジュールへの定義ジャンプ、ドキュメントのホバー表示、クラスやモジュールの補完など、開発の効率を向上させる多くの機能が含まれています。
2. [Rails Partial](https://marketplace.visualstudio.com/items?itemName=atipugin.rails-partial): 
RailsのPartialに関して、自動完成機能とファイル移動機能を提供します。
3. [Rails Routes](https://marketplace.visualstudio.com/items?itemName=aki77.rails-routes): Railsのルーティングに関して、URLまたはパスメソッドの自動完成機能とファイル移動機能を提供します。
4. [Rails DB Schema](https://marketplace.visualstudio.com/items?itemName=aki77.rails-db-schema): RailsのSchemaと関連して、コード自動完成機能とファイル移動機能を提供します。
5. [Fuzzy Ruby Server](https://marketplace.visualstudio.com/items?itemName=Blinknlights.fuzzy-ruby-server): Rubyコードのインテリジェンスを向上させ、大規模なコードベースに不可欠なコードナビゲーションやシンボル検索などの機能を提供します。

# 生産性と可読性を向上させる
1. [Better Haml](https://marketplace.visualstudio.com/items?itemName=karunamurti.haml): Hamlのシンタックスハイライトを提供し、このテンプレート言語でのコーディングを直感的にします。
2. [Rainbow CSV](https://marketplace.visualstudio.com/items?itemName=mechatroner.rainbow-csv): CSVファイルの異なる列を様々な色でハイライト表示し、大規模なデータセットを扱う際の読みやすさを向上させます。

# 結論
これらの拡張機能をVSCodeに組み込むことで、Ruby on Railsアプリケーションの開発における効率性と作業の品質が大幅に向上します。
Laradock 覚書

# Laradockが作られた経緯
・Docker の初期の頃、複数のコンテナーを起動が面倒だった
・最小限の変更ですべての PHP アプリを提供できるように、単一のコマンドで起動できる複数の分離された Docker イメージで構成される独自のソリューションを構築する必要があった


# Laradock の対象ユーザ
・Dockerについて学ばずに開発環境をセットアップしたいと考えているあらゆるレベルのPHP開発者

# Laradock 設定をプロジェクトの他のコンテナと共有する方法
・プロジェクトごとに 1 つの Laradock を設定
・すべてのプロジェクトに 1 つの Laradock を設定する方法

#所管

Laradockに初めて触れたので、少し調べたことの覚書

####  参考記事
[Laradock の作成者、Mahmoud Zalt 氏へのインタビュー](https://www.shiphp.com/blog/mahmoud-zalt-laradock)
【SwiftUI】@ScaledMetricを使ってフォントサイズを柔軟に対応する

# はじめに
`@ScaledMetric`という機能がiOS14から使えるようになっています
通常、サイズに関する値を数値で指定すると固定の値になってしまうところ、`@ScaledMetric`を使用して指定するといい感じにサイズ変更してくれます

# 実装
```swift
import SwiftUI

struct ContentView: View {
    @ScaledMetric private var fontSize1: CGFloat = 20
    
    private var fontSize2: CGFloat = 20

    var body: some View {
        VStack(spacing: 50) {
            Text("動的サイズ")
                .font(.system(size: fontSize1))

            Text("固定サイズ")
                .font(.system(size: fontSize2))
        }
    }
}
```

# サイズの変化
|||
|-|-|
|![IMG_4790.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/6c71339f-6c02-3171-4457-886910e2bcb7.png)|![IMG_4791.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/bb938d9f-3cd5-7b46-0823-03ef1fdd3d05.png)|
|![IMG_4792.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/3e26ea5d-719b-59f0-ccc4-2a439da8bade.png)|![IMG_4793.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/4f337fa2-33ac-67d2-31b9-bc56861ec392.png)|
|![IMG_4794.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/0b098d85-2fe1-dde9-5dea-ef49dae66ce6.png)|![IMG_4795.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/61e5330d-8315-fb76-5595-455edfb0e49d.png)|
|![IMG_4796.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/52c2c465-f039-4742-a1fe-65da190ba2f6.png)|![IMG_4797.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/53f971e9-10f5-c2a4-9151-b7ebe4b2a706.png)|
|![IMG_4798.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/7b91ccb2-96e2-3ebd-ff7d-0afedf13c86b.png)|![IMG_4799.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/c5838c4b-ab1e-91d2-ad55-c64ba55ce7ba.png)|
|![IMG_4800.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/65ec04b4-384a-e248-315b-e702b6591b2f.png)|![IMG_4801.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/5a1d4bc3-d580-f5cd-b9e2-9726a112ed47.png)|
|![IMG_4802.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/85b5a128-30c4-09df-722f-2765fb6c573b.png)|![IMG_4803.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/3b14fd86-e8ee-69f5-0ff4-27eb4560ab30.png)|

# おわり
指定した値を基準に`DynamicType`に対応してくれるので便利です
Flutterを導入してゲームを作ってみようと試みる(Flutter導入編)

エンジニア駆け出し３年目ぐらいです。

普段は、pythonやらRubyやら使って、業務効率化アプリを作成しているものです。
ここ最近、ゲーム作りたいなぁという欲望があり、どれで作るよ？？と悩んだ結果、Flutterでトライしてみようかなぁと思って導入を検討してみた。

# 導入
結構、手間取ったので、共有。
公式ページにも書いてある通りの手順をざっと、書く。
Apple Silicon(M1/M2/M3)だったら以下のコマンド手動て打ってねとのこと。

    ` sudo softwareupdate --install-rosetta --agree-to-license`

    ここのページを参照して、[DL](https://docs.flutter.dev/get-started/install/macos#update-your-path)

    ダウンロードしたら、解凍して、解凍後のページへ移動し、以下コマンドを入力。※通称PATHを通すってやつ
    `export PATH="$PATH:`pwd`/flutter/bin"`

    もし、永続的に、PATHを通したいということであれば、zshrcをvimとかnanoとかで開いて、上のコマンド書いてあげてね。


# 詰まったところ：flutter doctor
```
    - flutter doctorコマンドを打つ。以下内容
        Doctor summary (to see all details, run flutter doctor -v):
        [✓] Flutter (Channel stable, 3.13.9, on macOS 14.1 23B74 darwin-arm64, locale ja-JP)
        [✗] Android toolchain - develop for Android devices
        ✗ Unable to locate Android SDK.
        Install Android Studio from: https://developer.android.com/studio/index.html
        On first launch it will assist you in installing the Android SDK components.
        (or visit https://flutter.dev/docs/get-started/install/macos#android-setup for detailed instructions).
        If the Android SDK has been installed to a custom location, please use
        `flutter config --android-sdk` to update to that location.
        [!] Xcode - develop for iOS and macOS (Xcode 15.0.1)
        ✗ Unable to get list of installed Simulator runtimes.
        ✗ CocoaPods not installed.
        CocoaPods is used to retrieve the iOS and macOS platform side's plugin code that
        responds to your plugin usage on the Dart side.
        Without CocoaPods, plugins will not work on iOS or macOS.
        For more info, see https://flutter.dev/platform-plugins
        To install see https://guides.cocoapods.org/using/getting
        started.html#installation for instructions.
        [✓] Chrome - develop for the web
        [!] Android Studio (not installed)
        [✓] VS Code (version 1.84.0)
        [✓] Connected device (2 available)
        [✓] Network resources
        ! Doctor found issues in 3 categories.`
```

なんか色々と出た。
要するに、三つ引っかかってるとのことで、一つずつ解消していく

```
    1:Android Studioを導入せよ
    2:ruby のgemを使って、`sudo gem install cocoapods` せよ
    3:Xcodeのエミュレーターを導入せよ
```

結論としてはこの3つを導入して解消。

先は長そうだ笑

参考になれば幸いです。
nginxのアクセスログにレスポンスタイムを出力する

nginxのアクセスログにレスポンスタイムを出力しておくと、パフォーマンスチューニングの観点でいろいろ役立ちそうと感じたため手順をまとめておきます。

# デフォルトのアクセスログ
nginxのアクセスログはnginx.confで定義します。nginx.confで何を指定しなかった場合は以下の形式でログが出力されます。(combinedと呼ばれる形式)

```
log_format combined '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
        		    '"$http_referer" "$http_user_agent"';
```

各変数の内容は以下の通りです。

| 変数 | 内容|
| ---- | ---- |
| $remote_addr | リクエストの送信元IPアドレス |
| $remote_user | ユーザー名(ベーシック認証時等に使われる) |
| $time_local | リクエストの処理完了時刻 |
| $request | リクエストのHTTPメソッド、パス、HTTPのバージョン |
| $status | レスポンスのHTTPステータスコード |
| $body_bytes_sent | レスポンスのボディのバイト数 |
| $http_referer | リクエストのReferer(遷移元)の内容 |
| $http_user_agent | リクエストのUser-Agentの内容 |

# アクセスログで利用できるその他の変数
デフォルト以外にも様々な変数が利用できます。
パフォーマンスの測定やボトルネックの特定に役立ちそうな変数としては以下が挙げられます。

| 変数 | 内容|
| ---- | ---- |
| $request_method | リクエストのHTTPメソッド |
| $request_uri | リクエストのURI |
| $request_time | リクエスト処理に要した時間 |
| $upstream_request_time | nginxがリバースプロキシとして動作する場合に、プロキシ先からレスポンスを取得するまでの時間 |


# 設定例
上記の変数を加えた設定例が以下の通りです。
デフォルトの出力形式では集計ツール等で扱いづらいため、json形式で出力するようにしています。
時刻(time)も見やすいように`$time_iso8601`に変更しています。

```
log_format json escape=json '{'
                            '"time":"$time_iso8601",'
                            '"host":"$remote_addr",'
                            '"method":"$request_method",'
                            '"uri":"$request_uri",'
                            '"status":"$status",'
                            '"body_bytes":"$body_bytes_sent",'
                            '"referer":"$http_referer",'
                            '"ua":"$http_user_agent",'
                            '"request_time":"$request_time",'
                            '"respons_time":"$upstream_response_time"'
                            '}';
```


# $request_timeと$upstream_request_timeの違い
`$request_time`はnginxがクライアントからリクエストを受けてからレスポンスを返し終えるまでの時間であるのに対し、`$upstream_request_time`はnginxがプロキシ先(アプリケーションサーバー等)にリクエストを投げてからレスポンスが返ってくるまでの時間を表します。

つまり、`$request_time > $upstream_request_time`の関係になります。

クライアントの回線状況に問題がない場合はこの2つの指標はほぼ同じ値になりますが、もしクライアントが線の細い回線を使っている等、通信状況がよろしくない場合は2つの指標の値が大きく乖離することになります。
このように、ネットワークがボトルネックとなっていることに気づくきっかけにもなるため、これらの2つの指標は共に出力することをお勧めします。
JavaでDynamoDB JSONを生成する

（編集履歴を削除したかったので再投稿しました。）

# 目的
AWSのDynamoDBにデータをインポートする際のDynamoDB JSON形式をJavaで生成する方法を記載します。
なお、DynamoDB JSONについては[こちら](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/S3DataImport.Format.html#S3DataImport.Requesting.Formats.DDBJson)を参照下さい。

## 作りたいJSONの例
以下に例を記載します。
tagとnamesは属性名（個人的に開発しているアプリケーション依存）です。
ItemとSとSSは、DynamoDBの書き方です。

```json
{"Item":{"tag":{"S":"後三年の役"},"names":{"SS":["後三年合戦金沢資料館","平安の風わたる公園"]}}}
{"Item":{"tag":{"S":"備後国"},"names":{"SS":["神石牛","鞆の浦","三原城","比婆牛","びんご畳表","尾道"]}}}
{"Item":{"tag":{"S":"三原村"},"names":{"SS":["四万十かいどう"]}}}
{"Item":{"tag":{"S":"東海村"},"names":{"SS":["東海十二景"]}}}
```

形は
{"Item":{"属性名":{"型": "値"}}}な感じです。なお、全体をリスト([]で囲み、カンマでセパレト)にする必要は**無い**みたいです（つまり、JSONLに近い形）。


## 使いどころ
AWSのDynamoDBにインポートする際のフォーマットに「DynamoDB JSON」を選択で利用します。
![dynamodb_import.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1237247/242ca55b-1a44-913b-3245-d5161e8ed0f3.jpeg)


## 注意
もしかすると「AWS SDK for Java」に本記事に記載するコードよりしっかりしたものがあるかもしれません（ご存知な方、ご教示頂ければ幸いです）。


# 動作確認環境
Java 17系

# ソースコード
まず、型ごとに変換用のメソッドを作ります。

```java
// 文字列用
static String toJsonForString(String name , String s) {
	return String.format("\"%s\":{\"S\":\"%s\"}", name, s);
}
// コレクション用
static String toJsonForStringSetInner(String name , Collection<String> ss) {
	return String.format("\"%s\":{\"SS\":[%s]}", 
			name,
			ss.stream()
				.map(s -> String.format("\"%s\"", s))
				.reduce((s1, s2) -> s1 + "," + s2).get());
}
// List<String>用
static String toJsonForStringSet(String name , List<String> ss) {
	return toJsonForStringSetInner(name, ss);
}
// Set<String>用
static String toJsonForStringSet(String name , Set<String> ss) {
	return toJsonForStringSetInner(name, ss);
}
```

DynamoDB JSON化したいオブジェクト自体は、Map<String, Object>で渡します。
型に応じて呼び出すメソッドを変えます。

```java
public static String toJson(Map<String, Object> item) {
	return String.format("{\"Item\":{%s}}", item.entrySet().stream()
			.map(entry -> {
				String ret = null;
				String clzName = entry.getValue().getClass().getSimpleName();
				if (clzName.contains("List"))
					ret = toJsonForStringSet(entry.getKey(),(List<String>)entry.getValue());
				if (clzName.contains("Set"))
					ret = toJsonForStringSet(entry.getKey(), (Set<String>)entry.getValue());
				if (clzName.equals("String"))
					ret = toJsonForString(entry.getKey(), (String)entry.getValue());
				
				if (ret == null)
					System.err.println(clzName);

				
				return ret;
			})
            .filter(Objects::nonNull)
			.reduce((s1, s2) -> s1 + "," + s2)
			.get());
}

```

なお、importは以下になります。

```java
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
```


# 参考資料
1. [項目の操作:Java](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/JavaDocumentAPIItemCRUD.html)
これは普通の(?)JSONしか出力できない感じでした。
2. [DynamoDB Mapper for Java でサポートされるデータ型](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/DynamoDBMapper.DataTypes.html)
3. [DynamoDB 用の Amazon S3 のインポート形式](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/S3DataImport.Format.html#S3DataImport.Requesting.Formats.DDBJson)
ChatDevでRate limitエラーが出る場合の対処方法

# 概要
ChatDevでGPT-4モデルを利用すると、1分あたりのトークン数上限（Rate limit）に引っかかったので、回避する方法をメモ。

詳しくは、こちらのIssueの内容から。
https://github.com/OpenBMB/ChatDev/issues/26

## 原因
そもそも、ChatDevが内部で利用しているライブラリCamel側の問題。
よって、cloneして来たソースコードのCamel側のコードを修正する。

## 修正箇所
修正箇所は、以下の二箇所。

### camel/model_backend.py
最初に
```
from tenacity import retry, wait_exponential
```

というimport文を追加。

以下のクラスのクラスメソッドに、デコレータを追加。
```
class OpenAIModel(ModelBackend):
    r"""OpenAI API in a unified ModelBackend interface."""

    @retry(wait=wait_exponential(multiplier=1, min=4, max=10))        
    def run(self, *args, **kwargs) -> Dict[str, Any]:

```

### camel/agents/role_playing.py
最初に
```
from tenacity import retry, wait_exponential
```

というimport文を追加。

以下のクラスメソッドに、デコレータを追加。
```
    @retry(wait=wait_exponential(multiplier=60, max=100))
    def step(
            self,
            user_msg: ChatMessage,
            assistant_only: bool,
    ) -> Tuple[ChatAgentResponse, ChatAgentResponse]:
```

以上で、GPT-4を利用した場合でも、Rate limitエラーが出ずに実行が完了するようになった。
Playwrightを使ってみる

# 目次
1. 背景
2. Playwrightとは
3. 使ってみる
4. 最後に
5. 参考

# 1. 背景
E2Eテストツールをフレームワークの移行の際に導入しようかなと考えているからです。

https://qiita.com/yamatai12/items/3281e19f3138a89303d8

# 2. Playwrightとは
https://playwright.dev/

# 3. 使ってみる
[こちらのリポジトリ](https://github.com/yamatai12/nuxt3-playwright)で実施します。
## install
こちらを見ながら進めます

https://playwright.dev/docs/intro

```terminal
npm init playwright@latestnpm
Need to install the following packages:
create-playwright@1.17.131
Ok to proceed? (y) y
Getting started with writing end-to-end tests with Playwright:
Initializing project in '.'
✔ Where to put your end-to-end tests? · tests
✔ Add a GitHub Actions workflow? (y/N) · true
✔ Install Playwright browsers (can be done manually via 'npx playwright install')? (Y/n) · true
```

## test実行
以下のコマンドを実行します。
```terminal
npx playwright test
```

```
> e2e-test
> playwright test

Running 3 tests using 3 workers
  3 passed (5.5s)

To open last HTML report run:

  npx playwright show-report
```
以下のworkflowのファイルも自動で生成されるのでgithub-actionsが走ってくれます。
```playwright.yml
name: Playwright Tests
on:
  push:
    branches: [ main, master ]
  pull_request:
    branches: [ main, master ]
jobs:
  test:
    timeout-minutes: 60
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - uses: actions/setup-node@v3
      with:
        node-version: 18
    - name: Install dependencies
      run: npm ci
    - name: Install Playwright Browsers
      run: npx playwright install --with-deps
    - name: Run Playwright tests
      run: npx playwright test
    - uses: actions/upload-artifact@v3
      if: always()
      with:
        name: playwright-report
        path: playwright-report/
        retention-days: 30
```

# 4. 最後に
- 簡単に実装、実行できました。
- CIも容易に設定できるのはありがたいですね。
- 設定まわりだったり、[UIモード](https://playwright.dev/docs/test-ui-mode)というのも試してみたいと思いました。

# 5. 参考
- [Nuxt3 × 単体テスト × E2Eテスト実装例](https://zenn.dev/kotatsufujiwara/articles/2417338a3e3a93)
generative-ai-use-cases-jp を同一アカウントに 2 つデプロイしてみた

# generative-ai-use-cases-jp を同一 AWS アカウントで 2 つデプロイしたい

Tips 的な備忘録記事です。

GitHub で公開されている [generative-ai-use-cases-jp](https://github.com/aws-samples/generative-ai-use-cases-jp) があります。会社の中で複数の部署が存在するときに、Kendra Index を別々に保持して、データを分離したいときがあります。このときに、何も考えずにデプロイを行うと 1 個の AWS アカウントの中で、AWS CDK の Stack ID が重複し、個別にデプロイができません。

そこで、次のファイルを変更することで AWS CDK の Stack ID を変更でき、個別にデプロイができます。

Git Clone してきたディレクトリで、 /package/cdk/bin/generative-ai-use-cases.ts を開きます。次のようなファイルになっているはずです。

```typescript
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { IConstruct } from 'constructs';
import { GenerativeAiUseCasesStack } from '../lib/generative-ai-use-cases-stack';

class DeletionPolicySetter implements cdk.IAspect {
  constructor(private readonly policy: cdk.RemovalPolicy) {}

  visit(node: IConstruct): void {
    if (node instanceof cdk.CfnResource) {
      node.applyRemovalPolicy(this.policy);
    }
  }
}

const app = new cdk.App();
const stack = new GenerativeAiUseCasesStack(app, 'GenerativeAiUseCasesStack');

cdk.Aspects.of(stack).add(new DeletionPolicySetter(cdk.RemovalPolicy.DESTROY));
```



GenerativeAiUseCasesStack の部分を好きな ID に変更することで、同一の AWS アカウント上で 2 つのデプロイが可能です。



変更前

```
const stack = new GenerativeAiUseCasesStack(app, 'GenerativeAiUseCasesStack');
```



変更後

```
const stack = new GenerativeAiUseCasesStack(app, '好きなID');
```





この後、次のコマンドを実行しデプロイを行うことで、個別に構成が可能です。

```
npm ci
npm run cdk:deploy
```
PowerAutomate: TriggerCondition は、設定する前にCompose(作成)に入れて確認しよう。

# 背景

Trigger Condition は、起動回数を減らせるのでとても便利な反面、条件が間違っているとそもそも履歴が残らないので確認が大変、って言われたことがあったので・・ :thinking:  

# 確認の仕方

前提として・・

- 条件判断は、Automate 内で利用できる**関数**
- Trigger Condition で使えるのは、Boolean のみ

ということで、いきなり Trigger Condition に設定せずに

- Compose (作成) で、Trigger Condition の結果を格納して、入力パターンに対する結果を確認

すれば困ることも減る筈。 :laughing: 

# 具体例

- ファイル名が、"'" から始まらない場合のみ、起動させたい

この場合、以下のような関数を用意し、その結果を見るだけのフローを最初に作り、関数の動作確認をする。


> not(startsWith(triggerOutputs()?['body']['{FilenameWithExtension}'], '('))

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/97460063-450d-ad38-cf1d-4eeb8ede67a9.png)


で、問題なければ、この関数をそのまま、Trigger Condition に設定してやるだけ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/063ebc1c-b1a3-70cb-4730-6f14549f1f48.png)

あとから条件確認を再度しやすいように、このアクションは残しておくのがお勧め

:::note warn
"@" を先頭に入れないとエラーになるのでご注意を
:::

# あとがき

実行回数が減らせると、[クラウドフロー活動](https://qiita.com/baku2san/items/c3f808d6e077d1cb33db#cloud-activity-%E3%82%AF%E3%83%A9%E3%82%A6%E3%83%89%E3%83%95%E3%83%AD%E3%83%BC%E6%B4%BB%E5%8B%95-%E3%81%A8%E3%81%84%E3%81%86%E6%A9%9F%E8%83%BD%E3%82%92%E4%BD%BF%E3%81%86%E3%81%A0%E3%81%91%E3%83%94%E3%83%B3%E7%95%99%E3%82%81%E3%81%99%E3%82%8B%E3%81%AE%E3%81%8C%E5%90%89) が汚れなくてよくなりますね。
外部参照のあるSVNリポジトリをGItで管理する




# 目的と背景

snv管理されたプロジェクトで、個人としてgitを利用する方法です。
**プロジェクト全体でのgit移行の話ではありません**。

外部参照が無ければ、 `git svn`,`SubGit` などを使えば良いのですが、
外部参照のがあると上手く使えません。

特に、外部リポジトリの一部分を取り込んでいる様な場合は、
他の方法を取る必要があります。

# TL;DR
* ローカルに、svn チェックアウトした後、別途 git 管理を行う。
  * i.e. 同じファイルを、svn と git それぞれで管理する
* git の main ブランチが、svn の最新状態と一致するよう、メンテする。
* svn と git は、お互いの存在を知らず、運用により同期を取る。

# 手順

## 環境の作成

<!-- 以下の手順で、環境を作成します。 -->

1. svnリポジトリをチェックアウトする。
    * ビルド生成物などが無い状態が欲しいので、既にチェックアウト済みでも、別途チェックアウトをする[^1]。

2. チェックアウトしたフォルダを、gitの空リポジトリとして、初期化。
    * フォルダ内に、.svn と .git が並ぶ

4. フォルダ内にある、.svn 以外の全ファイルを、Git管理する。
    * .svn を Git の無視ファイルに設定して、全ファイルを add してコミットすれば良い。

[^1]:管理外ファイルの削除でも可


# 内容の同期

* 普段の作業は Git へ、まとまった,共有する変更は svn へコミットする。

* svn の Update時には、同じ変更をgitにも行う

Updateの具体的な手順は、
1. git を main ブランチへスイッチ
2. svn update を実行。
    * このとき、追加されたファイルを記録しておく
2. svn update で追加されたファイルを、git へ追加
3. 全ての変更を、git の main ブランチへコミット
    * ファイルの削除も、コミットする。

追加ファイルのメンテが煩雑なため、スクリプトを使った方が良いでしょう。

```ruby:Rubyスクリプト
# ローカルに変更が無いことを想定。
# リポジトリのパスを引数にする。
repo_dir = ARGV[0]


def GetLineStartWithPrefix( text, prefix )
  result = []
  text.each_line {|line|
    normalized = line.chomp
    if normalized.start_with?( prefix )
      result.push( normalized[prefix.length,normalized.length] )
    end
  }
  return result
end

def GitCurrentBranch( repo_dir )
  msg = `git -C #{repo_dir} branch --contains`
  return GetLineStartWithPrefix( msg, "* " ).first()
end

def GetLastChangeRev( repo_dir )
  info = `svn info #{repo_dir}`
  prefix = "Last Changed Rev: "
  return GetLineStartWithPrefix( info, prefix ).first()
end


org_branch_name = GitCurrentBranch( repo_dir )
`git -C "#{repo_dir}" checkout master`

if $?.exitstatus != 0 then
  puts( "swich failed" )
  exit 0
end

puts( "Start SVN Update" )

svn_update_log = `svn update #{repo_dir} --force`
new_files = GetLineStartWithPrefix( svn_update_log, "A    " );
new_files.each { |new_file|
  `git -C "#{repo_dir}" add #{repo_dir}/../#{new_file}`
}

comment = "Rev" + GetLastChangeRev( repo_dir );

puts( "Start Git Commit" )

`git -C "#{repo_dir}" commit -a -m #{comment}`
`git -C "#{repo_dir}" checkout #{org_branch_name}`

sleep( 3 )
```

# Note

この方法だと、svnのログをgitから見る事は出来ません。
また、svn で複数コミットとなっていても、git では、1つにまとまってしまいます。
* 自身の作業と他者の作業が明確に分離されるメリットともなりますが。

VisualStudio では、git と svn を同時には扱え無かった覚えがあります。
別途、svnやgitのクライアントソフトを入れると良いでしょう。
Livebook で Vim や Emacs と同じキー操作ができる

## はじめに

Livebook Launch Week 2 を自分でやってみるシリーズ

- Day1: [Smart Cell からのリモート接続](https://qiita.com/RyoWakabayashi/items/d2f19a674c261790d999)
- Day2: [Whisper による音声認識の新機能](https://qiita.com/RyoWakabayashi/private/4db05611945f3bba6e30)
- Day3: [ファイルをドラッグ＆ドロップすると、扱うためのコードを自動生成する](https://qiita.com/RyoWakabayashi/private/0a2760c88001076c0c7b)
- Day4:
  - [データクラウド Snowflake に接続する](https://qiita.com/RyoWakabayashi/private/98db4a51c6a275541ec2)
  - [Microsoft SQL Server に接続する](https://qiita.com/RyoWakabayashi/items/ab1ce456eaa14b1da6f8)
- Day5: Vim と Emacs のキーバインド　 <- ここ

Day 5 は定番エディターと同じ操作ができるようになる設定です

https://news.livebook.dev/vim-and-emacs-key-bindings---launch-week-2---day-5-VfcA0

## キーバインドの設定

Livebook のホーム画面から左メニュー **Settings** をクリックします

設定画面が開くので、一番下 **Code editor** の **Key bindings** から設定を変更します

選択肢は以下の3つ

- Dafault
- Emacs
- Vim

![スクリーンショット 2023-11-12 21.26.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/2552c917-7010-920d-7926-9113388a1b5f.png)

ちなみに Livebook のショートカットキーは左メニューの下から2番目、キーボードアイコンで確認できます

![スクリーンショット 2023-11-12 21.54.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/ad964650-df98-6b72-6849-3be00788ae95.png)

![スクリーンショット 2023-11-12 21.58.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/15cd7cb2-9d0a-6f63-437c-1b1695a63d4d.png)

## Vim のキーバインド

キー操作が分かるよう、 Section の右側に入力しているキーを表示しました

単語単位の移動や行コピー、ペースト、削除、挿入モードへの切り替えなど、 Vim と同じ操作ができています

![vim.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/a4d302a5-654d-10ba-6e98-729aa42fd797.gif)

Vim のキーバインドについては @Daisuke_MMM さんの記事にまとめられています

https://qiita.com/Daisuke_MMM/items/163f9f82f48dee6d7456

## Emacs のキーバインド

こちらもキー操作が分かるよう、 Section の右側に入力しているキーを表示しました

単語単位での移動など、 Emacs のキー操作ができています

![emacs.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/df21d9dd-6e45-7327-d9db-7625cbdbec40.gif)

Emacs のキーバインドについては @ikemo さんの記事にまとめられています

https://qiita.com/ikemo/items/a98ad937c28cc67bb34b

## まとめ

正直私はそんなに Vim を使っていませんが（サーバー上で使うくらい）、普段から Vim を使いこなしている人にとっては生産性がかなり上がるでしょう

細かいところまで親切設計です

## 補記（キー操作の表示ツール）

キー操作の表示については ShowKeys を使用しました

https://github.com/jmhobbs/ShowKeys

今回初めて使いましたが、かなり便利なので今後も使いたいです
汎用掲示板ビューアSikiを使う。またはjdimとか。


この程、５ちゃんねる、talk、open2chにアクセスしなければならなかったので、各サイトの専用ブラウザを使っていましたが、アクセスするのに非常に煩雑で、探せば汎用掲示板ブラウザのSikiというブラウザに巡り逢いました。掲示板にアクセスするのは、一般のネットサーフィンと切り離したいので、インストールし、使っております。Sikiは少し難しいですけれど、慣れたら便利です。

### ダウンロード

https://sikiapp.net/download/

### インストール

Sikiのサイトからの引用です。

```
・ダウンロードしたAppImageファイルを任意の場所に置きます
・Siki.appimageに実行権限を与えて実行してください
・起動しない場合--no-sandboxオプションを付けて起動してください
・Sikiが管理するデータディレクトリは通常/home/{ユーザー名}/.config/siki/profile に作られます
・アンインストールはSiki.appimageのあるディレクトリとデータディレクトリを削除してください
```

### 設定

実用に至るまでの設定がややこしいのですが、大事なところだけ。

##### ３ペイン表示
縦３列の３ペイン表示にしたほうが良いです。理由は、スレッドを立てるときに、画面の縦ピクセルが足りなくなりためです。

##### bbsmenuの登録

Sikiを起動し、「歯車のアイコン」→「設定」→「BBSMenu」で、次の３つを登録します。

```
https://menu.5ch.net/bbsmenu.html
https://classic.talk-platform.com/bbsmenu.json
https://menu.open2ch.net/bbsmenu.html
```

各bbsmenuの入力ののち、［保存する］を押して、［更新する］を押して下さい。これで、5chとopen2chとtalkにアクセスすることができるようになります。

##### AA
SikiはAAを自動判別して、フォントを変えてくれるようですが、デフォルトでは、ちょっとずれていました。僕のシステムには既にAA用のフォントがインストールされていましたが。
Arch Linuxで、AA用のフォントのインストールは以下のようにします。

```
yay -S ttf-mona
```

AAのフォントはモナーフォントが良いです。バッチリずれないで表示されます。AA用フォントの設定は、「歯車アイコン」→「テーマ編集」→スクロールして、フォント、Ascii Artに使用されるフォントに"Mona"を設定します。

### talkへの書き込み

Sikiのtalkプラグインは現在書き込みに対応してないようです。

・レスの書き込みは、スレビューから、右クリック→「スレッド操作」→「ちょっと見る」で書き込みボックスが出てきます。
・スレッドを立てるのには、スレタイビューから、右クリック→「板操作」→「ちょっと見る」で、下の方に「新しいスレッドを立てる」のボタンが出てきます・


# またはjdim

５ちゃんねるだけにアクセスするとなると、jdimが良いので、jdimをインストールする方法も書いておきます。

AAのフォントはモナーフォントが良いので、`ttf-mona`をAURからインストールしておきましょう。

```
yay -S ttf-mona
```

jdimのインストールは次の通り。

```
yay -S jdim-git
```

時間がかかりますが、辛抱強く待ちましょう。

そして、jdimは、キャッシュを~/.cache内に作るので、キャッシュディレクトリを頻繁に削除する場合、jdimのキャッシュを、~/.jdimcacheに移します。環境変数をセットして、jdimを立ち上げるスクリプトを書き、デスクトップからはそれを呼び出すようにします。

```jdim.sh
JDIM_CACHE=~/.jdimcache jdim
```

`chmod +x jdim.sh`をして実行権限を付けておきましょう。デスクトップアイコンを押すと、これを実行するようにします。

あとはjdmを立ち上げて設定して終わりです。[設定]→[フォントと色]→[詳細設定]で、フォント指定の全てをmona regularにしましょう。
擬似言語プログラム

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457284/de4d3279-7565-17af-8803-59ff47a21686.png)
１：関数
　関数は、一連の処理を「部品」として、使えるようにするものです。関数を使うことによって、プログラムを整然と記述できるようになります。関数は、自分で作成することもできるますし、すでに、用意されているものを利用することもできます。様々な関数をまとめた道具箱のようなものをライブラリと言います。インターネットで検索すると、様々なライブラリを見つけることができます。例えば、AI処理をするライブラリなどもインターネット上で見つけられます。ライブラリ中の関数を利用することで、AI処理の理論などを知らなくても、AI技術を利用して画像認識をするプログラムを作成できます。このように、関数は、プログラムを作成するにはなくてはならないものなのです。
 　
  　関数を利用することを「関数を呼び出す」と言います。また、関数を利用する際には、処理に必要なデータを関数に渡す必要があります。関数に渡すデータを「引数」と言います。
　さらに、関数は、処理結果を呼び出し側に返却することができます。返却されてくる処理結果のことを「返却値」と言います。
Render.comのStart Commandがわからなかった

# はじめに
[Render.com](https://render.com/)でデプロイする際に、Build CommandとStart Commandが全く分からず困ったので、困った部分をメモします。
Render、Flaskともに初心者で、分からないなりに動かすために行ったことを記載しています。

# 前提
・Python3
・Flask

# 使い方
### Build Command
requirements.txtに書いてあるライブラリをインストール(pip install)する

```Build Command
pip install -r requirements.txt
```

### Start Command
app:appの1つ目のappは最初に起動するファイル名(app.pyのappの部分)、2つ目のappはコード内に書いた変数名を記載する。
```app.py
app = Flask(__name__)
...
app.run()
```
(requirements.txtにGunicornを記載)
```Start Command
gunicorn app:app
```

# 補足
APIを使った関係でgunicornのタイムアウトエラーになったのですが、後ろに`--timeout 120`(任意の数字)をつけるとタイムアウトエラーを防げます。
```
gunicorn app:app --timeout 120
```
SQLの書き順と実行順について

MySQLでエラーが発生した際、原因がSQLの書き順と実行順の違いであったことが判明しました。
そもそも、両者が違うことを知らなかったので、備忘録として残します。
# そもそもSQLとは？
リレーショナルデータベースに情報を入れたり、各種処理(検索・抽出など)したりするための言語。

:::note info 
**リレーショナルデータベースとは**
関連性のある情報を表形式でまとめているもの。
:::
# SQLの書き順と実行順
## (人が)SQLを書くときの順番
1. SELECT句：「こんな情報が欲しい」
2. FROM句：「このテーブルから欲しい情報取ってきてね」
3. JOIN句：「テーブルをこんな風に結合してね」
4. ON句：「テーブル同士をこのカラムで結合してね」
5. WHERE句：「こんな条件でデータを取得してきてね」
6. GROUP BY句：「●●列ごとの情報が知りたい」
7. HAVING句：「グループ化した後に条件を設定する」
8. ORDER BY句：「取得したデータを並び替えてね」
9. LIMIT句：「データは●●個取ってきてね」  
## (コンピューターが)SQLを実行するときの順番
**1. FROM句：「このテーブルから情報を取得するよ」**
**2. ON句：「テーブル同士がどのカラムで結合するか選ぶよ」**
3. JOIN句：「結合するテーブルを選ぶよ」
4. WHERE句：「テーブルの中でも指定された条件をもとにフィルタリングするよ」
5. GROUP BY句：「指定された列を基準にグループを作るよ」
6. HAVING句：「グループ化したものを条件にもとづいてフィルタリングするよ」
**7. SELECT句：「欲しがっている情報を取得するよ」**
8. ORDER BY句：「取得したデータを並び替えるよ」
9. LIMIT句：「データの数を絞るよ」 

**太字**の部分が違いますね。
書き順と実行順を知らないと、思わぬエラーが起こることに…！

# 実際にあったエラー例
・商品テーブル
|商品ID|商品名|値段|購入者数|商品カテゴリーID|
|:----:|:----------|:----:|:----:|:----:|
|     1|りんご|200円|8|1|
|     2|みかん|80円|14|1|
|     3|バナナ|100円|18|1|
|     4|じゃがいも|150円|5|2|
|     5|にんじん|200円|20|2|

・商品カテゴリーテーブル
|商品カテゴリーID|カテゴリー名|
|:----:|:----:|
|1|果物|
|2|野菜|

```sql:以下はエラーが発生
--カテゴリーごとの合計購入者数が30人以上なら表示する
SELECT カテゴリーID,SUM(購入者数) AS 合計購入者
FROM 商品テーブル
WHERE 合計購入者 >= 30
GROUP BY 商品カテゴリーID;
```
エラー発生の理由は、
**SQLの実行順では、「WHERE句」→「SELECT句」だから！**
SELECT句でSUM(購入者)に「合計購入者」と名前を付けたとしても、先にWHERE句が実行されるため、「合計購入者」の名前を参照できません。

:::note info
標準SQLでは同じ理由で「GROUP BY句」「HAVING句」でもASで設定した別名は参照できないようですが、MySQLでは拡張機能として両方の句で別名を参照できるようです。
:::
https://dev.mysql.com/doc/refman/8.0/ja/problems-with-alias.html
# まとめ
SQLの書き順と実行順は違います。
このことを意識して、プログラムを書かないとエラーにつながることに。
正直この実行順をすべて覚えておくことは難しいですが、繰り返しSQLを書いて覚えていこうと思います。
StreamのmapMultiはどういう時に使うのか

Java16で追加された`Stream.mapMulti`メソッドの説明が、最初はよくわからなかったので、理解したことを少し具体例を挙げてまとめてみます。

## 前置き

実は、最近までJava9より後のJavaの動向を追ってなかったので、Java21までの変更をさらっと読んできました。


## 参考資料

 * Java 16新機能まとめ
   https://qiita.com/nowokay/items/215769cdcb14d6c5412f

 * java.util.stream.Stream - Java17 API ドキュメント
   https://docs.oracle.com/javase/jp/17/docs/api/java.base/java/util/stream/Stream.html


## APIの説明にある「`flatMap`」との関係とは

APIドキュメントにはこのように書いてあります。

> APIのノート:
> このメソッドは、ストリームの要素に一対多変換を適用し、結果要素を新しいストリームにフラット化するという点で、flatMapに似ています。 このメソッドは、次の場合にflatMapよりも推奨されます:
> 各ストリーム要素を少数の(0(ゼロ))要素で置換する場合。 このメソッドを使用すると、flatMapで必要な結果要素のグループごとに新しいStreamインスタンスを作成するオーバーヘッドが回避されます。
> 結果要素をStreamの形式で返すよりも、結果要素の生成に必須のアプローチを使用する方が簡単な場合。

これを読んだだけで理解できる方は、これ以降は読む必要はないと思います。

最初、新しいStreamインスタンスというのが何のことなのか分かりませんでした。
`flatMap`メソッドを使ったことがあれば気づけそうですが、私は使う頻度はあまり高くないので、コード書いてみたらピンときました。

それぞれの要素にダッシュ要素を追加したリストを作るコードを書いてみます。（ダッシュだと見づらいのでスラッシュで代用）

```java
jshell> var data = IntStream.rangeClosed(1, 3).mapToObj(String::valueOf).toList()
data ==> [1, 2, 3]

jshell> data.stream().flatMap(x -> Stream.of(x, x + "/")).toList()
$1 ==> [1, 1/, 2, 2/, 3, 3/]
```

Javaの場合、フラット化するには一対多変換にStreamしか使えないので、その時に生成するStreamインスタンスのことを言っていたんですね。
なるほど。

そして、`mapMulti`メソッドを使うと、新しいStreamインスタンスを作らずに処理できるようになります。
型推論してくれないのがちょっと面倒ですね。

```java
jshell> data.stream().<String>mapMulti((x, c) -> {
   ...>     c.accept(x);
   ...>     c.accept(x + "/");
   ...> }).toList()
$2 ==> [1, 1/, 2, 2/, 3, 3/]
```


## ほかの例

再帰的に増幅するようなケースは`flatMap`では難しそうですので、`mapMulti`を使うとよさそうです。再帰の例はAPIドキュメントに載っているので省きます。

`filter`と`map`をまとめられるのが地味に嬉しいかも。反面、複数行になってしまいがちですね。

```java
jshell> Stream.of("AAA", "BB", "CCCCC").mapMulti((x, c) -> {
   ...>         if (x.length() >= 3) c.accept("%s=>%d".formatted(x, x.length()));
   ...> }).toList()
$3 ==> [AAA=>3, CCCCC=>5]
```


## 新しいStreamインスタンスを作らないとパフォーマンスはどうなる？

簡易ベンチマークで試してみました。

少なくとも、新しいStreamインスタンスを作らないことで速くなっているみたいです。


```java
List<String> data = IntStream.rangeClosed(1, 1_000_000).mapToObj(String::valueOf).toList();

for (int j = 1; j <= 3; j++) {

	long t;
	List<String> amplified;

	t = System.currentTimeMillis();
	System.out.print("flatMap ");
	amplified = data.stream().flatMap(x -> Stream.of(x, x + "/")).toList();
	t = System.currentTimeMillis() - t;
	System.out.printf(" %d回目 %4dミリ秒 %d個%n", j, t, amplified.size());

	t = System.currentTimeMillis();
	System.out.print("mapMulti");
	amplified = data.stream().<String>mapMulti((x, c) -> {
		c.accept(x);
		c.accept(x + "/");
	}).toList();
	t = System.currentTimeMillis() - t;
	System.out.printf(" %d回目 %4dミリ秒 %d個%n", j, t, amplified.size());
}
```

```
flatMap  1回目  187ミリ秒 2000000個
mapMulti 1回目   68ミリ秒 2000000個
flatMap  2回目  152ミリ秒 2000000個
mapMulti 2回目   33ミリ秒 2000000個
flatMap  3回目  229ミリ秒 2000000個
mapMulti 3回目   61ミリ秒 2000000個
```