OmniAICreator/Qiita-1.07M huggingface dataset:
AIエージェントデザインパターン実践：ツールレジストリ

## AIエージェントのデザインパターンを実装する

AIエージェントをLanggraphで実装する「LangChainとLangGraphによるRAG・AIエージェント［実践］入門」を読み、AIエージェントのデザインパターンを実際のユースケースに当てはめてColaboratory上で実装してみる。

https://gihyo.jp/book/2024/978-4-297-14530-9

今回は「ツールレジストリ」パターンについて実装する。ツールレジストリパターンは、LLMから利用できるツール一覧を与えて適宜ツールを利用しながら回答を作成していくデザインパターンである。後でツールを追加していくことによりAIエージェントが行うことのできるタスクの幅を広げることができ、LLMの判断でAPIを呼び出したりメールを送信したりといったアクションを実行することも可能となるため、能動的に行動できるという意味でよりAIエージェントに近いものが作成できる。

他のデザインパターンについての記事は以下にまとめている。
- [プロンプト・レスポンス最適化](https://qiita.com/k5o/items/f24ae8b8583c0f355e89)
- [リフレクション](https://qiita.com/k5o/items/8ae34e4d45d261bddad1)
- [パッシブゴールクリエイター、プロアクティブゴールクリエイター](https://qiita.com/k5o/items/b7bd1c96f3602749352a)
- [シングルパスプランジェネレータ](https://qiita.com/k5o/items/5b5db14f6203b5e7f75d)
- [投票ベースの協調](https://qiita.com/k5o/items/c0ad3c0bc34881c44bdb)
- [議論ベースの協調](https://qiita.com/k5o/items/a86f62926b66e10c0ff9)

## ツールレジストリ

ツールレジストリを実現するためには、まずLLMから利用できる各種ツールを定義する必要がある。langchainのcommunityライブラリには多くのツールが用意されており、今回はこちらのいくつかを活用するが、独自ツールを簡単に開発することもできる。ツールは、「web検索」、「wikipedia検索」、「arxiv論文検索」の３つを用意し、問題を解決する際に活用できるツールとしてLLMに渡すこととする。

実装したフローチャートは以下となる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517503/b8f0e039-d178-4b4d-9fd3-7930ae1df097.png)

https://colab.research.google.com/drive/10-vrxp_7XNmVfNgNMBQuC5YxFFVYqIzj?usp=sharing

クエリの例としては、「化学繊維を合成したい。」と入力し、化学繊維を合成するための検討事項や製造手順、取り扱いの注意事項などが回答された。
Linux : nanoコマンド

今回はnanoコマンドとその超基本操作を紹介します。

1. [nanoコマンドとは](#nanoコマンドとは)
1. [超基本操作①：ファイルの保存方法](#ファイルの保存方法)
1. [超基本操作②：nanoコマンドの終了方法](#nanoコマンドの終了方法)


## nanoコマンドとは
nanoコマンドは「ファイルの中身を編集するためのコマンド」です。これを使えるようになれば、PCの環境構築などが非常にしやすくなります。

```bash
$ nano 編集するファイル名
```

:::note warn
注意
編集するファイル名には、ファイルの拡張子まで入力してください。
:::

例：test.txtを編集する場合
```bash
$ nano test.txt
```
nanoコマンドを実行すると、次のような画面が表示されます。

![Screenshot from 2025-03-09 21-31-10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4011834/9690d294-3ec8-4819-8bb7-819324c1d620.png)

この画面が表示されたら、ファイル内容を編集することが可能です。

>入力例
![Screenshot from 2025-03-09 21-52-55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4011834/a6c01912-59c3-4bd2-80b5-b35a5dec972c.png)


## ファイルの保存方法
編集したファイルは保存する必要があります。
手順は次の通りになります。

1. ```Ctrl + O```を押す
1. ```Enter```を押す


## nanoコマンドの終了方法

編集したファイルを保存したら、```Ctrl + X```でnanoコマンドを終了します。
Rustで浮動小数点を丸めようとして知った、Pythonのround()の落とし穴

Rustを最近練習していて、小数点の値を任意の桁数で四捨五入してまとめる処理を行おうとした際にPythonより少し複雑だったので、その理由を調べたらPythonのround()の問題点を知ったので、まとめました。

## 小数点を丸める場面

RustでWEB API構築の練習をしていて、その中でBMIを計算する機能を作成しました。

BMIの計算式は下記の通りです。

```math
\text{BMI} = \frac{体重(kg)}{(\text{身長(m)})^2}
```

[参考資料](https://www.tyojyu.or.jp/net/kenkou-tyoju/koureisha-shokuji/tyojyu-eiyou.html)

BMIの計算結果に小数点が含まれる場合も多いので、一定の桁で丸めてから表示したいと思いました。

## Rustで任意の桁数で小数点をまとめる

実際にRustでは下記のように作成しました。

```rs
#[post("/bmi")]
pub async fn bmi_endpoint(req_body: web::Json<models::BmiRequest>) -> impl Responder {
    let height = req_body.height/100.0; //身長は一般的にcmで受け取るので、mに変換
    let weight = req_body.weight;
    let bmi_row = weight / height.powi(2); //BMIを計算する。powiは引数乗を計算
    let bmi = (bmi_row * 100.0).round() / 100.0; // 小数点第三位を四捨五入して、小数点２桁にする
    let category = match bmi {
        n if n < 18.5 => "Underweight",
        n if n < 24.9 => "Normal weight",
        n if n < 29.9 => "Overweight",
        _ => "Obesity",
    };
    // 構造体を生成
    let response = BmiResponse {
        bmi,
        category: category.to_string(),
    };

    // JSONとして返す
    HttpResponse::Ok().json(response)
}

```

小数点以下を丸める部分はここです。
```rust
let bmi = (bmi_row * 100.0).round() / 100.0;
```
処理の流れは次のようになっています(例：3.14159)

1. BMIの計算結果に100を掛ける(例：3.14159*100 = 314.159)
1. 少数第一位を四捨五入して整数にする(例：314.159 → 314)
1. 計算結果を100で割り、少数に戻す(例：314/100 = 3.14)

とても冗長に感じますよね。

Pythonだとroundを使って小数点以下を直接指定できます。

```py
bmi = round(bmi_row, 2)
```

## Rustの標準ライブラリにroundがない！

Rustでももっと簡単にやりたいのになぁ〜と思ったので、ChatGPTを使って調べました。
ここで明確に説明できないのが申し訳ないですが、**2進法では小数点以下の値で正確に保持できない場合がある** ということが原因です。

Pythonで実際にやってみると下記のようになります。
数学的には0.3が正しいですが、Pythonで出力される値が大きくなってしまします。

```py
>>>print(0.1 + 0.2)
0.30000000000000004
```

そのため、研究など厳密な値が求められるシーンではDecimal型などが使われるそうです。
Pythonのroundはこの誤差を許容(無視)していました。

```py
value = 1.005
rounded = round(value, 2)
print(rounded)
```

期待値は1.1ですが、実際の結果は下記のようになります。

```bash
1.0
```

1.005が実際にコンピュータ内でどのように認識されているかは下記のようになっています。
```py
>>>'{:.20f}'.format(1.005)
1.00499999999999989342
```

このような場合の誤差をPythonのroundは許容しています。
Pythonを長く使っていましたが、あまり意識してきませんでした。
Rustは低レイヤーで採用されることが多いので、このような誤差が隠されてしまうことで誤解を招くことを避けたり、精度が求められる場面では専用の型を使用することが推奨されているため、標準ライブラリとしてPythonのroundに当たる機能が搭載されていないようです。

私自身、誤差のことを考えずにPythonで使用してきてしまったので、反省です。

そして、前出のRustの処理も浮動小数点の処理が適切にできていません。
誤差が出るケースをサンプルで作成しようと思ったのですが、うまく作成できなかったのでこれからまた挑戦してみます!!

## 追記

コメントでご指摘頂きましたが、Pythonのround()がそもそも四捨五入ではなく、偶数丸めでした。
ご指摘ありがとうございました。
RAGとは、どんな仕組み？

RAGはAIが質問に答える際に、自分がすでに持っている知識だけに頼らず、質問に関連した外部の知識を検索（Retrieval）して、検索結果を踏まえて回答を生成（Generation）する方法です。


## ロボットの例えで理解しよう！

### 1. ロボット（AI）は自分の頭の中にあるデータだけを頼りに話していた。  
- 今までは、このロボットはあらかじめ与えられたマニュアル（学習済みの知識）の中だけで答えていました。
- マニュアルに載っていない質問が来ると、的外れな回答をしたり、答えられませんでした。

### 2. RAGを搭載したロボットは、外部の図書館を利用できるようになった。 
- RAGを使うロボットは、質問が来ると自分の頭の中のデータベースをまず調べます。
- さらに、図書館（外部知識）に行って質問に関連する情報を探し出します（Retrieval）。
- 図書館から必要な資料を持ち帰り、自分の知識と合わせて最適な答えを作り出します（Generation）。


### 例：天気について質問された場合

#### RAGなしロボット
  「明日の天気は知りません。私は数年前までの天気しか分からないからです。」

#### RAGありロボット
  「ちょっと待ってください。最新の気象情報を図書館で調べます…調べました！明日は晴れのち曇りです。」

---

## RAGのメリット（ロボットの利点）

- **最新情報に対応できる**：常に最新の知識を外部から調べて回答できるため、情報が古くなりません。
- **正確性が向上する**：外部の正確なデータを参照できるため、誤った回答が少なくなります。
- **専門的な情報にも対応可能**：自分の内部知識になくても、専門的な資料を外部から引っ張ってきて正しく回答できます。


このようにRAGとは、「自分の知識」と「外から調べて得られる知識」を組み合わせて、より的確で新鮮な情報を提供できる、進化したAIロボットのような仕組みです。
画像も動画もいらないくせにまだChatGPTに毎月3000円払っていたので50円に節約を試みる

# 画像も必要ないし1日５回くらい使う程度なので、ChatGPTからAzure OpenAI Serviceに切り替えた話。
普段の業務の中でちょっと翻訳に使ったり、ちょっとコード直すのに聞いたりする程度なので、
惰性で払い続けるのものよくないな。。。ということでAzure OpenAI Serviceの従量課金に乗り換えました。

これは単純に安くなるのではなく、従量課金に切り替えただけなので、Azure等使い慣れていなれておらず、費用の確認等知らない方にとっては少し注意してほしいですが、むしろそういう人にこそ役に立ってほしい記事になればと思います。
# Azure OpenAI Serviceとは
Azure OpenAIは Microsoftが Azureという クラウドサービス経由で提供する Gen AI サービスの統合環境です。
https://azure.microsoft.com/ja-jp/products/ai-services/openai-service
AWS Bedrock等の細かい比較はしていませんが、簡単にモデルを作成して利用することができます。

特徴としてMicrosoftはプロンプトのデータを学習に利用しないことを明言しており、その点でも安心できるところはメリットです。
https://learn.microsoft.com/en-us/azure/ai-services/openai/faq#data-and-privacy

UIは以下のような感じです。ちょっとAI使いたいだけの人にとっては左側のオプションは過剰でして、「チャット」だけ使えれば十分かと思います。
![スクリーンショット 2025-03-09 21.32.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256764/0bbd0b15-a312-4a4e-b238-c7eb84b4c0fa.png)

# 費用について：1週間くらい使ってみた
1週間で1日５回くらい使ったのですが、以下の料金で済みました。10円もかかっていないですね。
![スクリーンショット 2025-03-09 21.34.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256764/022f1548-68b1-462b-b721-b4452fdaa99f.png)

ただしモデルは最安値のgpt-4o-mini (version:2024-07-18)を使っているのでこの点だけ注意が必要です。
価格は下記に明記されていますので、こちらご参照ください。
https://azure.microsoft.com/ja-jp/pricing/details/cognitive-services/openai-service/
記事を書いた時点においては 100 万トークンあたり以下の価格になっていました。
- 入力: ¥22.42576
- キャッシュされた入力: ¥11.2129
- 出力: ¥89.7031

# Azure AI Foundry portal
もちろん Azureの提供する機能としてシステムに組み込む豊富な機能はありますが、Azure AI Foundry portalがあればChatGPTと同じ画面は用意できます。
![スクリーンショット 2025-03-09 21.38.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256764/27e187fd-12af-448f-a439-33ad9522acd0.png)
この「モデルと価格」できないことは、画像生成や検索・最近だとSoraの動画生成などChatGPTではできるようになりましたが、そういったことはできないです。
ただただ文章レベルのやりとりが可能です。（もちろん Azure OpenAI もお金を積めば大丈夫です。たとえば画像生成であればDall-E-3：標準：1024 * 1024の画像100件あたり¥598.021です。

# 最後に
あくまでも従量課金ですし、モデルの選択等間違えると一気にお金がかかったりします。慣れない人は慎重にチャレンジしてください。
従量課金なので2、3日使ってみてその時の金額と使用感を見ながら継続するかどうかご判断ください。

またAzure自体初めての方は、まずはAzureが何か理解してからの利用を推奨します。

色んな良記事がありますので、ぜひご覧ください。
- https://qiita.com/YoshiakiOi/items/90d8162fc9fcfc3b01f1
- https://qiita.com/taiki_yoshida/items/86390f68e0c3aff8fcc4
Pythonで土日を判定する

Pythonで土日を判定するには、datetime.weekday()を利用します。

## weekday()

`dateime.weekday()` で取得する値は以下の通りです。

0: 月曜日
1: 火曜日
2: 水曜日
3: 木曜日
4: 金曜日
5: 土曜日
6: 日曜日

今回は `5` と `6` の場合は休日と判断する関数（`is_holiday`）を作ってみます。

```python weekday_test.py
import datetime

def is_holiday(dt: datetime):
    """
    休日か判定する
    """
    weekday = dt.weekday()
    print(weekday)
    if weekday == 5 or weekday == 6:
        # 土日
        return True
    else:
        # 平日
        return False

def main():
    """
    休日か判定するサンプル
    """

    # 金曜日
    dt = datetime.datetime(2025, 3, 7)
    print(dt)
    print(is_holiday(dt))

    # 土曜日
    dt = datetime.datetime(2025, 3, 8)
    print(dt)
    print(is_holiday(dt))

    # 日曜日
    dt = datetime.datetime(2025, 3, 9)
    print(dt)
    print(is_holiday(dt))

if __name__ == '__main__':
    main()
```

```bash:実行結果
2025-03-07 00:00:00
4
False
2025-03-08 00:00:00
5
True
2025-03-09 00:00:00
6
True
```

今回は `datetime` を利用しましたが、`calendar` を利用する方法もあります。
AIエージェンシー: 本当に稼げるのか

「AIエージェンシー」は本当に稼げる有望なビジネスでしょうか？

興味深い体験談がありましたので見ていきましょう。

https://www.reddit.com/r/AI_Agents/comments/1j6vjvf/wanting_to_start_your_own_ai_agency_heres_my/

---

近年、AIエージェンシービジネスの可能性に関する情報が溢れています。YouTubeなどでは「AI開発で月に700万円稼げる」といった派手な宣伝文句も踊っているそうですが、現実はどうなのでしょうか。この記事では、実際にAIエージェンシーを運営している人の体験談を基に、現実的な視点からこのビジネスモデルについて考察します。

## AIエージェンシーとは

AIエージェンシーは、AI技術を活用したソリューションを企業や個人に提供するビジネスです。具体的には以下のようなサービスが含まれます：

- カスタマーサポートの自動化
- データ分析と洞察の提供
- コンテンツ生成の効率化
- 業務プロセスの自動化

このビジネスモデルの本質は、単にAI技術を提供することではなく、クライアントの具体的な事業課題をAIによって解決することにあります。

## ステップ1：AIエージェントの技術習得

AIエージェンシーを始めるには、まず技術的な基盤が必要です。以下のような基本スキルの習得が重要だそうです：

### カスタマーサポートAI
FAQや一般的な問い合わせに自動で対応するシステムの開発は、最も基本的なスキルの一つです。これには大規模言語モデル（LLM）のAPIを活用することが一般的です。

### パーソナルアシスタントAI
リマインダー設定、メール整理、スケジュール管理などの基本タスクを自動化するアシスタントの開発もニーズがあるそうです。

### タスク自動化システム
データ収集、文書要約、情報整理など、特定業務の効率化を目的としたシステム開発も重要なスキルセットです。

実際の開発経験を積むために、次のようなプロジェクトから始めることが推奨されています：
- 定期的に情報を配信するボットの開発
- コンテンツ要約ツールの作成

これらの開発経験は、単なるスキルアップだけでなく、ポートフォリオとしても機能します。

## ステップ2：実績の構築

技術的な基盤ができたら、次は実績を築く段階です。この段階では、**無償**でのサービス提供が効果的な戦略とされています：

- 友人や家族などのパーソナルネットワークへのサービス提供
- 小規模なケーススタディの実施

例えば：
- フィットネストレーナー向けのトレーニングプラン生成ツール
- カフェなどの小規模店舗向けの自動応答システム

この段階の目的は利益を得ることではなく、ソリューションの有効性を証明し、推薦文や実績を集めることです。これらは次のステップで大きな価値を持つそうです。

## ステップ3：地域ビジネスへのアプローチ

初期の実績ができたら、地域の小規模ビジネスにアプローチするのが効果的です。ここでのポイントは：

- コスト効率：**クライアントのAPIキーを使用する**ことでコストを抑制
- 具体的な価値提供：業務時間削減や顧客対応改善など、明確なメリットを示す

業種別の具体例としては：
- 不動産業：物件説明の自動生成ツール
- 自動車販売：テストドライブ予約や問い合わせ対応の自動化

これらのプロジェクトから得られる実績と推薦文は、事業拡大のための重要な資産となります。

## ステップ4：ビジネス基盤の確立

いくつかの実績ができたら、正式にビジネスとしての体制を整えます：

- 事業名とブランディング
- 専用ウェブサイトの構築
- 実績と推薦文の掲載
- 専門知識の発信

ウェブサイトは複雑である必要はなく、サービス内容と価値提案を明確に伝え、実績を示すことが重要です。ロゴやデザインに過度に時間をかけるよりも、まずは基本的な情報発信の場を整えることが優先されます。

## ステップ5：類似ビジネスへの展開

基盤ができたら、成功実績のある業界内で横展開を進めるのが効率的です。アプローチの例：

「御社と同業の〇〇様向けに開発したAIシステムにより、週に5時間の業務効率化を実現しました。同様のソリューションについてご説明させていただけませんか？」

すでに成功した業界に特化することで、信頼性の構築と成約率の向上が期待できます。

## ステップ6：サービスの体系化

複数の成功事例ができたら、サービスを体系化して事業拡大を図ります：

- サービスパッケージの明確化
- 継続収益モデルの構築（月額サポートなど）
- マーケティング活動の拡大

サービス例：
- スタンダードプラン（5万円〜）：基本的なAIアシスタント構築
- プロフェッショナルプラン（15万円〜）：既存システム連携と高度なカスタマイズ

## ステップ7：持続的成長と現実的な展望

AIエージェンシービジネスの成功には、持続性と現実的な期待値の設定が重要です。多くのクライアントはAI技術の価値をすぐには理解しないため、地道な教育と価値提案が必要です。

「月700万円」といった収益例は例外的なケースであり、一般的には堅実な成長を目指すべきだとしています。しかし、具体的な業務課題解決に注力することで、安定した収益基盤の構築は十分に可能です。

## 知識共有の重要性

AIエージェンシービジネスでは、専門知識の共有が信頼構築に重要な役割を果たします。ブログやSNSでの情報発信は、潜在顧客の獲得と業界での地位確立に役立ちます。「公開しながら構築する」姿勢が推奨されています。

## まとめ

ここまで読んで、「月700万円」という夢が壊されたように感じますか？それとも役に立ちそうなアドバイスだと思えたでしょうか？

AIエージェンシービジネスの現実は、派手な宣伝文句とは少し異なります。しかし、適切なアプローチで取り組めば、確かに持続可能なビジネスになり得るかもしれません。一夜にして大金を稼ぐことは難しいかもしれませんが、段階的な実績構築と価値提供に焦点を当てることで、着実に成長するビジネスモデルです。

成功の鍵は、技術力だけでなく、クライアントの事業課題を理解し、それに対する適切なソリューションを提供する能力かもしれませんね。AIはあくまでツールであり、その真の価値は具体的な問題解決です。
音声のフーリエ変換

環境：MATLAB R2018b
内容：ビープ音のパターンマッチングの勉強メモ
~~~~~~.mlx
[AmpLv, Fs] = audioread('bleep-41488.mp3');
disp(Fs); % サンプリング周波数=24000hz

N = length(AmpLv); % サンプル数
time = (0:N-1) / Fs; % 時間軸
disp(N/Fs); % 総時間=5.018sec

% 時間領域のプロット
figure;
plot(time, AmpLv);
xlabel('Time [s]');
ylabel('Amplitude');
title('Time Domain Signal');

% FFT計算
fftAmpLv = abs(fft(AmpLv)); % フーリエ変換
lenfftAmpLv = length(fftAmpLv);
x_freq = (0:lenfftAmpLv/2-1) * Fs / N; % 周波数軸
y_freq = fftAmpLv(1:lenfftAmpLv/2) / N; % 振幅正規化

% 周波数領域のプロット
figure;
plot(x_freq, y_freq);
xlabel('Frequency [Hz]');
ylabel('Amplitude');
title('Frequency Domain');
grid on;
~~~~~~
![beepSound.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3181208/d8384e97-e4c5-47b1-92fd-1fdccd4d46d2.png)


![フーリエ変換後のBeepSound.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3181208/1c24084c-ca5e-421f-8e56-5e5e36438a9f.png)

単純なビープ音なら、周波数で何のビープ音か判別できるかもしれません。
ESPnet2（JSUT）を実行してみる

# 前書き
tts(text-to-speech)を実装してみようと思った

## 環境
- Google Colab
- Python3.11

## インストール
```bash
!apt install cmake
!apt install python3-dev
```
```bash
!pip install flash-attn --no-build-isolation
!pip install espnet
!pip install pyopenjtalk
!pip install espnet_model_zoo
```

## 実装コード
```py
import argparse
import numpy as np
import torch
from IPython.display import Audio
from espnet2.bin.tts_inference import Text2Speech
from espnet2.utils.types import str_or_none
```
今回は[JSUT](https://sites.google.com/site/shinnosuketakamichi/publication/jsut)を利用してみようと思うので、tagに指定します
```py
lang = 'Japanese'
tag = 'kan-bayashi/jsut_full_band_vits_prosody'
```
text-to-speechの設定を入れていきます
```py
text2speech = Text2Speech.from_pretrained(
    model_tag=str_or_none(tag),
    vocoder_tag=str_or_none('none'),
    device = "cuda",
    threshold=0.5,
    minlenratio=0.0,
    maxlenratio=10.0,
    use_att_constraint=False,
    backward_window=1,
    forward_window=3,
    speed_control_alpha=1.0,
    noise_scale=0.333,
    noise_scale_dur=0.333,
)
```
今回テキストのインターフェースを設けずに、直接関数内で指定するようにします
また`<pause>`を指定することで間を設けるようにします

```py
text = "こんにちは。本日は花粉が凄く<pause>くしゃみが止まりません。"
```
`<pause>`の設定をします
```py
pause = np.zeros(30000, dtype=np.float32)
sentence_list = text.split('<pause>')
```
音声ファイルのリストを作ります
```py
wav_list = []
for sentence in sentence_list:
  with torch.no_grad():
    result = text2speech(sentence)["wav"]
    wav_list.append(np.concatenate([result.view(-1).cpu().numpy(),pause]))
```
実際に聞いてみましょう
```py
finale_wav = np.concatenate(wav_list)
Audio(finale_wav, rate=text2speech.fs)
```
(Qiitaにはどうやって貼り付けるのでしょうね。。。)
GitのコミットメッセージのPrefixを決めておく

<!-- GitのコミットメッセージのPrefixを決めておく -->

## はじめに

大学のサークルで一緒の人が以下のような記事を投稿していたのを見かけました。

[僕のコミットメッセージの prefix メモ](https://ryota2357.com/blog/2025/my-commit-prefix-memo/)

なるほど、コミットの種類によってPrefixを使い分け、そのあとに本命のメッセージを書くことによって、コミットの種類を明確化することができるわけですね。

自分は適当に「○○した」とかで済ませていましたが、これだとぱっと見で分かりづらいです。彼のように「Prefix+メッセージ」のような形式にすれば、Prefixでコミットの概要を、メッセージでコミットの詳細を知ることができそうです。

どうやら彼のコミットメッセージには[ベース](https://github.com/angular/angular/blob/2d8fa73c1d6cce078889548c69b8ddb8e84ac106/CONTRIBUTING.md#-commit-message-format)があるらしいです。自分もこれを参考にして、コミットメッセージを分かりやすくしようと思います。

## 考えてみた

### フォーマット

```
<type>: <message>
```

ベース記事では``<type>(<scope>)``という感じで``scope``をつけていましたが、あんまりピンと来ないのでとりあえず考えないこととしました。

将来的に``scope``を考慮することが増えてきたらまた考えます。

### ``type``

今回の企画の肝ですね。これを上手く決めることでコミットの概要が分かりやすくなるはずです。

#### ``env``

環境構築関連の変更をした際に用います。

#### ``ci``

CIとは「継続的インテグレーション」の意味で、コードの変更を自動でビルド・テスト・デプロイする仕組みのことです。GitHub Actionsなどが有名ですね。

そういったCIの設定を変更した場合にこのPrefixを使います。

#### ``docs``

ドキュメントの更新・修正を行った際に使います。

主には``README.md``がドキュメントになりますが、開発が大規模になってくると要件定義書とかが含まれる可能性があるので、それらの更新時にも使います。

#### ``feat``

新規で何かを追加した際に用いるものです。

新規機能、新規モジュールなど、とにかく何か新しいものを追加した時に使います。

#### ``fix``

バグの修正を行った際に使います。

バグというのは何処かを書き間違えた程度のものではなく、直すのにある程度手間がかかるものとします(依存関係など)。

ちょっとしたミスを修正した際のPrefixは別に用意します。

#### ``correct``

ちょっとしたミスを修正した際に使います。

「ちょっとしたミス」とは、typoやインデントのミス、誤字脱字、何かの消し忘れなどを指します。

#### ``style``

コード内の空白や改行など、スタイルのみの変更を行った際に用います。

スタイルを変更することでコードが見やすくなり、あとからの保守がしやすくなります。

#### ``perf``

パフォーマンスの向上を行った際に使います。

元々正常に動作していたコードに対し、アルゴリズムをよりよいものに変更したり、無駄な処理を減らしたりといった最適化をした時に用いることとなります。

#### ``refactor``

リファクタリングを行った際に使います。

リファクタリングとは、外部から見た振る舞い、つまり入出力の仕様を変えずにコードの内部構造を変更することです。

すでに動いている機能を停止させず、コードの見通しをよくするために行う作業です。こうしておくことで、業務を続けつつ後からのメンテナンスがしやすくなります。

#### ``test``

テストの追加・修正を行った際に使います。

Gitではブランチ機能があるので、テスト用ブランチを用意して他のブランチに影響を与えないようにしつつテストを行います。

様々な入力を用意し、想定の結果が得られるかどうかをテストとして行います。

#### ``review``

コードレビューを行った際に用いるものです。

コメントの追加などがレビューにあたるかな、と思います。

#### ``update``

何らかのアップデートを行った場合に用います。

パッケージやライブラリのアップデートをしたときに使うことが多いでしょう。

#### ``chore``

その他の変更を行った際に使います。

「その他」と一括りにしてしまうと分かりづらいので、できるだけ使わないようにしたいです。

### ``message``

英語か日本語。チームに合わせるべきですが、個人開発ならどっちでも良いと思います(英語のほうが勉強になる)。

基本的に短く書き、長くなる場合は2行目を空行としてそれ以降に記述する方式を取ります。

```
<type>: There is a short summary!
```

```
<type>:

There are long messages!
Foo Bar Baz Qux Quux Corge Grault Garply Waldo Fred Plugh Xyzzy Thud...
```

## おわりに

コミットメッセージをフォーマットすることによって、後から見た時に履歴が分かりやすくなって良いと感じました。

チーム開発でならチームの方針に従うことが重要ですが、個人開発などでは今回決めたフォーマットをどんどん利用していこうと思います。

それではまた。

## 参考文献

[僕のコミットメッセージの prefix メモ](https://ryota2357.com/blog/2025/my-commit-prefix-memo/)

[angular/CONTRIBUTING.md at 2d8fa73c1d6cce078889548c69b8ddb8e84ac106 · angular/angular](https://github.com/angular/angular/blob/2d8fa73c1d6cce078889548c69b8ddb8e84ac106/CONTRIBUTING.md#-commit-message-format)
APIについて

## APIとは？？
APIはApplication Programming Interfaceの略
Interfaceは何かと何かを「繋ぐ」という意味を持つ

つまりAPIとはあるアプリケーションを他のアプリケーションやツールと繋ぐことで、機能を共有できたりするもの
(APIはアプリケーションの窓口)

### WEB API
HTTP・HTTPS通信によってやりとりするAPIのこと
HTTP・HTTPS通信のやり取りなので、プログラミング言語が異なるアプリケーション同士であっても連携できたり、Webブラウザでも利用できる

## APIのメリット
・ソフトウェア開発の効率化
・セキュリティの向上
・最新情報を簡単に取得可能

## APIのデメリット
・提供やアップデートが終了してしまう可能性がある
・不具合が発生しても自力で解決できない
・利用に応じて費用がかかる場合がある

## 代表的なwebAPI
### google maps API
https://developers.google.com/maps/documentation/javascript?hl=ja

Google Maps をウェブサイトに表示することができる
企業や飲食店の所在地などを表示させるページで活用される

### Twitter(X) API
https://developer.x.com/ja/docs/x-api

外部アプリケーションからの投稿や投稿のリアルタイム表示が可能

### OpenAI API
https://openai.com/index/openai-api/

入力された文章の解析や画像生成
複雑な推論が求められる処理(チャットボット等を作成可能に)
【Vite + React】ローカル開発で画面が表示されない問題を解決した話


## はじめに

【時間がない方向け】
**4.まで読み飛ばして解決策をチェックしてください！**

Vite + React でローカル開発をしていた際に、ブラウザで `localhost` にアクセスしても画面が表示されないという問題に遭遇しました。<br>
最終的に `index.html` をルートディレクトリに移動することで解決しましたが、その過程で試したことや気づいた点をまとめます。

---

## **問題発生**
### **現象**
Vite を起動しても、ブラウザで `http://localhost:5174/` にアクセスすると画面が真っ白で何も表示されない。

### **環境**
- **OS**: Ubuntu 22.04（WSL2）
- **Node.js**: v18.x
- **Vite**: v4.0
- **React**: v18.x

### **ディレクトリ構成（エラー発生時）**
```plaintext
my_pjt/
├── frontend/
│   ├── public/
│   │   ├── index.html
│   │   ├── favicon.ico
│   │   ├── assets/
│   ├── src/
│   │   ├── App.tsx
│   │   ├── main.tsx
│   ├── vite.config.ts
```

**ポイント**
- `index.html` を `public/` に配置していた
- `vite.config.ts` で `publicDir` を `"/public"` に指定していた

---

## **試したことと結果**

### **1. Vite の開発サーバーを再起動**
```sh
npm run dev
```
**→ 変化なし（画面は依然として真っ白）**

### **2. ブラウザの開発者ツールを確認**
- `F12` → `Console` を確認すると、`Failed to load resource: the server responded with a status of 404 (Not Found)`
- `Network` タブで `index.html` のリクエストが `404 Not Found` になっていた

**→ Vite が `index.html` を正しく読み込めていない可能性があると判明**

### **3. Vite の `publicDir` の設定を変更**
#### **変更前（エラー発生時の設定）**
```ts
export default defineConfig({
  plugins: [react()],
  root: ".",
  publicDir: "/public",  // これが問題かも？
  server: {
    host: "0.0.0.0",
    port: 5174,
    strictPort: false,
  },
});
```
#### **変更後**
```ts
export default defineConfig({
  plugins: [react()],
  root: ".",
  server: {
    host: "0.0.0.0",
    port: 5174,
    strictPort: false,
  },
});
```
`publicDir` の設定を削除し、Vite のデフォルト動作（`public/` を自動認識）に戻す。

**→ 変化なし（依然として `index.html` が読み込まれない）**

### **4. `index.html` をルートに移動（解決策！）**
#### **ディレクトリ構成（修正後）**
```plaintext
my_pjt/
├── frontend/
│   ├── index.html  ← ルートに移動
│   ├── public/
│   │   ├── favicon.ico
│   │   ├── assets/
│   ├── src/
│   │   ├── App.tsx
│   │   ├── main.tsx
│   ├── vite.config.ts
```

### **結果**
`npm run dev` で開発サーバーを起動した後、
```sh
npm run dev
```
ブラウザで `http://localhost:5174/` にアクセスすると…

🎉 **無事に `Hello, Vite + React!` が表示された！**

---

## **考察：なぜ `index.html` をルートに置く必要があったのか？**

Vite の仕様上、`index.html` は **プロジェクトのルートディレクトリに配置されている必要がある** ため。

- Vite は `public/` ディレクトリを「静的ファイル専用のフォルダ」として扱う。
- `public/` 内の `index.html` はエントリーポイントとして認識されない。←これを知らず、時間がかかった
- そのため、`index.html` をプロジェクトのルート (`frontend/`) に移動することで解決。

---

## **結論と学び**

### **✔ まとめ**
| 試したこと | 結果 |
|------------|------|
| 開発サーバーを再起動 | ❌ 変化なし |
| 開発者ツールで 404 エラーを確認 | ✅ `index.html` が読み込まれていないと判明 |
| `vite.config.ts` の `publicDir` 設定を修正 | ❌ 変化なし |
| `index.html` をルートに移動 | ✅ **成功！** 🎉 |

### **✔ 今後の対策**
- **Vite では `index.html` はルートに配置する**
- `public/` は静的リソース専用（画像、フォント、favicon など）
- 開発時に `F12 → Console` や `Network` タブでエラーを確認

---

## **おわりに**

今回は `index.html` の配置ミスが原因で、画面が表示されない問題に直面しました。<br>
Vite の仕様を正しく理解していればすぐに解決できた問題ですが、いい勉強になりました。<br>
同じ問題で困っている方の参考になれば嬉しいです！🙌
電子工作始める時に必須なのに忘れがちのもの

基本的な工具とか部品とかは買うだろうけど
以下のものは持ってないよって人結構要ると思うので


- ニッパ
電工用しかないと結構きつい

- 電線
電線は持ってる人少ないと思う
AWG30だと皮剥き買う必要ない

- はんだ
買い忘れ多いし高いので事前に安いところで買っておく

- はんだ取り
[これ](https://www.bing.com/images/search?q=solder+wick&form=HDRSC3&first=1)
私間違えないのでっていう人は要らないと思う

- ステンレスたわし
ダイソーとかで売ってる[これ](https://jp.daisonet.com/products/4550480250687?_pos=15&_sid=f5440a119&_ss=r)後述(*1)

- 紙ヤスリ
番手の荒いもの(100番未満)後述(*1)

(*1)
はんだごてが酸化して真っ黒になるとまったく使えなくなる
はんだ送る -> たわしでとる -> 紙ヤスリでとぐ
を何回も繰り返すと復活する
ちなみに新品のはんだごてでも2時間くらいでそうなったりすることもある
flutter build_runner で freezed でmodelを作成するときに起きる、getter がないよってエラー の一時的解決方法

# エラー内容
```
Missing concrete implementations of '_$Post.toJson', 'getter _$Post.body', 'getter _$Post.createdAt', 'getter _$Post.imageUrl', and 3 more.
Try implementing the missing methods, or make the class abstract.
```

# エラーが出たファイル
```dart
/// post.dart
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:riverpod_training/function/timestamp_converter.dart';

part 'post.freezed.dart';
part 'post.g.dart';

@freezed
class Post with _$Post {
  factory Post({
    required String body,
    required String userId,
    required String postId,
    required String imageUrl,
    @TimestampConverter() required Timestamp createdAt,
    @TimestampConverter() required Timestamp updatedAt,
  }) = _Post;

  factory Post.fromJson(Map<String, dynamic> json) => _$PostFromJson(json);
}
```

# エラー再現
post.dartを作成して、ターミナルで以下のコードを叩く
```
flutter pub run build_runner build --delete-conflicting-outputs
```

その結果、`post.freezed.dart`と`post.g.dart`が作成されるが、先ほどのエラーが発生する。

# 解決方法
`post.freezed.dart`を以下のように書き加える

```diff_dart
...
// dart format off
T _$identity<T>(T value) => value;

+ final _privateConstructorUsedError = UnsupportedError(
+   'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models',
+ );

/// @nodoc
mixin _$Post {

- String get body; String get userId; String get postId; String get imageUrl;@TimestampConverter() Timestamp get createdAt;@TimestampConverter() Timestamp get updatedAt;
+ String get body => throw _privateConstructorUsedError; String get userId => throw _privateConstructorUsedError; String get postId => throw _privateConstructorUsedError; String get imageUrl => throw _privateConstructorUsedError;@TimestampConverter() Timestamp get createdAt => throw _privateConstructorUsedError;@TimestampConverter() Timestamp get updatedAt => throw _privateConstructorUsedError;
/// Create a copy of Post
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$PostCopyWith<Post> get copyWith => _$PostCopyWithImpl<Post>(this as Post, _$identity);

  /// Serializes this Post to a JSON map.
-    Map<String, dynamic> toJson();
+    Map<String, dynamic> toJson() => throw _privateConstructorUsedError;


```
有料アプリをクローズドテストする時の費用について

# はじめに

私は有料アプリを個人開発しました。
アプリリリースに必要なクローズドテストで疑問が出てきました。

テスターが有料アプリをクローズドテスト実施する上で、
有料アプリの代金をテスターが払う必要があるのか？

私のアプリは800円の有料アプリとしているので、テスターにも
800円の費用を払わせるのは申し訳ない。
クローズドテスト実施期間中だけ、無料アプリとする必要があるのか？
といった疑問が沸いてきました。

## クローズテストとは
2023年11月以降、新たにリリースするAndroidアプリに対して、次の要件が課せられることになりました。
・12人以上のテスターを集め、14日間以上連続でクローズドテストを実施する必要がある。

## 疑問を解決するためにしたこと
12人のテスターを集めるのはしんどいので、私は元々からクローズドテストの代行サービスを利用しようと考えておりました。
そのため、代行サービスを提供している方に質問を行いました。

結論としては、テスターのみ無料にする設定があるとのことでした。
※正確には指定したユーザのみ無料扱いにすることができる。

# 設定方法
１．Google play consoleにアクセス
２．「設定」にアクセス
３．「ライセンステスト」にアクセス
４．「メーリングテストの作成」にアクセス
５．費用を免除したい方のGoogleアカウントのメールアドレスを登録する
６．ライセンス応答では「RESPOND_NORMALLY」を選択する

設定の仕方について、資料にしてくださり、設定が簡単になるようCSVも提供して
いただいたので、設定は数分で完了しました。
資料が分かりやすかったこと、対応が丁寧だったこと、レスポンスが早かったことなどから、
下記、代行サービスを使ってクローズドテストを乗り越えました。

https://coconala.com/services/3461006
Microsoft Office365にはどのくらい機能があるのか？

# はじめに
Microsoft Office365を業務で使っているが、契約プランによって使える機能使えない機能があることを知った。

今のところ不自由なく使えているが、そもそもOffice365のサービスはどのくらいあるのか？

まだ知らないサービスを知り、さらに活用できるサービスを増やしたいと思い調べることにした。


# どんな契約プランがあるのか
まずは自分の働いている会社がどのプランで契約されているのかを確認する。
主要なプランは以下サイトにまとめられているので、そこから調べると良いだろう。
※プランは随時変わる可能性があるため情報のソースには注意

https://www.quest.co.jp/column/microsoft365-app.html

中小企業向けと大企業向けの判断基準は分からないが、大企業向けのプランのほうが月額が高く使用可能なサービスも多い。

似た名称のプランもあり思いのほか契約プラン数は多い。
ネットワークエンジニアなら一度は使うであろうVisioはやはりプランに含まれてはいない。

上のサイトではMicrosoft 365 E5が最も充実したプランといえる。
しかし会社として契約していても、会社の管理者が制御していると全てを使用できる訳ではないため注意してほしい。


# 提供サービス一覧
Microsoftのページを見ると非常に沢山のサービス・アプリを提供していることが分かる。
アルファベット順に並んでいるサービスを数えるとおよそ50ある。
多い印象があるがD列を見るとDefenderの機能がアプリやプランによって、変わって提供されているように見える。

最も充実したプランを契約したから全てのサービスを利用できる訳ではないようだ。
特にセキュリティ系のサービスは自分が手を動かして使うよりも、標準搭載されていたりバックグラウンドで動いていたりするのだろう。
ネットワークエンジニアなら一度は使用するVisioは、そもそもプランには含まれていない。

https://www.microsoft.com/ja-jp/microsoft-365/products-apps-services

※サービス終了している、サービス終了予定のものがないかは必ず確認すること

サービス一覧の中で、自分がよくわかっていないもの、今後活用できそうなものを探していく。


# 活用できそうなもの（企業によるのは大前提です）
- Lists
　Listsの使い方を調べるとExcelと比較されているサイトが複数見かけられた。
 　Excelと違って関数やマクロ機能はないが、単純な「データの蓄積」という点ではListsが向いていそうだ。
　ハードウェアの資産管理。バージョンやEoSLの管理等だろうか。個別にツールを契約せずにお試しで使ってみるのも良さそうだ。
 
https://www.microsoft.com/ja-jp/microsoft-365/microsoft-lists

- Loop
　Loopはプロジェクトチーム、組織単位でワークスペースを作成して、ファイルリンクの共有やタスク管理ができるアプリのようだ。
　Teams会議で表示されるメモタブから議事メモを取るとLoopに保存されるのは確認していたが、情報共有のツールとして非常に有効そうだ。
　Teamsのチャネル機能に似ている印象だが、Teamsチャネルはチャット機能の要素が強くコミュニケーションツールとしての役割が大きいと思う。
 　その点Loopはファイル共有のしやすさに長けているので、コミュニケーションよりもタスクが明確化していたり、作成ドキュメントの多い案件の管理には向いているのかもしれない。
 
https://www.microsoft.com/ja-jp/microsoft-loop

- Planner
- To Do
　正直この２つは調べてもピンと来なかった。
 　簡潔に言えばTo Doは個人のタスク、Plannerは共有タスクを管理するのに適しているようだ。
  　共通点はどちらもTeamsと連携することでタスクの見える化が行えること。慣れれば使いやすいのだろうが、使ったことのない身からするとタスクを登録していく作業が煩雑に見える。
    楽に登録できる方法あるのなら実用化が考えられそうだ。手動で管理するのであればLoop, Plenner, To Do全てを業務で使う必要はないと思う。

https://support.microsoft.com/ja-jp/office/to-do-%E3%81%A8planner-1044260a-3ac9-4006-aa27-f84476a03d23


# まとめ
　Microsoftのサービスをもう少し使いこなせれば、組織内の情報共有やタスク管理が行いやすくなると分かった。
  複数案件のタスクを並行で対応するとキャパオーバーする傾向にあるので、案件単位でタスクを見える化すればそういったこともなくなるのだろう。

　Teamsにアプリを連携させて使っていたが、チャットで流れてしまい欲しい情報を探すのに手間取ることがある。暫くは自分でLoopを使ってみて組織運用の手法も考えたい。

# 参考文献
各トピックに記載
人生初LTのスライド構成をどう考えたか？PREP法の視点

## はじめに
先日、社内LT会にて人生で初めて登壇する機会があり、「情報発信はコスパ最強！」というテーマで登壇してきました。PREP法を使って内容を組み立てたところ、思いのほか好評だったので、その裏側をシェアします！

## PREP法を活用したスライド構成
今回の登壇では、「PREP法」を使ってスライドを組み立ててみました。

PREP法とは、
<code>Point（結論）→ Reason（理由）→ Example（例）→ Point（結論の再提示）</code>
という流れでプレゼンを組み立てる手法です。

また今回は、ただ単に情報を伝えるだけでなく、聴衆の初期状態と最終的なゴールを明確にして、そのギャップを埋めていくストーリーを意識しました。

https://makefri.jp/work/7551/

### 聴衆の初期状態（Start）と目標（Goal）を明確化
効果的な登壇をするために、まず以下の2点を明確にしました。

<strong>【聴衆の初期状態（Start）】</strong>
<ul>
<li>聴衆の最初の認識：「櫻井くんっていうエンジニアが『情報発信はコスパ最強！』というテーマで話すらしい」</li>
<li>聴衆の心の声：「櫻井くんって情報発信してるの？」「コスパ最強ってどういうこと？」</li>
</ul>


<strong>【目指すゴール（Goal）】</strong>
<ul>
<li>聴衆に「よし、自分もテックブログ書いてみようかな！」と思ってもらうこと</li>
</ul>

今回は、この「Start」と「Goal」のギャップを埋めるために、どのように話を進めていくかを考えました。
聴衆の認識を少しずつ変化させ、最終的な行動を促す流れを作りたかったんです。


## スライドの流れは聴衆の認識変化に沿って設計
この「Start」から「Goal」へのギャップを埋めるために、以下のような流れでスライドを構成しました。

### スライド①：情報発信のメリット紹介
情報発信で得られる3つのメリットを自分の経験を交えて紹介しました。
#### 1. いろんなチャンスが広がる
個人事業主で活動をしていた過去があり、その際にXなどのSNSで情報発信を行い
そこでできた交友関係の仕事仲間から案件をいただくというような活動をしていました。
#### 2.会社に貢献できる
社内の技術ブログに投稿した記事が、採用活動や会社のブランディングに役立った実例を共有しました。エンジニア視点の記事が、意外と会社の魅力発信になっていたんです。
#### 3.やり方次第で意外と簡単
情報発信って大変そうに聞こえますが、日々の業務で気づいたことを少しずつまとめるだけでも価値があるんだよ、というお話をしました。


:::note info
<strong>この時点での聴衆の認識変化</strong>
「情報発信にはこんないいことがあるんだ！でも、ちょっとめんどくさそう？」
:::


### スライド②：社内の情報発信の場を紹介
思ったより身近にある情報発信の機会について紹介しました。

<ul>
<li>社内ドキュメントを充実させる</li>
<li>チーム内の技術共有会議で話してみる</li>
<li>社内技術ブログに投稿してみる</li>
<li>社外向けテックブログに寄稿する etc...</li>
</ul>
それぞれ「意外と簡単に始められるよ」というメッセージを伝えました。

:::note info
<strong>この時点での聴衆の認識変化</strong>
「あ、意外とハードル低いのかも！」
:::

### スライド③：具体例の提示
LT会の運営メンバーが今回のLT会についての記事を書くとどんないいことがあるか、具体例として挙げました。
#### チャンスが広がる
<ul>
<li>〇〇くん、こんな素敵なイベントを主催してくれているんだ！今度のイベント運営も任せてみたい・・・！</li>
</ul>

#### 会社に貢献できる！
<ul>
<li><a href="https://corp.menu.jp">
menu</a>（フードデリバリー事業を展開する弊社）って社内イベントが活発でいいな〜</li>
<li>登壇文化や技術共有がしっかりしてそう</li>
</ul>


:::note info
<strong>この時点での聴衆の認識変化</strong>
「おお、なるほど！いいことばかりじゃん！」
:::

<strong>作成したスライド構成</strong>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3980570/f7eb6837-2f9b-4b63-b504-815187b88cf3.png" width="600" />

## まとめ. 今回の構成設計のポイント

<strong>1. 聴衆の初期認識を把握する</strong>
「情報発信」と聞いて、多くの人は「大変そう」「時間がかかりそう」というイメージを持っています。この先入観を理解した上で話を組み立てました。

<strong>2. 具体的なゴールを設定する</strong>
単に「情報発信の大切さを理解してもらう」ではなく、「自分もテックブログを書いてみようと思ってもらう」という具体的な行動を目標にしました。

<strong>3. 認識の変化を段階的に設計する</strong>
「メリットを知る」→「ハードルの低さを理解する」→「具体例で実感する」という流れで、少しずつ聴衆の認識を変化させるよう設計しました。

<strong>4. 各スライドでの聴衆の反応を予測する</strong>
各スライド後に聴衆がどう感じるかを予測し、次のスライドでその疑問や不安に応えるような流れにしました。


## おわりに
登壇を終えてみて、「やっぱり場数は大事」 というのが率直な感想です。緊張で早口になってしまったり、伝えきれなかった部分も反省しています。ただ、「スライドの骨格」をしっかり考えたおかげで、聞き手の皆さんには概ね伝わったのではないかと思います！

今後も、登壇の機会があれば積極的にチャレンジし、さらに分かりやすい構成と話し方を追求していきたいです！

<hr>

### **▼採用情報**<br>
レアゾン・ホールディングスは、「世界一の企業へ」というビジョンを掲げ、「新しい"当たり前"を作り続ける」というミッションを推進しています。

現在、エンジニア採用を積極的に行っておりますので、ご興味をお持ちいただけましたら、ぜひ下記リンクからご応募ください。

https://recruit.reazon.jp/
openpyxlでVBAっぽくセルを扱う

## はじめに
openpyxlでブックをReadOnlyで開くとセルをインデックスアクセスしたときに異常に遅くなることから、iter_rowsを使えてなおかつVBAのCellsっぽく使えるクラス作りたくなったので作った。

```python
from openpyxl.worksheet.worksheet import Worksheet
from openpyxl.utils import column_index_from_string
from openpyxl.utils import get_column_letter
from openpyxl.cell.cell import Cell
import re
from dataclasses import dataclass

MAX_ROW = 1048576  # Excelの最大行数


@dataclass
class CellRange:
    """セルの上端、下端、左端、右端の行列番号を管理するデータクラス"""
    sheet: Worksheet
    top: int
    bottom: int
    left: int
    right: int

    @classmethod
    def from_string(cls, sheet: Worksheet, range_str: str) -> "CellRange":
        """
        Excelのセル範囲文字列（例: 'B2:P8'）を CellRange に変換する。

        :param sheet: ワークシートオブジェクト
        :param range_str: セル範囲文字列
        :return: `CellRange` のインスタンス
        """
        match = re.fullmatch(r"([A-Z]{1,3})(\d+):([A-Z]{1,3})(\d+)", range_str, re.I)
        if not match:
            raise ValueError(f"無効な範囲指定: {range_str}")

        col1, row1, col2, row2 = match.groups()

        try:
            top = int(row1)
            bottom = int(row2)

            if not (1 <= top <= MAX_ROW) or not (1 <= bottom <= MAX_ROW):
                raise ValueError(f"行番号が範囲外: {top} または {bottom} (許可範囲: 1~{MAX_ROW})")

            left = column_index_from_string(col1.upper())
            right = column_index_from_string(col2.upper())
        except ValueError:
            raise ValueError(f"無効な列名または行番号を検出: {col1}{row1} または {col2}{row2}")

        return cls(sheet=sheet, top=top, bottom=bottom, left=left, right=right)

    def get_cells(self) -> list[tuple[Cell | None, ...]]:
        """
        このセル範囲のセルデータを `list[tuple[Cell | None]]` で返す。

        :return: セル範囲のリスト（各行が `tuple` になっている）
        """
        return [
            tuple(cell if cell.value is not None else None for cell in row)
            for row in self.sheet.iter_rows(
                min_row=self.top, max_row=self.bottom,
                min_col=self.left, max_col=self.right
            )
        ]

    def cells(self, row: int, col: int) -> Cell | None:
        """
        Excelの絶対行列番号でセルを取得する（シート全体の座標基準）。
        VBAの `Cells(row, col)` に相当。

        :param row: Excelの行番号（1始まり）
        :param col: Excelの列番号（1始まり）
        :return: `Cell` オブジェクトまたは `None`
        """
        if not (self.top <= row <= self.bottom and self.left <= col <= self.right):
            return None  # 範囲外なら None を返す

        return self.sheet.cell(row=row, column=col)

    def rows_count(self) -> int:
        """
        行数を返す
        VBAの `Rows.Count` に相当。
        :return: 行数
        """
        return self.bottom - self.top + 1

    def columns_count(self) -> int:
        """
        列数を返す
        VBAの `Columns.Count` に相当。
        :return: 列数
        """
        return self.right - self.left + 1

    def address(self) -> str:
        """
        セル範囲のExcelアドレス表記を返す（例: 'A123:AB345'）

        :return: セル範囲の文字列
        """
        left_col = get_column_letter(self.left)
        right_col = get_column_letter(self.right)
        return f"{left_col}{self.top}:{right_col}{self.bottom}"

```
Auto Increment ID, UUID, ULIDの比較と選択ガイド

# はじめに
アプリ開発において、切っても切り離せないIDですが、
本記事では、以下の 3 つの ID 生成方式について、その特徴、メリット、デメリットを説明します。
- Auto Increment ID
- UUID (Universally Unique Identifier
- ULID (Universally Unique Lexicographically Sortable Identifier)

また、各方式の違いを理解し、どのIDを使用するのかの選択基準を解説します。



## Auto Increment ID（自動採番ID）

### 概要
- **仕組み**  
  データベースがレコード追加時に連番（整数値）を自動的に付与する方式。  
  例：MySQL や PostgreSQL の `INT` や `BIGINT` 型を用いる。

### メリット
- **シンプルで高速**  
  連番のため、クラスタインデックスに適しており、挿入性能が高い。
- **順序性が保証**  
  レコードの挿入順に値が増加するため、時系列性が保たれる。

### デメリット
- **分散システムでの課題**  
  単一ノード向けのため、複数のデータベース間で採番を合わせると衝突リスクが発生する。
- **予測可能性**  
  連番は容易に次の値が予測可能なため、セキュリティ上の懸念がある場合がある。



## UUID (Universally Unique Identifier)

### 概要
- **仕組み**  
  128 ビットの一意な識別子で、様々なバージョンがある。主に UUID v4（ランダム生成）が利用される。  
  例：`550e8400-e29b-41d4-a716-446655440000`  

### メリット
- **グローバルな一意性**  
  各システム間での衝突リスクが非常に低く、中央管理不要。
- **分散環境向け**  
  各ノードで独立して生成できるため、スケーラビリティが高い。

### デメリット
- **サイズが大きい**  
  16 バイト（文字列表現では 36 文字）と Auto Increment よりもストレージやインデックスに負担がかかる。


### UUID v4
**メリット**  
- 高いランダム性を持ち、衝突の可能性が極めて低い。  
- 事前の調整なしに分散システムで一意性を確保できる。  

**デメリット**  
- ランダム生成のため、順序性がなく、B-treeインデックスでの挿入効率が低下する可能性がある。  
- 可読性が低く、デバッグや手動管理が難しい。  
- 生成コストが比較的高い。  

### UUID v7
**メリット**  
- タイムスタンプベースで生成されるため、時系列順に並びやすく、B-treeインデックスの効率が向上する。  
- UUID v4と同様に分散環境での一意性を確保できる。  


**デメリット**  
- システムの時刻が適切に同期されていない場合、順序の不整合が発生する可能性がある。  




## ULID (Universally Unique Lexicographically Sortable Identifier)

### 概要
- **仕組み**  
  ULID は 128 ビットですが、先頭 48 ビットにミリ秒単位のタイムスタンプ、残り 80 ビットにランダム値を割り当て、Base32 でエンコードする。  
  例：`01ARZ3NDEKTSV4RRFFQ69G5FAV`

### メリット
- **時系列順ソート可能**  
  タイムスタンプ部分により、生成順にソートできるため、インデックスの効率が向上。

### デメリット
- **標準化の進行状況**  
  UUID ほど広く標準化されていない。



## まとめと利用シーンの考察

### 利用シーンに応じた選択
- **シンプルなシングルノード環境**  
  Auto Increment 型は、シンプルかつ高速なため、単一データベースや小規模なアプリケーションに最適。
- **分散システム**  
  分散システムでは、各ノードで独立して一意な ID を生成できる UUID（特に v4）や ULID がいい。  
  UUID v7、ULID は、タイムスタンプによる順序性があるため、インデックス効率が向上する。



## 参考文献
- [PostgreSQLで auto increment VS UUID VS ULID のパフォーマンス比較 – TerraDrone Tech](https://terra-drone.net/tech/postgresql%E3%81%A7auto-increment-vs-uuid-vs-ulid%E3%81%AE%E3%83%91%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%B3%E3%82%B9%E6%AF%94%E8%BC%83/)
- [UUID、ULID、SQID、Snowflake ID のユニークIDの選び方 – Qiita](https://qiita.com/dave_c/items/13e45495977be9f54558)
- [UUIDとULIDを理解していない方は見た方がいい記事 – Zenn](https://zenn.dev/kazu1/articles/e8a668d1d27d6b)
- [Choosing the Right ID Strategy: Auto Increment, UUID, ULID, or Snowflake ID – Medium](https://anilkumarvalluru.medium.com/choosing-the-right-id-strategy-auto-increment-uuid-ulid-or-snowflake-id-e21fe24af55f)
[AWS]ElastiCache for Valkey メモ


## Valkeyとは

- オープンソースのインメモリ型キーバリューストアで、Redisをフォークした製品。
    - 2024年3月、Redisのライセンス変更（従来のBSDライセンスから商用利用制限のあるライセンスへの変更）を受け、コミュニティ主導でフォークされたもの。
    - Linux Foundationを中心に、AWS、Google Cloud、Oracleなど主要クラウドベンダーが採用・サポートしている。  


## Redisとの違い

- **Redisとの違い**
    - コードベースはほぼ同一だが、Redisに含まれる名称やブランド部分がValkeyに置き換えられている点が大きな違い。
    - Redisと互換性があり、APIやデータフォーマットも同一のため、既存のRedis用クライアントやライブラリがそのまま利用可能。

## 利用メリット
- **コスト削減**    
    - ElastiCache for Valkeyは、Redis版と比較して料金が低く設定されている。
- **API互換性**    
    - Redis OSSと同一のAPI・データフォーマットを保持しているため、コードやアーキテクチャの大幅な変更が不要。
- **クラウド最適化**
    - AWSが積極的にサポートすることで、セキュリティ、運用の信頼性、可用性が確保される。
- **将来性** 
    - 今後、Valkey独自の機能強化や最適化（例：マルチコア対応、メモリ効率改善）により、さらに高性能なキャッシュとして活用できる可能性がある。
## アップグレード手順

1. **事前準備**
    - 現在のElastiCache for Redis OSSキャッシュのスナップショットを取得し、バックアップを確保する。
    - Redis用のカスタムパラメータグループを使用している場合、同じ静的パラメータ値を保持するValkey用パラメータグループを準備する。
2. **アップグレードのトリガー**
    - AWS CLIまたはコンソールから、既存のRedis OSSレプリケーショングループに対して、以下のように`modify-replication-group` コマンドを実行し、`--engine` パラメータに`valkey`、`--engine-version` に希望するバージョン（例: 8.0）を指定する。
        
        ```shell
        aws elasticache modify-replication-group \
          --replication-group-id myReplGroup \
          --engine valkey \
          --engine-version 8.0 \
          --apply-immediately
        ```
        
    - カスタムパラメータグループを利用している場合は、`--cache-parameter-group-name` オプションも指定する。
    - サーバーレスキャッシュの場合は、以下のように`modify-serverless-cache` コマンドを使用してアップグレードをトリガーする。
        
        ```shell
        aws elasticache modify-serverless-cache \
          --serverless-cache-name myCache \
          --engine valkey \
          --major-engine-version 7
        ```
        
3. **移行完了の確認**
    
    - ElastiCacheコンソールまたはAWS CLIで、キャッシュのエンジンが「Valkey」に変更され、ステータスが「available」になっていることを確認する。
    - アプリケーション側でGET/SET操作等の接続テストを実施し、データがそのまま保持されていることを確認する。  

## 参考文献

- **AWS公式ブログ**
    - 「Amazon ElastiCache for Valkeyの開始方法」  
        [https://aws.amazon.com/jp/blogs/news/get-started-with-amazon-elasticache-for-valkey/](https://aws.amazon.com/jp/blogs/news/get-started-with-amazon-elasticache-for-valkey/)
- **AWS公式ドキュメント**
    - 「Redis から Valkey へのクロスエンジンアップグレード OSSをトリガーする方法」  
        [https://docs.aws.amazon.com/ja_jp/AmazonElastiCache/latest/dg/VersionManagement.HowTo.cross-engine-upgrade.html](https://docs.aws.amazon.com/ja_jp/AmazonElastiCache/latest/dg/VersionManagement.HowTo.cross-engine-upgrade.html)
- **Zenn記事**
    - 「自社サービスのCacheをRedis->Valkey移行してみた」  
        [https://zenn.dev/shogo_b/articles/395a28c0ad46b4](https://zenn.dev/shogo_b/articles/395a28c0ad46b4)
【Mac / Linux】Homebrewのインストール方法【Homebrew】

様々なパッケージのインストールに必須と言っていいレベルのHomebrewのインストールを、[Homebrew公式ホームページ](https://brew.sh)に従ってインストールの方法を説明します。

# Homebrewが使える人
Homebrewが使えるのは、**Mac, Linux**の人のみです。ご注意ください。

# インストール
```zsh
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```

これだけです

パッケージのインストールは
```zsh
brew install (インストールしたいパッケージ名)
```
です。

例：neofetchのインストール
```zsh
brew install neofetch
```

# まとめ
様々な記事でパッケージのインストールに使用されているHomebrewですが、標準でインストールされていない割に使用者が多いので、解説が省かれることが多いです。

そんな人のお役に立てれば嬉しいです。
Drizzle ORM を Next.js で使ってみる

:::note
【Drizzle ORM シリーズ】
・Drizzle ORM を Next.js で使ってみる #Next.js - Qiita  
　https://qiita.com/sigeta/items/c0a2b0463eca06314906  
・Drizzle ORM でスキーマファイルを使ってDBを操作する方法 #Next.js - Qiita  
　https://qiita.com/sigeta/items/99a625c17c6a0a75da54  
・Drizzle ORM でリレーションを張る方法 #Next.js - Qiita  
　https://qiita.com/sigeta/items/b800f3e38beb1639d2b7  
・Drizzle ORM の設定ファイルを接続時も利用する方法 #TypeScript - Qiita  
　https://qiita.com/sigeta/items/d9267a06061d4d2a51e8
・Drizzle ORM でダミーデータを流し込む方法 #TypeScript - Qiita  
　https://qiita.com/sigeta/items/8bc85b74273eeb37c27a
:::

https://orm.drizzle.team/

簡単に言うと、SQLをラップしてくれるORM。
Laravel みたいにモデルを作る仕組みではなく、素のSQLを関数で組み立てて、スキーマ型で受ける仕組み。

[Kysely](https://kysely.dev/) の ORM 拡張っぽい感じ。

有名なのは [Prisma](https://www.prisma.io/) だが、スキーマが独自言語で、Prizma 自体で動かせるようなおっきいライブラリなので、そこまでは必要ないという若干の使いずらさを感じる。
Drizzle はすべてが `TypeScript` で完結しているので、シンプルで将来性が非常に高い。

ということで `Next` から `SQLite` を利用するまでのまとめです。
意外にも苦戦した...。


## インストール

`Next` の設定はデフォルトで。

:::note
利用する SQLite のドライバは `better-sqlite3` が良いかもしれない。

`libsql` のほうが新しいのだが、これは SQLite サーバーに直接接続できる機能が付いており、調査時に機能が混同していて難しかった...。時間があったら戦いたい。
:::

https://orm.drizzle.team/docs/get-started-sqlite

```bash
$ npx create-next-app@latest
✔ What is your project named? … test-next-drizzle
✔ Would you like to use TypeScript? … No / Yes
✔ Would you like to use ESLint? … No / Yes
✔ Would you like to use Tailwind CSS? … No / Yes
✔ Would you like your code inside a `src/` directory? … No / Yes
✔ Would you like to use App Router? (recommended) … No / Yes
✔ Would you like to use Turbopack for `next dev`? … No / Yes
✔ Would you like to customize the import alias (`@/*` by default)? … No / Yes

$ cd test-next-drizzle
$ npm i drizzle-orm better-sqlite3
$ npm i -D drizzle-kit @types/better-sqlite3
```

そしたら動かす RSC コンポーネントを作成する。
チュートリアルの移植だが、これ多分 `db.run()` メソッドが正しい。
`execute()` は赤線引かれる。

```tsx:lib/repository.tsx
'use server'

import { drizzle } from 'drizzle-orm/better-sqlite3'

export const dbSelect = async () => {
  const db = drizzle()
  const result = await db.run('select 1')

  return result
}
```

そしたら `pages.tsx` から雑に呼び出す。

```tsx:app/page.tsx
'use client'

import { useEffect } from "react"

export default function Home() {
  useEffect(() => {
    dbSelect().then(res => console.log(res))
  }, [])

...
```

動いた！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3833190/12ae6f1c-3850-44b2-a966-4aee53c83904.png)



時間が無いので、とりあえずここまで...

:::note
続き
Drizzle ORM でスキーマファイルを使ってDBを操作する方法 #Next.js - Qiita 
https://qiita.com/sigeta/items/99a625c17c6a0a75da54
:::
Oracle Cloud Infrastructure Architect Associate 2024(JP)を9日で合格(賞金稼ぎシリーズ)

以前のアカウントにログインできなくなりました。

https://qiita.com/bs2024/items/ae0ddc0946fcead3995b

アカウントを作り直し、賞金稼ぎシリーズの続きです。



# 賞金稼ぎは続く – Oracle Cloud Infrastructure 2024 Architect Associate 編

前回のAWS SAAに続いて、次なるターゲットをしとめました。今回の賞金稼ぎは **「Oracle Cloud Infrastructure 2024 Architect Associate（OCI Architect Associate）」** です。

## なぜOCI？

- **クラウドスキルの幅を広げたい**  という建前
  AWS、Azure、GCPがメジャーですが、OCIは **企業向けの需要が増えている** クラウドということで今後の成長が見込まれます。
  というのは当然建前でして、今回も社内の資格取得報奨金が一時的にアップ（会社として力をいれて、取得者をふやしたい）だったためです。
- **OCIの試験は無料バウチャーが手に入る**  
  あとから気がついたのですが、Oracleは頻繁に **無料試験バウチャーを配布** しており、今現在(2025/3）も5月末までの無料クーポン配布されています。コストをかけずにスキルを証明できるのはやはり魅力。

---

## 試験の概要
### 🏆 試験名:
**Oracle Cloud Infrastructure 2024 Architect Associate**  

### 📖 出題範囲（要約）
省略・・。公式サイト参照

https://mylearn.oracle.com/ou/learning-path/japanese-become-an-oci-architect-associate-2024-/140905

AWS SAA（Solutions Architect Associate）をもっていたら、ベース知識は応用できるので理解は早かった。

---

## どうやって勉強したか？
今回も「最小限の努力で合格する」スタイルを貫く。

### **1. 公式の無料トレーニング（倍速流し見）**
上記リンクのOracle公式が **無料で提供しているオンデマンド動画** をまず視聴。  
倍速で視聴して、模擬試験（無料）もあるので活用  

### **3. noteの一発合格問題集**
こちらはSNowpro coreのときにもお世話になった実績があるので迷わず購入。
大正解だった。かなりの精度にビビった。本番試験では9割以上、既視感のある問題ばかり。ありがたや。

https://note.com/data_ku/m/mfeee5ae13692


### **3. Oracle公式ドキュメント & ハンズオン**
公式ドキュメントはnoteのリンクが気になったときにクリックして軽く流し読みする程度。ハンズオンは、無料枠があるのはしっていたが全く触らなかった。実務で必要になったら触ればいいかなと。


---

## 試験を受けてみた感想
 **正直、簡単だった**  
SAAのベースがあったことと、例の問題集があったので相当時間をのこして合格。
業務時間中に勉強していいとアナウンスがあったこと、そしてプロジェクトがちょうど合間の時期だったので結果的に実質9日で合格できた。
プライベートの時間だけ使うんだったら2-3週間はかかかったと思う。多分。



---

## 次のターゲット

次は、しばらくは社内資格で賞金稼ぎをするのでQiitaには書けず。気が向いたらベンダー資格にもチャレンジしようとは思う。
[AWS]暗号化されていないRDS インスタンスの暗号化方法


* 暗号化されていないRDSインスタンスを暗号化する方法についてメモする

## 暗号化が必要な背景
- 情報漏洩や不正アクセスなどのセキュリティリスクを低減するため。
- 特に顧客情報や個人情報など機密性の高いデータを扱う場合は、暗号化が法規制やコンプライアンス基準において義務付けられる場合があるため。

## 暗号化しないと生じうるリスク
暗号化されていないRDSインスタンスは、以下のリスクがある。
- 不正アクセスやデータ漏洩時にデータが容易に読み取られる
- データベースストレージへの直接アクセスによるデータ取得が可能になる
- コンプライアンス違反による法的リスク、信用失墜、金銭的損害

## RDSの暗号化について
- 暗号化オプションはDB インスタンスの作成時にのみ有効にすることができ、作成後のインスタンスでは有効にすることができない。
- ただし、暗号化されていないスナップショットのコピーは暗号化することが可能。
- そのため暗号化してコピーしたスナップショットから暗号化されたインスタンスを復元することができる。

## 手順

- 前提
	- エンドポイントを変更したくない場合
	- サービス停止期間を許容できる場合

**1. スナップショットを作成する**
* 対象インスタンスのスナップショットを取得する

**2. スナップショットを暗号化してコピーする**
* KMSキーを選択し、スナップショットのコピーを作成する

**3. 暗号化したスナップショットからDB インスタンスを復元する**

**4.  元のDB インスタンス名を変更する**
- 元のDB インスタンス名を別インスタンス名に変更する(暗号化したスナップショットから復元したインスタンスで現在のインスタンス名を使用するため)

**5. 復元したDB インスタンス名を元のDB インスタンス名に変更する**
- 復元したDBインスタンスを、元のDBインスタンス名に変更する

**6. 暗号化されていることを確認する**
- インスタンスが起動し、作業は完了
- 暗号が有効化されていることを確認できる

**7. 元のDB インスタンスを削除する**
- 元のDB インスタンスを削除する（不要な場合は手動スナップショットもする)
Active Directory入門：PowerShell で Active Directory モジュールが読み込めない問題の解決についてまとめてみた

## はじめに

PowerShell で **Active Directory モジュール** を使おうとすると、**エラーが発生すること** があります。  

:::note info
**特に `Import-Module ActiveDirectory` の実行時に、**サーバーへ接続できない警告** が出ることがあります。**
:::

これは **Active Directory への接続に問題がある** ことを示しており、いくつかの原因が考えられます。本記事では、**エラーの主な原因とその解決方法** について解説します。

## 起きていたエラー
PowerShell で `Import-Module ActiveDirectory` を実行すると、以下のエラーが発生することがあります。

```powershell
WARNING: Error initializing default drive: 'Unable to contact the server. This may be because this server does not
exist, it is currently down, or it does not have the Active Directory Web Services running.'.
```

このエラーは、Active Directory に接続できないことを示しています。

## 主な原因（自分調べ）
1. このサーバーがドメインコントローラーではない（Active Directory がインストールされていない）。
2. Active Directory Web Services (ADWS) が動作していない。
3. このサーバーが Active Directory ドメインに参加していない。
4. ネットワークの問題（ドメインコントローラーに接続できない）。

## 実際に対応した方法

### 1. Active Directory Web Services (ADWS) の動作確認

まず、ADWS サービスが動作しているか確認します。

```powershell
Get-Service ADWS
```

- `Running` → ADWS は正常に動作している
- `Stopped` または `Not Found` → ADWS を開始する必要あり

ADWS が停止している場合、以下を実行：
```powershell
Start-Service ADWS
```
または、強制的に再起動：
```powershell
Restart-Service ADWS
```

### 2. サーバーがドメインに参加しているか確認

このサーバーが Active Directory ドメインに参加しているか確認します。

```powershell
(Get-WmiObject Win32_ComputerSystem).Domain
```

- 結果が `WORKGROUP` の場合 → ドメインに参加していない
- 結果が `ad.honda.com` などのドメイン名なら OK

ドメインに参加する場合：
```powershell
Add-Computer -DomainName "ad.honda.com" -Credential "ad.honda.com\Administrator"
Restart-Computer
```

### 3. ドメインコントローラー (DC) に接続できるか確認

ドメインコントローラー (DC) との接続をテストします。

```powershell
Test-NetConnection -ComputerName "ad.honda.com" -Port 389
```
- 成功 (`True`) → DC に接続可能
- 失敗 (`False`) → ファイアウォールやネットワーク設定を確認

LDAP（389）と LDAPS（636）のポートが開いているかも確認：
```powershell
Test-NetConnection -ComputerName "ad.honda.com" -Port 636
```

接続できない場合の対策：
- `nslookup ad.honda.com` で DNS 解決を確認
- `ping ad.honda.com` で名前解決ができるかチェック
- DNS サーバーの設定をドメインコントローラーに向ける

### 4. `Get-ADUser` を明示的にドメインコントローラーを指定して実行

もし `Import-Module ActiveDirectory` のエラーが続く場合、手動でドメインコントローラーを指定して `Get-ADUser` を試す。

```powershell
Get-ADUser -Identity Administrator -Server "dc1.ad.honda.com"
```
または、DC の IP アドレスを指定：
```powershell
Get-ADUser -Identity Administrator -Server "192.168.1.10"
```

## まとめ

| 原因 | 確認方法 | 解決策 |
|------|--------|------|
| AD Web Services (ADWS) が動いていない | `Get-Service ADWS` | `Start-Service ADWS` |
| サーバーがドメインに参加していない | `(Get-WmiObject Win32_ComputerSystem).Domain` | `Add-Computer -DomainName "ad.honda.com"` |
| ドメインコントローラーに接続できない | `Test-NetConnection -ComputerName "ad.honda.com" -Port 389` | `ping ad.honda.com`, DNS 設定の確認 |
| 明示的にDCを指定すれば動く場合 | `Get-ADUser -Identity Administrator -Server "dc1.ad.honda.com"` | `-Server` オプションを使用 |

エラーが出る場合は、詳細なメッセージを確認して対処してみてください！
SOLID原則について個人的まとめ

# 単一責任(Single responsibility)
> There should never be more than one reason for a class to change.
あるクラスの変更理由は１つより多くてはならない。

## 意味
一つのモジュール(関数やクラス)はある一つの理由（責任）によってのみ変更されること。
### 例
逆ポーランド記法で入力を行う電卓のプログラムがあったする。入力を処理するモジュールは足し算モジュールや掛け算モジュールを利用して、計算結果を出力する。
しかし、逆ポーランド記法での入力は使いずらいため、普通の電卓の計算方式に修正が必要になった。この時、修正すべきモジュールは入力の処理を行っていたモジュールにのみ限定される。
これが入力を処理や四則演算が１つのモジュールになると、複数の責任を１つのモジュールで持つことになる。

# 開放閉鎖(Open/Closed)
> software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.
ソフトウェアの実体は拡張にオープンで、修正にクローズであるべき。

## 意味
ソフトウェアが変更される時には、既存のエンティティ(クラス)を変更せずに拡張しやすくあるべき。

# リスコフの置換(Liskov substitution)
> Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.
基底クラスへのポインターや参照を使う関数はその派生クラスを知らなくても使えなければいけない。

## 意味
ある型（親クラスやインターフェース）を継承・実装したサブクラスが、親クラスの振る舞いを変更することなく、安全に置き換え可能であるべき、という原則。これにより、利用側のコード（関数やクラス）が、サブクラスの実装に依存せずに動作できる。

### 例
Dogという抽象クラスがあったとする。
```kotlin
abstract class Dog() {
    abstract fun bark():String
}

class BigDog() : Dog {
    override fun bark() {
        return "ワン"
    }
}

class SmallDog() : Dog {
    override fun bark() {
        return "キャン"
    }
}
```
DogにはBigDogとSmallDogの派生クラスがある。
ある関数ではDogクラスを引数にして、そのクラスのcall()を実行するとする。
```kotlin
fun feed(dog: Dog) {
    println("餌をあげる")
    println(dog.bark())
}
```
この時、feed()はBigDogやSmallDogの実装がわからなくてもcall()を実行することができる。
違反した例
```kotlin
class SmallDog() : Dog {
    override fun bark() {
        return 
    }
}
```


# インターフェース分離(Interface segregation)
> Many client-specific interfaces are better than one general-purpose interface.
一つの汎用的なインターフェースよりも、多くの特定用途のインターフェースの方が良い。

## 意味
必要としないモジュールには依存しない。

# 依存性逆転(Dependency inversion)
> High-level modules should not import anything from low-level modules. Both should depend on abstractions (e.g., interfaces), [not] concretions.
高いレイヤーのモジュールは低レイヤーのモジュールでインポートされるべきでない。両方は具体ではなく抽象(例えばインターフェース)に依存すべき。

## 意味


### 例
先ほどのDog関数の例で,feed()はDogにのみ依存し、その具体である。SmallDog()やBigDog()には依存していない。


# 参考
https://qiita.com/baby-degu/items/d058a62f145235a0f007
https://ja.wikipedia.org/wiki/SOLID
https://amzn.asia/d/b8ulJe6