OmniAICreator/Qiita-1.07M huggingface dataset:
docker compose upしたときにAttributeError: module 'django.db.migrations' has no attribute...'××'のエラーが出た時の対処法

```
AttributeError: module 'django.db.migrations' has no attribute '××'
```

Djangoで開発中このエラーが出た場合の対処法。
このエラーはdjango.db.migrations に ‘××’ という関数名、クラスがない、という意味でマイグレーションの状態が双方食い違っているときに起こる。

まずはコンテナ名を確認する。

```
docker ps
```

そしたらDockerの中に入る。

```
docker exec -it `コンテナ名` /bin/bash
```

そしたら`manage.py`があるところから、showmigrationsして差分を確認する。

```
python manage.py showmigrations
```

結果はこちら

```
user
 [X] 0001_ファイル1
 [X] 0002_ファイル2
 [X] 0003_ファイル3
 [X] 0004_ファイル4
 [ ] 0005_××
 ```

××が対象のファイルである時に、userの中の××がまだ適用されていないことがわかる。

その場合はmigrateしてあげる。

 ```
python manage.py migrate
 ```

また下記の場合もある。
```
user
 [X] 0001_ファイル1
 [X] 0002_ファイル2
 [X] 0003_ファイル3
 [X] 0004_ファイル4
        　.
        　.
        　.
 ```

 そもそもこのように対象のファイルが見つからない場合は、makemigrationsをしてあげると良い。

```
 python manage.py makemigrations
```

これでもう一回docker compose upしたらエラーがとれてます。


<br>
<br>
以上です。

Djangoは会社で使う機会が多いのでまたわからなくなったらまとめます。
OpenAI Agents SDKでMCPをやってみる

MCPは、Anthropicの提唱するLLMから別のシステムを呼び出す方法のひとつです。[OpenAI Agents SDKも対応した](https://x.com/OpenAIDevs/status/1904957755829481737)ことで話題になりました。

## 環境
- uv 0.6.6
- Python 3.13.2
- mcp[cli]>=1.6.0
- openai-agents>=0.0.9

### ディレクトリ構成（一部抜粋）

```
.
├── .env
├── main.py
├── pyproject.toml
├── src
│   ├── __init__.py
│   └── whattime.py
└── uv.lock
```

## 実装
現在時刻を返すMCPサーバーを実装し、AIに「いま何時？」と聞いて現在時刻を教えてくれるエージェントを実装します。

まずMCP無しの挙動を確認します。なんらかのツールが無いとうまく答えてくれません。

```python
def whattime():
    agent = Agent(
        name="Assistant",
        model="gpt-4o-mini",
    )
    result = Runner.run_sync(agent, "いま何時？")
    print(result.final_output)

if __name__ == "__main__":
    whattime()
```

`.env`に`OPENAI_API_KEY`を置いて、`$ uv run main.py`で実行します。

>ごめんなさい、リアルタイムの情報を提供することはできませんが、あなたの現在の時間を知りたい場合は、お手元の時計やスマートフォンをご確認ください。何か他にお手伝いできることがあれば教えてください！

という感じで、答えてくれません。

### MCPサーバーの構築
まずエージェントから呼び出すためのMCPサーバーを用意します。`$ uv add "mcp[cli]"`したあと、`src/whattime.py`に以下の記述をします。

```python:src/whattime.py
from mcp.server.fastmcp import FastMCP
from datetime import datetime

mcp = FastMCP("whattime")

@mcp.tool()
async def get_time() -> str:
    """現在時刻を取得する関数"""
    return datetime.now().strftime("%Y-%m-%d %H:%M:%S")

if __name__ == "__main__":
    mcp.run(transport='stdio')
```

`$ uv run src/whattime.py` しても、何かを待ち受けたまま何も起きません。
### MCPホスト・クライアントの構築
OpenAI Agents SDKでMCPのクライアント側を用意します。`$ uv add openai-agents`して、`main.py`に以下の記述をします。

```python:main.py
from datetime import datetime
import asyncio
from agents import Agent, Runner
from agents.mcp import MCPServerStdio

async def whattime_mcp():
    async with MCPServerStdio(
        params={
            "command": "uv",
            "args": ["run", "src/whattime.py"],
        }
    ) as server:
        tools = await server.list_tools()
        print(tools)
        agent = Agent(
            name="Assistant",
            model="gpt-4o-mini",
            mcp_servers=[server],
        )
        result = await Runner.run(agent, "いま何時？")
        print(result.final_output)

if __name__ == "__main__":
    asyncio.run(whattime_mcp())
```

`$ uv run main.py`で実行します。

>現在の時刻は2025年4月10日21時40分です。

成功しました。

## 余談: MCPを使わずにツールを呼び出す
このように、LLMを呼び出すクライアント側のプログラムとツール用プログラムとが同一のシステムに存在して実行できるのであれば、MCPを使う必要はとくにありません。今回の例のようにOpenAI Agents SDKを使っているならば[SDKの関数ツール機能](https://openai.github.io/openai-agents-python/tools/)を使う方が簡潔に記述できると思います。

```python:main.py
from datetime import datetime
from agents import Agent, Runner, function_tool

@function_tool
async def get_time() -> str:
    """現在時刻を取得する関数"""
    return datetime.now().strftime("%Y-%m-%d %H:%M:%S")

def whattime():
    agent = Agent(
        name="Assistant",
        model="gpt-4o-mini",
        tools=[get_time],
    )
    result = Runner.run_sync(agent, "いま何時？")
    print(result.final_output)

if __name__ == "__main__":
    whattime()
```

## 参考文献
- [Model context protocol \(MCP\) \- OpenAI Agents SDK](https://openai.github.io/openai-agents-python/ja/mcp/)
- [For Server Developers \- Model Context Protocol](https://modelcontextprotocol.io/quickstart/server)
書籍「人が壊れるマネジメント」が個人的に刺さりまくった

# 背景

人が壊れるマネジメント　プロジェクトを始める前に知っておきたいアンチパターン 50 を読みました。
その中で、個人的にすごく共感できたトピックを自分の体験談も交えて紹介したいと思います。

https://amzn.asia/d/eIcYDj3

# 本記事を書いている人のスペック
新卒7年目のITエンジニアです。

複数メンバーを抱えたチームのマネジメント経験はありません。
2人ほどの開発チームメンバーの一人です。
開発にかかる工数見積 ～ テスト まで一通りの業務はこなせます。

どこにでもいる一般的なSEといったレベル感です。

# 個人的に刺さったトピック
## 非現実的な工数とスケジュールで壊れる
これまでいくつかのプロジェクトを経験して、炎上した理由の第1位がこれだと思っています。
ありがちなのが、**不正確なタスクの見積もり**です。

特にアサインされたばかりでプロジェクトの事もよく知らない場合、大抵他の人が工数見積したスケジュールに沿って開発していました。
しかし、見積もられた工数はそのプロジェクトをある程度わかっている前提で見積もられていました。

当然、プロジェクト入りたての僕の馬力では間に合わず、残業をする羽目になりました。
また、自分の見積もりが楽観的過ぎて工数が足りなくなってしまうケースもありました。

振り返ってみると、**自分が安請け合いしてしまった**ことが原因でした。

### 対処法
本書では、非現実的な計画によるプロジェクト失敗を避けるため「**積み上げ式で工数を見積もって計画を立て、要件変更や追加要件が入った際は必ず再計画を実施する**」と書かれています。

当たり前のようで、これができていないプロジェクトは本当に多いです。
ただ、実際の現場では顧客からのプレッシャーや納期等様々な要因で再計画の実施が難しい場合もあります。

その場合、プロジェクトが走り出す前に顧客と計画変更の可能性について理解して貰う必要があります。

#### 現実的な工数を提示する
安請け合いせず、**最初から無理な計画を組まない**事が重要です。

#### プロジェクト初期の工数見積は、あくまで概算であることを伝える
要件定義や機能設計が終わったタイミングで、**再度詳細の見積もりを行い計画を見直すことを理解してもらうようにしましょう。**
また、当初の要件・要求に変更が入った場合や、優先度の高い対応が割り込んで来た場合は、**再計画を実施することに合意をもらうようにしましょう。**

## 経営陣の無理解で壊れる
僕の経験では、**現場の状況を理解していない経営陣の無茶な要求でプロジェクトの計画が破綻するケース**がありました。

上からのプレッシャーで現実的ではない目標に対応せざるを得ず、無茶な働き方をするケースです。

経営陣とは少し違いますが、**プロジェクトに詳しくない技術者がオブザーバーとして入る**ケースもあります。
共通しているのは、**現場の状況を理解しておらず、無茶な指摘や要求をする**ことです。

このように、現場の声が届いていないと**組織の信頼度やチームの指揮も下がります。**

### なぜ経営陣は無茶な要求をしてくるのか
経営陣が現場に理不尽な要求を突きつけるのは、**「要求に応じたリソース（予算や工数、スケジュール）が必要である」という現実を理解できていない**ことが大半である と本書では書かれています。

プロジェクトの方針や要求変更は、**注文した料理を作っている間に注文を変更するようなもの**と例えられていました。
つまり、**今まで作り上げてきたものを一からやり直す**くらいインパクトの大きいものになります。

経営陣から見ると、「些細な方針変更」でもプロジェクトの影響範囲は大きいものになってしまいます。

方針変更に伴いリソースが見直しされるならまだ良いですが、リソースの見直しが行われずに計画が続行されると開発者に過剰な負担がかかってしまいます。

### 対処法
### 定期的な報告と対話を行う
進捗状況や課題点を経営陣に共有し、現状を理解してもらう。
対話を通して、プロジェクトの現状に対し共通認識を持ってもらうようにしましょう。

###  リソースの確保を優先する
プロジェクトの方針や前提条件が変わった場合、必ず再計画を行います。
また、**再計画が行われない場合のリスクについてもきちんと伝えることも重要です。**

## プロジェクトの不確実性で壊れる
プロジェクトに不確実性はつきものです。
プロジェクト開始時点では想定が難しい要素や、いざ作業に入らないとわからないこともたくさんあります。

そういった不確定要素のためにプロジェクト初期の工数見積もりでバッファを積みますが、
バッファだけでは賄えないケースもたくさんあります。

特に新しい技術を扱った案件や、プロジェクトで扱うプログラミング言語に詳しいメンバーがいない場合、
プロジェクト初期の段階で出した工数通りに計画を進めることは困難です。

### 対処法
こうしたリスクが顕在化した場合、**一度立ち止まってプロジェクトの方針や計画を見直すことが重要です。**

#### リスクの洗い出しと優先順位付けを行う
プロジェクト初期の段階で想定できるリスクを洗い出し、影響の大きさや発生する可能性を考慮して対策を検討します。
また、プロジェクト関係者へ**プロジェクトは本質的に不確実性を扱う取り組みである**ことを理解してもらうことも重要です。

高いお金をかけたプロジェクトでも、1つの不確定要素でプロジェクト全体が失敗してしまう可能性があるのです。

#### 柔軟な計画を立てる
不確実性が高いプロジェクトの場合、詳細すぎる計画よりも柔軟な計画を立てるほうが重要です。
例えば、プロトタイプを作って実際の開発感覚を検証したり、状況に応じて計画を見直すアプローチをすることが大切です。

**プロジェクトに変更はつきものである**と関係者へ意識してもらうことが大切です。


# 感想
新しくアサインされたプロジェクトで早速障害が見つかり、かなり忙しくしている時にこの本と出会いました。
プロジェクト失敗の要因となり得る要素が広く網羅されており、とても読みやすく共感を持てるものも多くありました。

特に、**アンチパターンが与えるメンバーの心理的負担**について書かれたものが多く、一 SEとしてとても共感できました。
（特に 長時間労働で壊れる のトピックとか・・・笑）

まだ一部（プロジェクト計画編）しか読めていないですが、
タスク編、コミュニケーション編、キャリア編等 面白そうなトピックがあるので楽しみです。

マネジメント業務をしている方でなくても勉強になるおすすめの一冊です。

ここまで読んでいただきありがとうございました。
本書「世界一流のエンジニアの思考法」の実務で活用できることの要約

本書『世界一流のエンジニアの思考法』（著：松尾豊氏など）は、単なる技術的なノウハウではなく、「思考の土台」や「問題解決の姿勢」について述べた本で、エンジニアに限らず、思考力を高めたい人すべてにとって価値のある内容です。
実務で活用できるノウハウを整理しましたので、良ければ目を通していただいてご活用ください。

# キーメッセージ
**「手を動かしながら、思考を深める」ことが世界一流のエンジニアになるカギである。**

# 世界一流のエンジニアは「考え方」で決まる
- 知識やスキルではなく、「考える力」こそが差を生む。
  - 知識は検索できるが、思考は代替不可能。
  - 失敗や手探りの中から「なぜこうなるのか」を突き詰める力。
- 一流は「抽象化」と「構造化」が得意
  - 問題を一段上の視点から眺める能力（＝メタ認知）が鍵。

「抽象化」の例：
バグが出た → 単なる修正ではなく、「同様のバグが今後出ない構造か？」を考える。
一流の思考は、「目の前の現象の背後にあるパターンを読む力」。

# 世界一流のエンジニアは「手を動かす」ことで考える
- 思考と実装はセットで回すもの
  - 実際に試してみる中でしか「本当の理解」にはたどり着けない。
  - 最小構成（MVP）でまず動かす
- 最初から完璧を目指さず、動くものを早く作る。
  - 試行回数＝成功への道。

頭で考えているだけでは「実用的な知恵」にならない。
コードを書いたり図を描いたり、アウトプットを伴うことで初めて「思考」が深まる。

# 「問いを立てる力」が最重要スキル
- 「良い問い」は良い答えを生む
  - 問題の立て方を間違えると、いくら頑張っても解決しない。
  - 「これは本当に解くべき課題か？」を疑え。
- 問いを磨くことで、思考の質が上がる
  - Why型の問い→本質へ
  - What型の問い→構造化へ
  - How型の問い→具体化へ

Googleのエンジニアも「問いを磨くこと」に8割の時間を使う。
成果が出ない人は「問いの浅さ」に気づかない。

# 学び続ける人が一流になる
- 自己研鑽が止まった瞬間に成長は終わる
  - エンジニアに限らず、現代は「変化対応」が最も価値が高いスキル。
- 学びは点ではなく「線と面」で捉える
  - 単発の知識ではなく、それが他とどうつながるかを考えながら吸収せよ。

「1日1つの知識」より、「その知識がどう既存の知識体系に作用するか」を意識した方が深まる。
成長の速度より、**学びの構造化（知識の地図化）** がカギ。

# まとめ
- エンジニアの価値＝「考える力」
- とにかく手を動かせ。それが最高の学びと成長をくれる
- 問題を解く前に、問いを疑え
- 知識を点で終わらせるな。線にし、面にせよ
【Docker】Corepackのダウンロードプロンプトが表示されないようにする方法

## Corepackのダウンロードプロンプト

`yarn install`などを実行した際に以下のようなプロンプトが表示される。

```shell
$ docker compose run -it --rm frontend yarn install
! Corepack is about to download https://repo.yarnpkg.com/4.4.0/packages/yarnpkg-cli/bin/yarn.js
? Do you want to continue? [Y/n]
```

## 非表示にする方法

`Dockerfile` に `ENV COREPACK_ENABLE_DOWNLOAD_PROMPT=0` を追記すると表示されなくなる。

```dockerfile
ENV COREPACK_ENABLE_DOWNLOAD_PROMPT=0
```

```shell
$ docker compose run -it --rm frontend yarn install                 
➤ YN0065: Yarn will periodically gather anonymous telemetry: https://yarnpkg.com/advanced/telemetry
➤ YN0065: Run yarn config set --home enableTelemetry 0 to disable

➤ YN0000: · Yarn 4.4.0
➤ YN0000: ┌ Resolution step
➤ YN0000: └ Completed
```

## 参考

https://github.com/nodejs/corepack/blob/main/README.md#environment-variables
Chromeの拡張機能をChromeウェブストアで公開する方法

作成したChromeの拡張機能をChromeウェブストアで公開する方法です。

## デベロッパー登録

Chromeウェブストアで公開するにはまずChromeウェブストアの[デベロッパー登録](https://chrome.google.com/webstore/devconsole/register?hl=ja)が必要です。
デベロッパー登録するには5ドルの登録料が必要になります。

## 拡張機能の審査

拡張機能をストアで公開する前に審査があります。
審査に進むには、デベロッパーダッシュボードから画面右上の「新しいアイテム」をクリックします。
すると、下記のようなウィンドウが現れるので、作成した拡張機能をzipファイルに圧縮してドラッグ&ドロップします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2382613/925c0f62-7911-4f5a-9c63-1fa94d1ca184.png)

### ストア掲載情報の入力

拡張機能のアップロード後、「ストアの掲載情報」で必要事項の入力、アイコンやスクリーンショットなどを添付していきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2382613/ad7751b2-107f-4249-924f-dd1afd26d86e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2382613/cbae497e-2c64-4e50-92d9-e51c5a63471c.png)

## プライバシーへの取り組みの入力

ここでは、拡張機能の用途やリモートコードを使用するか(使用する場合はその理由も)、ユーザーから収集するデータについて入力していきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2382613/9bbad332-5fc5-40df-8567-abc22a222193.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2382613/b6a45fae-379b-4969-952e-e1dbdc51d58c.png)

### 審査

全ての必須項目の入力が終わったら画面右上の「審査のため送信」をクリックします。

すると下記のようなポップアップが表示されるので、審査合格後に自動的にストアに公開する場合はチェックボックスにチェックをして「審査のため送信」をクリックします。

審査に合格すればストアに公開され、拡張機能をChromeに追加できるようになります！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2382613/ad6de9f6-a350-430a-bed8-4c106048b5f0.png)

もし入力項目の不足や誤りがある場合は「送信できない理由」のリンクをクリックすると修正点が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2382613/004b9abf-b009-448d-813b-e10c18a34d14.png)
#0101（2025/04/11）Kafkaを用いた構成

# Kafkaを用いた高信頼・高スループットなイベント駆動アーキテクチャの実践

Apache Kafkaは、分散型ログ収集・ストリーム処理基盤として広く採用されている高性能メッセージングシステムである。本稿では、Kafkaを用いた非同期アーキテクチャの構築手法、ならびにその利点と代替技術との比較を、PythonおよびNode.jsによる実装例とともに概説する。

---

## ✅ Kafkaのアーキテクチャ構成要素

- **Producer**
  - Kafkaクラスタにイベント（メッセージ）を送信する役割を担うエンドポイント。
  - 例：Webアプリケーションからのログデータ送信。

- **Consumer**
  - Kafkaの特定トピックからイベントを購読し、後続処理に供する。
  - 例：ログ情報をデータベースや分析基盤に格納。

- **Broker**
  - 実際のメッセージを保持・管理するKafkaノード。

- **Topic**
  - メッセージのカテゴリやチャネルを意味する単位。トピック内のメッセージは厳密な順序を保持する。

- **Offset**
  - 各メッセージに対する一意な位置情報。Consumerがどこまで読み進めたかを管理する。

---

## 📚 ユースケース

### 1. セキュアで拡張性の高いログ基盤
Webアプリケーションの操作ログやセキュリティイベントをKafkaに送信し、ConsumerがそれをElasticsearchやS3、BigQuery等の外部ストレージに非同期で保存。スケーラブルかつ高可用なログ収集処理を実現できる。

### 2. イベント駆動による通知分離
ユーザーの操作に応じた通知処理（例：メール、プッシュ通知）をイベント化し、Kafkaで疎結合に扱うことで、通知ロジックをアプリケーション本体から分離・独立させることができる。

### 3. ストリームデータのリアルタイム分析
IoTセンサーデータや金融取引ログなどをリアルタイムでKafkaに集約し、Consumer側で逐次処理・モニタリングを実施。Kafka StreamsやApache Flinkとの統合によって、より複雑なCEP（Complex Event Processing）も可能。

---

## ✨ Kafkaを用いるメリット

- **高スループット**：ディスクベースの連続書き込みおよびバッチ送信により、1秒あたり数百万件のメッセージ処理が可能。
- **耐障害性**：複数Broker間のレプリケーションにより、ノード障害時もデータを損なうことなくリカバリ可能。
- **オフセット管理**：Consumer側で処理位置（offset）を制御できるため、再処理や追跡性が保証される。
- **スケーラビリティ**：Partitionをキーに分散配置し、Consumer Groupによって負荷分散が容易。
- **柔軟な統合性**：Kafka ConnectやREST Proxyを通じて外部システムとの双方向連携が可能。

---

## ⚠️ Kafkaの非採用時における代替技術

| 技術 | 特徴 |
|------|------|
| RabbitMQ | メッセージングにおける高度なルーティングとキュー制御機構を有する。 |
| Redis Pub/Sub | 超高速・軽量なPub/Subモデル。永続性は保証されない。 |
| WebSocket | クライアント-サーバー間の双方向通信に最適。ただし信頼性や耐障害性の実装は別途必要。 |
| AWS SQS + Lambda | サーバーレスアーキテクチャと組み合わせたキュー処理に適する。 |

---

## 🔧 Kafkaを活用したシステム実装例

### Node.js によるProducer実装
```javascript
const { Kafka } = require('kafkajs');
const kafka = new Kafka({ clientId: 'webapp', brokers: ['localhost:9092'] });
const producer = kafka.producer();

async function sendLog(logData) {
  await producer.connect();
  await producer.send({
    topic: 'logs',
    messages: [{ value: JSON.stringify(logData) }]
  });
  await producer.disconnect();
}

sendLog({ user: 'keita', action: 'login' });
```

### Python によるConsumer実装
```python
from kafka import KafkaConsumer
import json

consumer = KafkaConsumer(
    'logs',
    bootstrap_servers='localhost:9092',
    group_id='logger-group',
    value_deserializer=lambda m: json.loads(m.decode('utf-8'))
)

for message in consumer:
    log = message.value
    print(f"[LOG] User: {log['user']}, Action: {log['action']}")
```

---

## 結語
Kafkaはイベント駆動アーキテクチャにおける要となる技術であり、特に高スループット処理やリアルタイム性が求められる分野（金融、IoT、ログ収集など）で真価を発揮する。
Salesforceでカスタムオブジェクトのレコードを効率よく削除する方法～カスタムオブジェクトの切り捨て～

本橋孝昭です

今回はSalesforceでカスタムオブジェクトのレコードを効率よく削除する方法として「カスタムオブジェクトの切り捨て」について説明します。

この設定を行えばカスタムオブジェクトのレコードを効率よく削除することが可能です

なお、標準オブジェクト含め開発者コンソールでレコード一括削除の方法はこちらです

https://qiita.com/Takaa/items/d50c71f9af709f7a2fe4


## 設定
Lightningで「ユーザーインターフェース」から「カスタムオブジェクトの切り捨てを有効化」をクリックします


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/dd067347-bbdf-4d09-8d05-9f9cae2ef3af.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/9690858f-a13c-4668-a920-8f067ba56a7b.png)


こちらで設定は完了です


次にClassic環境に変更してデータを一括削除したいカスタムオブジェクトを選択します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/f75a83f6-ff00-4c9d-b2ca-441da5db0acb.png)

「切り捨て」ボタンをクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/b49fa32b-a190-452f-8e52-de587f6121d0.png)

「切り捨て」にオブジェクト名を入力します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/913512e7-0245-49ae-ae20-7452f6e329ff.png)

以上で完了です

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/f83c1dca-2307-4aa4-b00a-7356b57cba64.png)


「削除済みオブジェクト」が表示されていることを確認します


「切り捨て」の詳細はこちらのヘルプをご確認ください。

https://help.salesforce.com/articleView?id=dev_object_trunc_overview.htm&type=5#TruncatingObjectsOverview


>カスタムオブジェクトを切り捨てると、そのレコードのすべてが完全に削除されます。これらのレコードをごみ箱から復元することはできません。15 日間は、切り捨てられたオブジェクトのコピーが [削除済みオブジェクト] リストに表示されます。この間、オブジェクトとそのレコードは引き続き組織の制限に含まれます。15 日を過ぎると、コピーされたオブジェクトとそのレコードは完全に削除されます。
一方、カスタムオブジェクトを削除すると、そのオブジェクトは [削除済みオブジェクト] リストに 15 日間保持されます。その後、オブジェクトとそのレコードは完全に削除されます。
【AWS】CDKで「mysql: command not found」エラー発生...`latest_amazon_linux`が原因だった

# 概要
AWS CDKを利用して、EC2インスタンスに`latest_amazon_linux`を指定してmysqlをインストールしました。すると以下のエラーに。

> sh-4.2$ mysql --version sh: mysql: command not found

こちらの原因と解決方法を紹介します。

# 前提と原因

CDKで指定した内容は以下でした。

```py
        user_data = ec2.UserData.for_linux()
        user_data.add_commands(
            "sudo yum update -y",
            "sudo yum install -y mysql"
        )

        ec2_instance = ec2.Instance(
            self, "sample-EC2Instance",
            instance_type=ec2.InstanceType("t3.micro"),
            machine_image=ec2.MachineImage.latest_amazon_linux(),
            vpc=private_subnets_vpc,
            security_group=ec2_security_group,
            role=ec2_role,
            key_name="sample_ssh",
        vpc_subnets=ec2.SubnetSelection(subnet_type=ec2.SubnetType.PRIVATE_WITH_EGRESS),
            user_data=user_data
        )
```

上述のエラーメッセージから、EC2インスタンス内でMySQLクライアントがインストールされていないように思われます。`UserData`があるので、EC2インスタンス作成時にMySQLクライアントをインストールされているはずなのだが...。

管理コンソールを確認してみると、EC2は正常に起動しています。
AMIを確認する

> AMIはamzn-ami-hvm-2018.03.0.20231218.0-x86_64-gp2

とありました。

あれ、Amazon Linuxの最新ではない...？
`latest_amazon_linux()`を選ぶと、Amazon Linux2の最新が得られると思っていたのだが...

Amazon Linux 1は2023 年 12 月 31 日にサポート終了しています。

https://docs.aws.amazon.com/ja_jp/batch/latest/userguide/al1-ami-deprecation.html

これが原因で最新のMySQLパッケージが利用できないなどの状況になっていたと考えられます。


## 解決方法

以下のドキュメントを見ると、確かにMachineImageごとに指定するメソッドが違いました。

https://docs.aws.amazon.com/cdk/api/v2/python/aws_cdk.aws_ec2/MachineImage.html

AmazonLinux2の最新版にした場合は

```
latest_amazon_linux2()
```

を選ぶ必要があるとのこと。

ということで、CDKファイルの

```py
machine_image=ec2.MachineImage.latest_amazon_linux()
```

を

```py
machine_image=ec2.MachineImage.latest_amazon_linux2()
```

としたらエラーが消えました。
以上！
【Shopify】TrustShop‑ Product Reviewsアプリにテストデータをインポートする

# はじめに

インポートの画面やドキュメントで書いてあることが異なったりするのでインポートできるCSVを共有します。

## リンク

- アプリ
    - https://apps.shopify.com/trustshop?locale=ja
- 公式ドキュメント
    - https://trustshopio.notion.site/TrustShop-Help-Docs-a61d15b7148d40d993fb4ce90326c9a1
- サンプルCSVリポジトリ
    - [GitHub - trustshop-product-reviews-sample-csv](https://github.com/cats-park/trustshop-product-reviews-sample-csv)

## CSVファイルの構造

TrustShopにレビューをインポートする際のCSVファイルには、必須フィールドとオプショナルフィールドがあります。

### 必須フィールド

以下のフィールドは必ず入力が必要です：

- `title`: レビューのタイトル
- `body`: レビュー本文
- `rating`: 1から5の数値で評価を入力
- `reviewer_name`: レビュアーの名前
- `product_handle`: 商品のhandle

### オプショナルフィールド

以下のフィールドは空欄でも問題ありません：

- `review_date`: レビュー日時
- `reviewer_email`: レビュアーのメールアドレス
- `state`: レビューの状態
- `author`: レビュアー名（**重要**: 空欄の場合、レビューは匿名として表示されます）
- `email`: メールアドレス
- `reply`: 返信内容
- `replied_at`: 返信日時
- `location`: 場所情報
- `created_at`: 作成日時（YYYY/MM/DD形式で入力。例：2025/1/1）

## 注意点

1. **匿名レビューについて**
   - `author`フィールドを空欄にすると、レビューは匿名として表示されます
   - レビュアーの情報を保護したい場合は、このフィールドを空欄にしてください

2. **日付形式について**
   - `created_at`は「YYYY/MM/DD」形式で入力してください
   - 例：2025/1/1

3. **商品handleについて**
   - `product_handle`には対象商品のhandleを入力してください
   - Shopifyの商品URLの最後の部分がhandleとなります
   - 例：`https://your-store.myshopify.com/products/example-product`の場合、`example-product`がhandleです

## まとめ

TrustShopへのレビューインポートは、正しいCSV形式を使用することで簡単に行えます。このブログで紹介したフォーマットに従えば、確実にインポートを成功させることができます。

特に注意が必要なのは以下の点です：
- 必須フィールドは必ず入力すること
- `author`フィールドの扱い（匿名設定）
- `product_handle`は対象商品の正しいhandleを使用すること

より詳細な情報や実際のサンプルについては、GitHubリポジトリを参照してください。
M5Stamp FlyをM5StampS3で制御する

# M5Stamp FlyをM5StampS3で制御する
M5StampS3をシリアルでPCにつなげば、PCからM5Stamp Flyをコントロールできるようにしてみました。
方法は、M5Atom-joysticの信号をM5StampS3からシミュレーションして送ることでPCからM5StampFlyを飛ばそうとしたものです。
まだまだ課題は多いですが・・・

https://www.youtube.com/shorts/LR_KySrYpsk?feature=share

こんな感じで飛びます。

# ソース
ソースファイルとコントロール用のPythonで書いたサンプルプログラムは、GitHubで公開しております。

https://github.com/kawamo55/M5Drone

よかったらいじり倒してみてください。
Paperpile for Word で自作の引用スタイルを利用する方法

# 絶妙に違う引用スタイル
Paperpileは<a href="https://citationstyles.org/">csl</a>が出しているコードに従っている。コードはxml形式で、サイトで見ることが出来る。

XMLのコードの内容は<a href="https://docs.citationstyles.org/en/stable/specification.html">ここ</a>
例えばpaperpile側で、pageが110-112と保存されていても、csl側でpage-firstにすると110のみwordに出力される。

# Paperpileへの適用
自分好みのスタイルになるcslファイルを作製した後は、paperpileにインストールする。
Paperpileのwebページの
1. 右上のアイコンクリック
1. settings
1. Citation Styles
でアップロード画面が表示される。
![a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2165244/c65f7569-868d-4c7d-8235-41c7b5a34046.png)
基本情報技術者試験(FE)に合格した勉強方法

## はじめに

以前、基本情報に合格した時の勉強方法を記しておきます。
前提として、私はプログラマの端くれだったので、科目B(旧:午後問題)は過去問を数回解いただけで、あまり勉強していません。

※本記事では勉強時間は記載していません。勉強時間なんて人それぞれで全く参考になりません。

## 私の実践した勉強方法

※はっきり言います、この方法は完璧ではありません！ 理由は受験結果の項目に記載しています。

### 1. 参考書を購入
参考書は買わなくても合格できると思いますが、あえてお金をかけることでやる気が出るのでお勧めです。私が購入した本は、"試験に出るとこだけ!"みたいな本です。（過去問はついていなかったと思います。）

### 2. テキストを1周
気になった単語は常にメモします。
私の場合はノートに手書きしました。

### 3. 過去問道場をひたすら進める
便利なことに、数年分の過去問に無料で挑戦できるサイトがあります。
ご存知、"基本情報技術者過去問道場"です。
https://www.fe-siken.com/

科目A(旧:午前問題)の過去問をひたすら解きます。お風呂の中でも解きます。
出題はランダムに設定しました。
これをおおよそ正解率75%以上を目指してやりまくります。
わからなかった問題はテキストに戻って適宜復習しました。

また、過去問道場には"以前不正解だった"問題のみを出題する機能があります。
最終的にはすべて正解できるようになったと思います。

## 受験の申し込み

基本情報はCBT方式の受験に対応しています。（全国各地にあるセンターで受験できます）
ですので、受験日から逆算して勉強計画を立てる必要はありません。

過去問を解いて、安定して正答率が7割5分を超えることができるようになった時点で試験を申し込みました。


## 受験当日

再度過去問を解き、余った時間でテキストに目を通しておきました。
いざ試験会場につくと、受付や注意事項の説明等（おおよそ30分程度）の後、試験開始です。

#### 試験時間
```
 科目A: 90分
 途中休憩: 10分
 科目B: 100分
```

科目Aは解き終わった段階で終了して、途中休憩を早めることができます。
途中休憩は最大10分ですので、お手洗いを済ませてからすぐに受験することもできます。
科目Bについても同様で100分経過前に終了することができ、その分早く帰宅することができます。


## 受験結果（＆ふりかえり）

科目Bの終了時に結果が表示されます。
結果は科目Aが6割5分程度（結構ギリギリ）、科目Bが9割程度でした。

科目Aが合格ラインギリギリになった要因ですが、
私が購入した"出るとこだけ"の本からはほとんど出題されませんでした...（仕方がありません）
また、過去道場で解いた問題は出題中のせいぜい5割程度に思いました。
受験中は正直焦りました。

IPAが公開しているシラバスから、満遍なく出題されている印象です。
https://www.ipa.go.jp/shiken/syllabus/gaiyou.html

最新のテクノロジーについての出題が予想以上に多く（知らない単語もでてきました）、
頑張って勉強した計算問題が逆に少なめでした。

どうもCBT試験対応の際に、出題の傾向が大きく変わったようです。
（過去問道場はCBT対応前の問題がほとんどです）

科目Bは過去問と同じような雰囲気だったので、特に問題ありませんでした。


## 結論

IPAのシラバスをすべて網羅しましょう。

教材は"IPAのシラバス"＋"最新の参考書（情報量が多いもの）"＋"過去問道場"が私のオススメです。
SSHで、rootユーザーのログインを禁止する方法

テーマは、表題の通りrootユーザーのアクセスを禁止する方法です。

そもそも、なぜrootユーザーで、アクセスをできるのがいけないのかですが、これは、とてもシンプルな理由で、rootユーザーは、

とても強大な権限を有しているため、ログインが可能であると、サーバーにあらゆる操作ができてしまい、乗っ取られてしまうからです。



では、そのようにできないようにするために、どのようにすればいいのかですが、それは、以下の手順を踏んでください。

１、rootユーザー以外のユーザーを新規作成

この手順は、この記事で触れていますので、こちらを参照ください。

https://yamachan228.seesaa.net/article/512015818.html

２、1で作成したユーザーで、念のために、SSH接続できることを確認

これは、以下のコマンドで可能です。実行後にパスワードを求められるので、入力してください。

ssh 新規作成のユーザー名@ipアドレス

3、cpコマンドを使って以下のパスのファイルのバックアップを取る。(これも、念のためです。今回の件に限らず設定ファイルはバックアップを取った方がいいです。)

cp /etc/ssh/sshd_config /etc/ssh/sshd_config_org

4、sshd_configファイルをvim(エディターなら何でもよい)で、PermitRootLoginがnoになっているのをyesに変更する。

5、diffコマンドを使って、3のcpコマンドで作成した、コピーと比較する。

以下のコマンドで、できます。

diff sshd_config sshd_config_org

6、sshプロセスを再起動する

以下のコマンドで、できます。

systemctl restart sshd

7、rootユーザーで、SSH接続できないことを確認する。

Permision denied, Please try againと表示されれば、OKです。

これらの手順がrootユーザーログイン禁止の方法になります。

今日は、ここまで。
「情報セキュリティって何？」から始める、初心者向け入門

## はじめに

現代社会において、情報は企業や組織にとって最も重要な資産の一つです。その情報を守るために欠かせないのが **「情報セキュリティ」** です。本記事では、情報セキュリティの基本的な考え方から、具体的なセキュリティ対策までを体系的に整理して紹介します。セキュリティ初心者から経験者まで、改めて基礎を見直すきっかけになれば幸いです。


## :shield:情報セキュリティとは？
セキュリティとは、大切なものが危害や損傷を受けない、正常な状態を維持することを指します。つまり、**安全な状態を保ち続けること**がセキュリティの本質です。

情報セキュリティは、情報の **「機密性」「完全性」「可用性」** を確保・維持することが基本です。加えて、 **「真正性」「責任追跡性」「否認防止」「信頼性」** などの特性も重要視されています。

これらの考え方は、情報セキュリティマネジメントシステム（ISMS）の根幹をなすものであり、企業や組織が情報という資産を守るためのフレームワークです。


## :large_orange_diamond: 情報セキュリティの分類

情報セキュリティは、大きく次の2つに分けることができます。

### 1. 物理的セキュリティ
建物や設備を守るための対策。

- 耐震・防火・電源・回線設備
- 入退室管理（ICカード、生体認証など）
- バックアップセンターの整備、UPSの設置
- 電源・通信ケーブルの保護

### 2. 論理的セキュリティ
情報システムや人、運用ルールに対する対策。

- **システム的セキュリティ**：アクセス制御、暗号化、マルウェア対策など  
- **管理的セキュリティ**：ポリシーの策定・運用、監査、ライセンス管理など  
- **人的セキュリティ**：教育・訓練、誤操作や不正対策など  


## :large_orange_diamond:  情報セキュリティの7大要素

情報セキュリティの基本的な特性は以下の7つがあります。

1. **機密性（Confidentiality）**  
   情報を許可された人だけが扱える状態に保つこと。  
   → アクセス制御（認証、認可）、暗号化

2. **完全性（Integrity）**  
   情報が正しく、改ざんや誤りのない状態を維持すること。  
   → ハッシュ値による検証、デジタル署名

3. **可用性（Availability）**  
   必要なときに情報やサービスが使える状態にあること。  
   → 冗長化、バックアップ、定期保守

4. **真正性（Authenticity）**  
   アクセスしている人や組織が正当なものであること。  
   → 多要素認証、デジタル証明書

5. **責任追跡性（Accountability）**  
   誰が何をしたかを追跡できる状態にあること。  
   → ログ管理、操作履歴の記録

6. **否認防止（Non-Repudiation）**  
   「やっていない」と後から言い逃れできないようにすること。  
   → デジタル署名、タイムスタンプ

7. **信頼性（Reliability）**  
   システムが期待通りに動作し、誤動作しないこと。  
   → フォールトトレラント設計、ヒューマンエラー対策


## :large_orange_diamond:  セキュリティ対策の4つの機能

情報セキュリティの対策は、目的ごとに以下の4つに分類できます。

### 1. 抑制
問題の発生を未然に防ぐために、人の意識へ働きかける。

- セキュリティポリシーの策定と教育
- 社内ネットワークの監視（実施告知だけでも効果が期待できる）

### 2. 予防
脆弱性に対して事前に対策を施す。

- ソフトウェアの更新・パッチ適用
- 強力な認証・アクセス制御
- 暗号化やバックアップの整備

### 3. 検知
インシデントを早期に発見・追跡し、影響を最小限に抑える。

- ログ管理、常時監視、IDS/IPS
- 監視カメラの設置

### 4. 回復
障害や攻撃が発生した後、速やかに復旧する。

- バックアップと復旧手順の整備
- 体制・フローの構築と訓練


## :large_orange_diamond:  セキュリティ対策の基本的な考え方
セキュリティ対策の基本的な考え方は、単に対策を講じるだけでなく、「**守るべきものは何か**」「**どんなリスクがあるのか**」「**どうやってそれに対応するか**」という一連の流れを踏まえて計画・実施していくことが重要です。


### 1. **守るべき資産を明確にする**
　すべての情報やシステムを同じように保護するのではなく、重要度（顧客情報、機密ファイルなど）優先順位（業務影響、法的責任）に応じて守るべきものを特定します。

### 2. **脅威と脆弱性を理解する**
　外部からの攻撃（サイバー攻撃、マルウェア）だけでなく、内部不正、ヒューマンエラー、自然災害などの「脅威」もリスクの対象になります。
　システムの設定ミスや運用上のミスといった「脆弱性」を見逃さないことも大切です。

### 3. **リスクアセスメントの実施**
　情報資産にどんなリスク（脅威と脆弱性の組み合わせ）があるのかを分析・評価します。
  　例：顧客情報を扱っている → 漏洩リスクあり → 適切なアクセス制御が必要

### 4. **セキュリティポリシー・基準の明確化**
　組織全体で「どう守るか」というルールや方針を明確にします。
　セキュリティの意識を統一し、従業員教育や手順書の整備を通じて過失や不正を防ぎます。


### 5. **利便性とのバランスをとる**
　セキュリティを強化すると利便性が低下する場合もあるため、業務効率とのバランスを考慮します。


### 6. **インシデント発生を前提に備える**
　100%防ぐことは不可能という前提で、インシデント発生時の対応体制や手順を事前に整備します。（BCP対策など）

### 7. **定期的なレビュー・見直し**
　現在のセキュリティ対策が本当に有効かどうか、年1回以上は第三者によるレビューを行い、状況や技術の変化に応じて見直しを図ります。


## :large_orange_diamond:  セキュリティ設計の原則
セキュリティ設計の原則とは、情報資産を安全に守るための基本的な考え方です。

- **最小権限の原則**：必要最小限のアクセス権だけを与える  
- **責務分離の原則**：1人が複数の権限を持ちすぎないように業務を分担し、ミスや不正行為を防ぐ
- **フェールセーフ設計**：障害が起きても安全な方向に動くよう設計する  
- **単純化**：システムは可能な限り単純に設計して、ミスや不正利用のリスクを減らす  
- **多層防御**：複数の対策を組み合わせて防御を強化する  
- **分散化**：重要機能を1箇所に集中させず、バックアップや認証を分けて管理する  
- **一意性と追跡性**：誰が何をしたかをログ等で明確にし、証跡を残す


## おわりに

情報セキュリティは、単に技術やツールだけで成り立つものではありません。組織の文化や人の意識、運用ルールなど多くの要素が絡み合っています。だからこそ、基礎をきちんと理解し、実行可能な対策を一歩ずつ積み上げていくことが何より重要です。
集中分析アプリ「FocusSensei」の企画背景と技術構成【プロダクト開発メモ】


個人開発プロジェクト「FocusSensei」は、集中力の可視化と学習習慣の定着を目的とした**自己学習支援アプリ**です。  
本記事では、なぜこのアプリを作ろうと思ったのか、誰のためのプロダクトなのか、そしてどのような技術で構成しているのかをまとめます。


## 🎯 なぜ作るのか？

- 「ただ時間を測るだけ」でなく、「集中状態そのものを振り返る」ことが目的  
- 勉強・作業時間を記録しても、結局「内容や質」が見えない → 可視化したい  
- GPTベースのフィードバックや、集中傾向の分析を通じて、**内省しやすい設計**を目指している


## 👤 想定ユーザーと価値

| ユーザー層 | 提供価値 |
|------------|-----------|
| 自学自習する学生・社会人 | 集中の波や学習ログの分析 |
| 計画倒れしがちな人 | 2週間スプリント型の学習進捗管理 |
| 言語・資格学習ユーザー | GPTによる日/英/韓の自動フィードバック |


## 🛠️ 技術スタック

- **フロントエンド**: React (Next.js + TypeScript + TailwindCSS)
- **バックエンド/API**: Firebase (Auth, Firestore, Functions), GPT API
- **マルチ言語対応**: i18n（ja / en / kr）
- **認証・データ管理**: Firebase Auth, Firestore
- **AI機能**: ChatGPT API によるコメント生成・分類分析
- **セキュリティ**: Firebase Security Rules（利用ログ + ユーザー別分離）


## ✨ MVP機能（第1フェーズ）

- ⏱️ **集中タイマー**（ポモドーロ方式 + UI進捗バー付き）
- ✍️ **GPTによるフィードバック記録**
- 📊 **集中度分析ダッシュボード**
- 🔐 **Firebase認証 + セキュリティ設計**
- 🌐 **3言語対応UI（日本語・英語・韓国語）**
- 📂 **学習ログの自動保存と検索**


## 💡 設計のこだわり

- **最初は「自分のため」**の設計で始めた  
- 情報を詰め込みすぎず、「習慣化」を妨げないUIに  
- GPTの導入は「答え」よりも「振り返り」を促すための補助ツールとして位置づけ


## 🔗 関連リンク

- 📝 Zennでの詳細記事（開発背景 & UI構成）  
  https://zenn.dev/hyeon_marina247/articles/448429e8176bb7

- 💻 GitHub（コードは近日整理予定）  
  https://github.com/hyeon-marina/focus-sensei


## 🏁 最後に

このアプリは「習慣化 × 内省 × 可視化」を大事にしながら、  
エンジニアとしての学びとアウトプットを積み重ねていくプロジェクトです。

今後も開発の進捗や学びをQiita/Zennを通じて記録していきます 🚀



## 🏷️ タグ

`#React` `#Firebase` `#ChatGPT` `#個人開発` `#集中アプリ` `#習慣化` `#プロダクト設計`
AWSの取っつきにくさのメモ（要約：カタカナ語が多い！）

※駄文です
AWS認定資格のクラウドプラクティショナーってやつを取ろうかな～と思って
AWSOMEDAYというオンラインセミナーを視聴した　会社の半休を取った
（2025-04-10の回）
https://aws.amazon.com/jp/events/awsome-day/awsome-day-online/

以下、取っつきにくい点
- 略語が多い
- カタカナ語が多い
- オンプレミス（自前で用意した物理サーバーに構築するやつ）の場合と同じ操作の内容で用語が違っていたりする
- 基本情報の知識と業務でちょっとAWSマネジメントコンソールを触った（≠操作した）ことがあった状態でギリついていけるレベル
- カタカナ語多くてメモしにくい

対策
- 高校英語レベルの語彙はあった方がいい
- 基本情報取れるなら取るか勉強している状態で学んだほうがやりやすい
- 略語めっちゃ多くて意味覚えきれないので、その都度脳内変換するしかない

AWSOMEDAY、視聴する前はわからなかったけどZOOMでWEBカメラ映すの必須とかは全くなくて、
必死で部屋を片付けた時間が虚無になった。
Youtubeのライブ配信みたいな感じ
最後の方ポテチ食べながら見てた（帰宅後に自宅で見てたので）

入門とか言ってるけどガチの何も知らん素人状態で見ると全くついていけない部類のやつだから、入門という言葉を信じないほうがいいかも
【競技プログラミング:リハビリ】ワーシャルフロイド

# 既存投稿一覧ページへのリンク
[一覧ページ](https://qiita.com/o_chan_t/items/fc759695acfaef8df2cc)

# 関連する問題
https://atcoder.jp/contests/abc369/tasks/abc369_e

# ワーシャルフロイド
```python:sample_code.py
def warshall_floyd(edges):
    # ノードの最大番号を取得
    max_node = max(max(e[0], e[1]) for e in edges)
    n = max_node + 1  # ノード数
    
    # 距離行列の初期化
    INF = float('inf')
    dist = [[INF] * n for _ in range(n)]
    
    # 自分自身への距離は0
    for i in range(n):
        dist[i][i] = 0
    
    # エッジ情報を反映
    for src, dst, val in edges:
        if dist[src][dst] > val:  # 重複エッジがある場合は最小値を採用
            dist[src][dst] = val
    
    # ワーシャルフロイド法のメイン処理
    for k in range(n):
        for i in range(n):
            for j in range(n):
                if dist[i][k] != INF and dist[k][j] != INF:
                    dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])
    
    return dist

# 使用例
if __name__ == "__main__":
    edges = [
        [0, 1, 5],
        [1, 2, 3],
        [0, 2, 9],
        [1, 4, 3],
        [3, 4, 1],
    ]
    result = warshall_floyd(edges)
    
    # 結果表示
    print("最短距離行列:")
    for row in result:
        print(" ".join(f"{x:2}" if x != float('inf') else "∞" for x in row))

```
Ubuntuからシリアルポート接続を試してみた

勉強のためにIX2215を購入しました。

いつもWindowsからTeraTerm経由で接続していますが、今回は気分を変えてUbuntuから接続してみることに。
Linuxはほとんど使ったことがないので備忘がてらメモします。

ルーターからPCまではコンソールケーブルとUSBシリアル変換ケーブルを使います。



LinuxではUSBポートを/dev/tty*のファイルとして認識するみたいです。
今回はこんな感じ。
```
ls /dev/tty*
 /ttyUSB0 ※ほかにもいっぱい出てきた
```



接続方法は色々あるみたいですが調べて出てきたcuを試します。
dialoutというグループに参加させる必要があるみたいです。(要確認)

```
sudo usermod -aG dialout USER
```


ちゃんと入っているか確認。
```
groups USER
 
 USER : USER dialout sudo
```
```
getent group dialout
 
 dialout:x:20:USER
```



実行してみましたがパーミッションエラーが...
```
cu -l ttyUSB0

 cu: open (/dev/ttyUSB0): Permission denied
 cu: ttyUSB0: Lini in use
```
/dev/ttyUSB0の権限を変えるとうまくいくという情報があったので試すと成功しました。
cuの使用についてはまた勉強しておきます。
```
chmod 666 /dev/ttyUSB0
cu -l ttyUSB0

 Connected
```
切断時は~.で行けるみたいです。
~を入力すると[USER]が出てきたので.で切断できました。
```
Router#~[USER].
  
  Disconnected.
```

ひとまずつながって設定はできそうですが、コマンド周りが怪しいのでもう少し勉強してみます。
cuの引数もデフォルトのままつながっちゃったけど大丈夫なんだろうか。
screenとかほかのコマンドもいつか試してみます。
自作debファイルで独自拡張子をfileで認識させる方法

# はじめに

先日リリースした`pdfveil`を使って暗号化したファイル(hoge.veil)をfileコマンド認識させたいと思い、実装したのでその時につまったところなどを書きます。
`pdfveil`を知らない方はぜひ以下の記事を読んでみてください。

https://qiita.com/Saku0512/items/aba503f2178440a121db


# 各ファイルに記述する内容

では早速`file`コマンドを実装していきましょう。

## pdfveil.magic

今回は暗号化されたveilファイルの先頭に`VEIL`という文字列を入れています。
それをプロジェクトのルールに作成した`pdfveil.magic`で認識させ、表示する文言を設定します。

```text:pdfveil.magic
0 string VEIL PDFVeil encrypted file

```
簡単に説明します。
| 文字 | 意味 |
| --- | --- |
| 0 | ファイルの先頭を見ろ |
| string | 文字列を指定 |
| VEIL | もしVEILを見つけたら実行せよ |
| PDFVeil encrypted file | 説明文 |

## debian/rules

debパッケージを作成する時に作るビルドのルール等を記述するrulesファイルにも書いていきます。

```make:rules
#!/usr/bin/make -f

export DEB_BUILD_MAINT_OPTIONS = hardening=+all
export DEB_CFLAGS = -O2 -pipe -fstack-protector-strong -Wformat -Werror=format-security
export DEB_LDFLAGS = -Wl,-z,relro -Wl,-z,now

%:
	dh $@ --with python3 --buildsystem=pybuild

override_dh_install:
	dh_install
	cp ./pdfveil.magic /usr/share/file/magic
	file -C -m /usr/share/file/magic > /usr/share/file/magic.mgc

```
`override_dh_install`の部分が重要です。
先ほど作った`pdfveil.magic`をfileコマンドが参照する`/usr/share/file/magic`にコピーします。
その後コンパイルして実行可能ファイルにします。

これで、一応実装は完了しているはずです。
一度`file`コマンドで確認してみましょう。

```bash
$ file memo.veil 
Warning: using regular magic file `/usr/share/misc/magic'
file: file `/usr/share/misc/magic.mgc' is too small (No such file or directory)
memo.veil: PDFVeil encrypted file
```

一応指定した説明は表示されていますが、警告ｇでてしまっていて見づらくなっています。

この警告の原因はおそらく`rules`で既存の`/usr/share/file`内のファイルでディレクトリと競合してしまっているためだと思います。

そこで、`rules`を修正します。

```make:rules
#!/usr/bin/make -f

export DEB_BUILD_MAINT_OPTIONS = hardening=+all
export DEB_CFLAGS = -O2 -pipe -fstack-protector-strong -Wformat -Werror=format-security
export DEB_LDFLAGS = -Wl,-z,relro -Wl,-z,now

%:
	dh $@ --with python3 --buildsystem=pybuild

override_dh_install:
	dh_install
	mkdir -p debian/pdfveil/usr/share/pdfveil
	cp ./pdfveil.magic debian/pdfveil/usr/share/pdfveil/pdfveil_magic
	file -C -m debian/pdfveil/usr/share/pdfveil/pdfveil_magic > debian/pdfveil/usr/share/pdfveil/pdfveil.mgc
```

`/usr/share/pdfveil`というディレクトリを新しく作りそこにファイルを置くようにしました。
しかし、これでは`file`コマンドを実行した際に参照されません。

## debian/postint

そこで、`postint`を新しく作成して記述します。
このファイルはdebianパッケージをインストールした後に、実行されるスクリプトです。
今回は、`alias`を使って先ほどの`mgcファイル`を`file`で認識させようと思います。

```sh:postint
#!/bin/sh
set -e

# pdfveil の magic ファイルがインストールされていることを確認
if [ -f /usr/share/file/magic.mgc ] && [ -f /usr/share/pdfveil/pdfveil_magic ]; then
    # ユーザーの ~/.bashrc に alias を設定する
    echo "alias file='file -m /usr/share/file/magic.mgc -m /usr/share/pdfveil/pdfveil_magic'" >> /home/$SUDO_USER/.bashrc
fi

# 新しい設定を反映させるためにシェルを再読み込み
if [ -f /home/$SUDO_USER/.bashrc ]; then
    . /home/$SUDO_USER/.bashrc
fi
```

これで`file`コマンドを使った時にaliasで呼び出されるようになります。
```bash
$ chmod +x debian/postint
```

忘れずに実行権限を付与しておきましょう。

これで設定は完了です。
ビルドして、fileコマンドを使ってみましょう!

```bash
$ file memo.veil
memo.veil: PDFVeil encrypted file
```

ちゃんと指定した文字列が出力されました!!!
「それって、p-hackingじゃないの？」と思っても言えなかった話    〜データサイエンス実務における“正しさ”と“求められる結果”の狭間〜

# 「それって、p-hackingじゃないの？」と思っても言えなかった話  
## 〜データサイエンス実務における“正しさ”と“求められる結果”の狭間で〜

---

## はじめに

こんな経験、ありませんか？

- 分析結果が出なかったのに「この施策、効果があったことにできないかな？」と求められる  
- 仮説と異なる結果が出たら「最初の仮説に合うように調整して」と言われる  
- サンプルサイズが不十分でも「とにかく“結果”を出してほしい」と急かされる  

私は、何度もありました。  
そしてそのたびに、「これって、p-hackingじゃないの？」「HARKingでは？」と心の中でつぶやきながら、空気を読んで声に出せずにいた自分がいます。

この記事では、そんな実務の中で感じた葛藤を共有しながら、「データ分析者として、どのように現実と向き合うべきか？」をあらためて考えてみたいと思います。

---

## 「再現性」と「成果主義」のはざまで

### 成果主義とは？

ビジネスにおける“成果”は、しばしば**短期的かつ分かりやすい数字**で評価されます。  
報告書、プレゼン資料、経営判断の材料として、「効果があった」と言えることが何より重視されがちです。

そのため、「分析の結果として効果があったことにしてほしい」「成功ストーリーを作ってほしい」といったプレッシャーを受けることは少なくありません。

### 一方、再現性とは？

一方で、**再現性は科学的分析の根幹**を成す要素です。

- 手法が一貫していること  
- 仮説と検証のプロセスが透明であること  
- 同じ手順を他者が再現可能であること  

これらを欠いた分析結果は、単なる偶然やバイアスによる産物かもしれません。

---

## 実務で経験した“ズレ”の瞬間

以下は、私自身がこれまでに経験した場面の一部です。

| 状況 | 分析者の内心 | ステークホルダーの要望 |
|------|--------------|--------------------------|
| A/Bテストで有意差が出なかった | 「これは誤差の範囲だな…」 | 「でも、効果あったことにしないと施策が止まってしまう」 |
| 仮説と異なる結果が出た | 「意外だけど、他の要因を探してみたい」 | 「それだと話が複雑になる。仮説に沿うように調整して」 |
| サンプルサイズが少なすぎた | 「この結果では判断できない…」 | 「でも上に報告しなきゃいけない。何か“言えること”を作ってほしい」 |

現場の人々に悪気はなくても、「都合のいい結果」への期待は確かに存在しています。

---

## 分析者としてどう向き合うか

### 1. “迎合”はしない

求められるままに切り口を変え、p値が有意になるまで繰り返し分析し、結果に合わせて仮説を後付けする……  
これは、**分析者としての信頼を損なう行為**であり、自分自身の納得も得られません。

### 2. かといって“正論”だけでは響かない

「それは科学的に正しくない」と伝えることが必要な場面もありますが、現場の事情や立場を無視した主張は、かえって壁を作ることもあります。

### 3. だからこそ、“伝え方”と“バランス”が重要

- 正しさを守りながらも、相手に伝わる言葉を選ぶ  
- 短期の成果と長期の信頼の間で、最善の落としどころを探る  
- 「分析しない」という判断も含めて、誠実な選択をする  

---

## 私自身が意識しているスタンス

- データと向き合う**誠実さ**を失わない  
- **「結果が出なかったとき」の説明力**を磨く  
- **分析しない勇気**も選択肢として持つ  
- 分析者としての役割と責任を、忘れない  

どれも理想論に見えるかもしれません。  
でも、こうした考え方を少しずつでも現場に浸透させることが、分析者としての信頼を築く第一歩だと信じています。

---

## おわりに：それでも再現性を信じたい

データサイエンスがビジネスの中で求められるようになった今、私たちは常に「科学としての正しさ」と「現場が求める成果」のあいだで揺れています。

でも、もしも「再現性」を軽視し、「納得感のある物語」だけを優先するようになったら、それは**分析職という専門性の価値を自ら壊す行為**ではないでしょうか。

地道でも、時に煙たがられても、  
「この分析は、本当に信頼できるのか？」という問いを持ち続けたい。  
それが、私なりの“抵抗”であり、**希望**でもあります。

---

## 補足：p-hacking / HARKing / QRPとは？

- **p-hacking**：p値が有意になるまで分析を繰り返す行為  
- **HARKing（Hypothesizing After Results are Known）**：結果を見た後に仮説を後付けすること  
- **QRP（Questionable Research Practices）**：再現性や透明性を損なう分析全般のこと  

---

## 最後に

あなたの現場では、「それってp-hackingでは？」と感じたこと、ありませんか？  
あるいは、正しさを主張しづらかった経験、ありませんか？
そういうものがあれば、ぜひ共有してください！
PHPer Kaigi 2025：初心者が楽しむための体験レポート

# はじめに

現地まで行き、PHPer Kaigi 2025に参加してきました。  
結論から言うと、参加を強くお勧めします。  
本記事では、参加したことがない方に向けて、情報を提供することを目的としています。  
※ 本記事の内容は個人の主観に基づいており、正確な情報は[公式ページ](https://phperkaigi.jp/2025/)をご確認ください。

# PHPer Kaigiとは

PHPer Kaigiは、技術的なノウハウを共有する交流会です。  

## 雰囲気

小難しい講義を想像しがちですが、実際には和やかな雰囲気で、身内で集まって行う勉強会のような感じです。  
また、「ランチマッチ」という交流企画もあり、一人で参加しても安心です。  
（懇親会には参加していないため、詳細は不明です。）

## 内容

実務経験が1年程度の方でも理解できるN+1問題の話から、PHPを活用している方に向けた内容まで、幅広いプレゼンテーションが行われます。  
実践的な内容が多く、非常に役立ちました。  
また、ユーモアを交えたプレゼンが多いため、聞いていて疲れません。

## ランチ企画について

「ランチマッチ」は、PHPer Kaigiの参加者同士が集まり、ランチを共にしながら技術的な話をする企画です。  
飲食店の選び方や話題に関する印刷物が配布されるため、気まずい雰囲気になる心配はありません。

# 参加に必要なこと

- **チケットの購入**  
  早めに購入することをお勧めします。ノベルティ付きのチケットを選ぶと良いでしょう。  
  ノベルティのTシャツがあれば、少なくとも1日は服装に悩まずに済みます。  

# 参加時の服装

スーツを着る必要はありません。  
極論、Tシャツとジーパンでも許される雰囲気です。

# 持ち物

基本的にはスマホだけで大丈夫です。  
メモを取りたい場合は、ノートやノートパソコン、タブレットなど、お好きなツールを持参してください。

# さいごに

お祭りのような和やかな雰囲気の中で、役立つ話を聞くことができます。
参加を迷っている方は、軽い気持ちでエントリーすることをお勧めします。
複素数平面「(その2/4)【1問多解】2025年 京都大(理系) 複素数の絶対値の最大・最小」様をAI先生に丸投げ。

・mathjaxの丸投げです。

:::note info
[(その1/4) sympyで](https://qiita.com/mrrclb48z/items/af2e0208b8ef1b8a92a5)
(その2/4) 本ページ
[(その3/4) AI先生へxy平面へ書き換え](https://qiita.com/mrrclb48z/items/7116ef1032b91886e749)
[(その4/4) AI先生へ5通りで](https://qiita.com/mrrclb48z/items/97f1b76173d4e42326d0)
:::

# (再出)オリジナル
**・問題文(mathjax テキスト形式)**
　大学入試数学問題集成 様。いつもお世話になっております。
　2025 京都大学 前期MathJax理系【１】問１
　https://mathexamtest.web.fc2.com/2025/202510541/2025105410100mj.html
　https://mathexamtest.web.fc2.com/daigakubetumj/10541index.html#y2025

# ChatGPT先生へ
　（省略)
# (本日の)Gemini先生へ

#### 質問リスト
```
# 質問リスト
1.  次の各問に答えよ．
    * 問１　$i$は虚数単位とする．複素数$\,z\,$が，絶対値が$\,2\,$である複素数全体を動くとき，$\left|z-\displaystyle\frac{i}{z}\right|$の最大値と最小値を求めよ．
2.  上記をsympyのソースコードで教えて下さい。結果もテキスト形式で。
3.  以上の私の質問をMarkdown形式でリスト化して出力して。Markdown形式でリストからアスタリスクは削除して。 1行目に、# 質問リスト　の文字を出力して。追番をふって下さい。
4.  上の質問リストをmarkdown形式で。本質問も含めて。
5.  markdown形式で。
```

>(回答省略)

・上記をsympy のソースコードで教えて下さい。
```python
from sympy import *

# 変数の定義
theta = symbols('theta', real=True)

# 複素数zの定義
z = 2 * (cos(theta) + I * sin(theta))

# i/zの計算
iz = I / z

# z - i/zの計算
diff = z - iz

# 絶対値の2乗の計算
abs_sq = simplify(abs(diff)**2)

# 三角関数の合成
abs_sq = simplify(abs_sq.subs(cos(theta)**2, 1 - sin(theta)**2))
abs_sq = simplify(abs_sq.subs(sin(theta)*cos(theta), sin(2*theta)/2))

# 最大値と最小値の計算
max_abs_sq = abs_sq.subs(sin(2*theta), -1)
min_abs_sq = abs_sq.subs(sin(2*theta), 1)

# 絶対値の計算
max_abs = sqrt(max_abs_sq)
min_abs = sqrt(min_abs_sq)

# 結果の出力
print("最大値:", max_abs)
print("最小値:", min_abs)
```
実行結果:
```
最大値: 5/2
最小値: 3/2
```
# copilot先生へ

# いつもの? sympyの実行環境と 参考のおすすめです。
[(テンプレート)](https://qiita.com/mrrclb48z/items/00dd08b0317069be9342)

https://qiita.com/mrrclb48z/items/b6351b48e47bcf6265c0

# いつもと違うおすすめです。
array_mergeはpushするよりも30倍遅い

```bash
$ php test.php 
Xdebug: [Step Debug] Could not connect to debugging client. Tried: localhost:9003 (through xdebug.client_host/xdebug.client_port).
=== array_merge を使用する場合 ===
array_merge の実行時間: 18.542617082596 秒

=== foreach と array_push を使用する場合 ===
foreach + array_push の実行時間: 0.53139305114746 秒
bool(true)
```


```php:test.php
<?php
ini_set('memory_limit', '2048M');

$baseArray = range(1, 10000);

echo "=== array_merge を使用する場合 ===\n";

$resultMerge = [];  // 初期は空の配列
$startMerge = microtime(true);
for ($i = 0; $i < 1000; $i++) {
    // 毎回、新しい配列として再代入する
    $resultMerge = array_merge($resultMerge, $baseArray);
}
$timeMerge = microtime(true) - $startMerge;
echo "array_merge の実行時間: {$timeMerge} 秒\n";

echo "\n=== foreach と array_push を使用する場合 ===\n";

$resultPush = [];  // 初期は空の配列
$startPush = microtime(true);
for ($i = 0; $i < 1000; $i++) {
    foreach ($baseArray as $value) {
        $resultPush[] = $value;
    }
}
$timePush = microtime(true) - $startPush;
echo "foreach + array_push の実行時間: {$timePush} 秒\n";

var_dump(json_encode($resultMerge) === json_encode($resultPush));

```
OracleにはLimit句が使えなかった＠SQL講習

# こんにちはSQL講習です:robot:
オブジェクティブグループの@Yukidarusanです！
弊社では月に1回、社内講習会を開いておりまして自分はSQL講習を担当しております。
今回はその中で使用したLimit句について、追加で解説させていただきます！

## Limit句って実はメジャーではない？
SQL講習でも登場しましたLimit句です！
全部のレコード出すのも時間がかかるし...かといってまだ条件で絞るには早すぎる...といったときに便利に使用できるLimit句ですが、実はOracleDBでは使用できません。追加でSQL Serverでも使用できません。
講習でもお話があったかと思いますが、SQL文が基本どのリレーショナルデータベース管理システム（以降RDBMS）でも基本的なものは一緒です。
ですが、細かい箇所で差異があります。
今回はそんなお話を一つ！

## Limit句の代わり
じゃあ使えないなら、似たようなことができないのか！？というと...似たような動きをできる句があるのです。ここから各RDBMSでの抽出件数を指定したSQL文を例を交えて説明します

1. Oracle:ROWNUM疑似列
    ROWNUMを使用することによって、Limit句のような動きをさせることができます。
    注意点としては、意図しないソート順の上位件数を抽出するため、副問い合わせ等でソートを指定する必要があります。
    ```sql
    -- 顧客マスタを顧客IDでソートした上から10行を表示する
    SELECT * FROM
        (SELECT * FROM kokyaku_mst
            ORDER BY kokyaku_id)
    WHERE ROWNUM < 11;
    ```
    
1. SQLServer：TOP
    TOPを利用すれば同じ形に表示できます。
    ```sql
    -- 背番号でソートした上から10名の選手を表示する
    select TOP 10 * from player_mst order by back_number;
    ```
## Limit句の使い方
Limit句の使い方自体も各RDBMSで違いがあったので参考までに:yum:
1. PostgreSQL：LimitーOFFSET
    Limitの後に件数を指定し、OFFSETで開始位置を指定します。
    ```sql
    -- ５個目の売上から10個売上を表示する
    select uriage_amount from uriage_rireki Limit 10 OFFSET 5;
    ```
1. MySQL：Limit
    引数を２つ指定可能。
    ```sql
    -- 40人の社員を表示する
    select *from Emproyee_mst Limit 40;
    -- 105人目から30人の社員を表示する
    select *from Emproyee_mst Limit 30,105;
    ```

## 使えなくても手立てはある
今回はLimit句に対して、ない場合は同じような手立てがあるか？ある場合は使用方法について記載しました。ここまで違う使い方なのもなかなかありません。
他の句でも、存在しなくても何か手立てはあるものです。
慌てず、手立てがないか調べながら実施してみましょう。

***

### ※参考

https://techracho.bpsinc.jp/penguin10/2020_05_22/92490

https://gumfum.hatenablog.com/entry/2022/03/21/180000

https://style.potepan.com/articles/27640.html
Qiitaをgithubから投稿するときにしておくべきおすすめ設定_パート1


# はじめに

qiita で推奨されている Github との連携は済んでいますか？
https://github.com/increments/qiita-cli

今回は追加で対応すると良いものを記載します。

# こんな人におすすめ!

- Qiita と Github の投稿用リポジトリを連携し終わっている人
- Qiita の投稿をもっと楽にやりたい人

# TL;DR

- 「Automatically delete head branches Loading」を有効化

# おすすめ設定

### ①GitHub リポジトリ Settings

#### Automatically delete head branches Loading

連携したリポジトリの設定にある「Automatically delete head branches Loading」を有効にします。
＊『Settings > General > Pull Request』にあります。

この設定をすると、main ブランチにマージした際に、feature ブランチが削除されます。

書き途中の記事を main ブランチにプッシュしてしまうと投稿されてしまいます。
そのため、記事を下書きしておきたい場合、feature ブランチを切ってこちらにプッシュしておく必要があります。

そこで投稿するたびにブランチをマージし、feature ブランチを削除する必要が発生しますが、
main にマージした段階で自動で feature ブランチが削除されるため、一手間不要になります！

# まとめ

<!--
#### Dependabot の有効化

### Node modules


# 参考リンク
 -->
2回目のRubyGold受けたけど1点足りなかった件。

2回目のRubyGold受けてきました。
結果は、100点満点中74点...

ボーダーラインは75点です。(.- -.)

やってしまった...
16,500円がぁぁぁ

![スクリーンショット 2025-04-10 19.38.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711491/409b9c35-8fd4-4beb-a1cf-1dfd59cd475b.png)

なんで落ちたのか、振り返っていきます。

# 出題された内容

覚えている範囲で、出題された内容は以下です。

* 転送引数
* ナンバードパラメータ
* `include`,`prepend`の探索経路
* `catch`と`throw`の問題
* `case..in..end`のパターンマッチング
* 正規表現の`$0`,`$1`,`$2`の問題
* `refinement`で`using`を選択させる問題
* `(1..Float::INFINITY)`で`lazy`を選択させる問題
* `x, y, z = [1, 2]`で、`z`は`nil`になる問題
* 例外処理で`raise`に何も指定しなかった場合、なんのクラスを返すか
* 例外処理で`rescue => e`を記述した場合、なんのクラスを返すか
* 例外処理で`exit`が実行された場合、`SystemExit`が返ってくる
* 例外処理で`ensure`節が実行される
* 可変長引数（`*aaa`）の特徴
    * 「デフォルト値を持たせることはできるか」など
* `DateTime`クラスのオブジェクトで「`+`」「`>>`」かを選ばせる問題
* `Comparable`モジュールの`<=>`演算子の挙動の問題
* `Proc.new`と`lambda`で、引数の制限が緩い方を選ばせる問題
* `const_missing`メソッドをオーバーライドした時の挙動
* `define_method`と`class_eval`と`instance_eval`選ばせる問題

細かい内容までは覚えていないです。すみません。

# どうやって勉強した？

## 教材

以下の教材を使用して、対策を行いました。

* Ruby技術者認定試験合格教本（バージョン3.0対応）

https://www.amazon.co.jp/gp/product/B0756VF9Y3/ref=ppx_yo_dt_b_d_asin_title_o00?ie=UTF8&psc=1

* Githubに公開されていた練習問題

https://github.com/ruby-association/prep-test/blob/version3/gold_ja.md

* Rex

https://rex.libertyfish.co.jp

* インターネット上に落ちている受験者の皆さんの記事

↓例↓

https://qiita.com/universato/items/e5a9b2fb75e412f8e780

## 勉強時間

細かいところまでは覚えていないですが、「こういう時に勉強してた」というのはお伝えしておきます。

* **通勤時の電車の中**で教本を読み漁る
* **出社する1時間前にカフェに寄って**模擬問題を解く
* **退勤後に家の近くのカフェに寄って**模擬問題を解く
* **土日の空いている時間を見つけて**模擬問題を解く

こんな感じです。

基本的に隙間時間を見つけて勉強するようにしていました。

↓エビデンスはこちら↓

https://x.com/kuracchi_enj

# 不合格の原因

## 1. 問題と答えを覚えてしまっている状態になっていた

試験中、同じことを問われている問題でも、少し形式が変わってきたりすると一気に難しく感じました。
問題を解いていたと言っても、**教本の模擬問題**と**Githubの問題**と**Rexの問題**しか解いていなかったので、正直なところ「**問題と答えを覚えてしまっている**」という状態になっていました。

なので、次の受験までに取り組みたい点としては、
「**GPTやClaudeにお願いして、類題をたくさん作ってもらってたくさん解く**」
ことです。

:::note warn
生成AIを使う場合、Rubyスクリプトを実際に実行して本当に正解か確認する必要はありますが。
:::

## 2. Ver2.1→V3.1の新機能に対応できていなかった気がする

ナンバードパラメータは好きだから自信しかないですが、転送引数の問題はノーマークでした。

せめて`filter_map`メソッドなら解けたけどって思いますが、勉強不足でしかないですよね。

# まとめ

悔しい。
【Unity】UniTaskのキャンセル処理（その４）

# はじめに
:::note info
**この記事は下記記事の続きです**
[【Unity】UniTaskのキャンセル処理（その３）](https://qiita.com/isshi777/items/4ddb70abb629bd5d1b5a)
:::

## ThrowIfCancellationRequestedを使用
前回の記事から少し変えたソース（下記）で同様の操作をします
ソースは前回記事のProcess1関数内の
`UniTask.DelayにcancelTokenを渡さない`ようにした
`cancelToken.ThrowIfCancellationRequested();`を呼ぶようにした

**１、Aキーを押すだけ**
**２、Aキーを押した直後にZキーを押して５秒くらい待機**
それぞれどのようなログが出るでしょうか？
```test.cs
public class UniTaskTest1 : MonoBehaviour
{
	private CancellationTokenSource cancelTonkenSource = new CancellationTokenSource();

	private void Update()
	{
		if(Input.GetKeyDown(KeyCode.A))
		{
			this.cancelTonkenSource = new CancellationTokenSource();
			this.MainProcess(this.cancelTonkenSource.Token).Forget();
		}
		else if (Input.GetKeyDown(KeyCode.Z))
		{
			this.cancelTonkenSource?.Cancel();
		}
	}

	private async UniTask MainProcess(CancellationToken cancelToken)
	{
		try
		{
			var val = await this.Process1(cancelToken);
			Debug.Log("結果：" + val);
		}
		catch(OperationCanceledException e)
		{
			Debug.Log("MainProcess catch");
		}
		finally
		{
			Debug.Log("MainProcess finally");
		}
	}

	private async UniTask<int> Process1(CancellationToken cancelToken)
	{
		try
		{
			Debug.Log("開始");
			int result = -1;
			await UniTask.Delay(TimeSpan.FromSeconds(3f));
			Debug.Log("待機終了");

            cancelToken.ThrowIfCancellationRequested();

			result = 1;
			if (cancelToken.IsCancellationRequested)
			{
				Debug.Log("キャンセル2");
				return result;
			}

			result = 2;
			return result;
		}
		catch (OperationCanceledException e)
		{
			Debug.Log("Process1 catch");
			throw;
		}
		finally
		{
			Debug.Log("Process1 finally");
		}
	}
}
```
### 正解
**１、Aキーを押すだけ**
![スクリーンショット 2025-04-10 011024.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820411/306e5ff4-f80a-4314-8578-92085d69e502.png)


**２、Aキーを押した直後にZキーを押して５秒くらい待機**
![スクリーンショット 2025-04-10 011053.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820411/fe11117b-6e5e-45e4-a214-058b9ad3c536.png)

## まとめ
１は同じなので２を見てみます。
UniTask.DelayにcancelTokenを渡していないので即キャンセルせず`待機終了`ログが出てます。
その後`キャンセル2`のログは出ず、Catch内に入っていることがログからわかります。

ということは、
キャンセル確認＆例外発生は渡された`CancellationTokenのThrowIfCancellationRequested`を呼べばよさそうですね。
ていうか関数名そのままですね。

また、
非同期処理が呼ばれた段階でキャンセルされている可能性だってあるので`まずは関数の先頭でThrowIfCancellationRequestedを呼ぶ`というのが安全そうです！
　
　
他にも複数のCancellationTokenリンクさせたりする方法など便利そうなのもあるっぽいのですがいったんここまでです。
ありがとうございました。<(_ _)>
【Unity】UniTaskのキャンセル処理（その３）

# はじめに
:::note info
**この記事は下記記事の続きです**
[【Unity】UniTaskのキャンセル処理（その２）](https://qiita.com/isshi777/items/ef231f2c6d51d69d13ce)
:::

## Try-Catch-Finallyを使用（Catch内でthrowを呼ぶ）
前回の記事から少し変えたソース（下記）で同様の操作をします
ソースは前回記事のProcess1関数内の`return 99;`を`throw`に変えただけです

**１、Aキーを押すだけ**
**２、Aキーを押した直後にZキーを押して５秒くらい待機**
それぞれどのようなログが出るでしょうか？
```test.cs
public class UniTaskTest1 : MonoBehaviour
{
	private CancellationTokenSource cancelTonkenSource = new CancellationTokenSource();

	private void Update()
	{
		if(Input.GetKeyDown(KeyCode.A))
		{
			this.cancelTonkenSource = new CancellationTokenSource();
			this.MainProcess(this.cancelTonkenSource.Token).Forget();
		}
		else if (Input.GetKeyDown(KeyCode.Z))
		{
			this.cancelTonkenSource?.Cancel();
		}
	}

	private async UniTask MainProcess(CancellationToken cancelToken)
	{
		try
		{
			var val = await this.Process1(cancelToken);
			Debug.Log("結果：" + val);
		}
		catch(OperationCanceledException e)
		{
			Debug.Log("MainProcess catch");
		}
		finally
		{
			Debug.Log("MainProcess finally");
		}
	}

	private async UniTask<int> Process1(CancellationToken cancelToken)
	{
		try
		{
			Debug.Log("開始");
			int result = -1;
			await UniTask.Delay(TimeSpan.FromSeconds(3f), cancellationToken: cancelToken);
			Debug.Log("待機終了");

			result = 1;
			if (cancelToken.IsCancellationRequested)
			{
				Debug.Log("キャンセル2");
				return result;
			}

			result = 2;
			return result;
		}
		catch (OperationCanceledException e)
		{
			Debug.Log("Process1 catch");
			throw;
		}
		finally
		{
			Debug.Log("Process1 finally");
		}
	}
}
```
### 正解
**１、Aキーを押すだけ**
![スクリーンショット 2025-04-10 004013.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820411/ac5eb5b9-3897-4624-8d1d-b37a7529f3a5.png)


**２、Aキーを押した直後にZキーを押して５秒くらい待機**
![スクリーンショット 2025-04-10 004058.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820411/3ab4ed6d-a2f3-4166-ba50-4d8d7e106763.png)

## まとめ
１は同じなので２を見てみます。
前回の記事ではMainProcess側の`Catch内のログ`は出ていませんでした。
今回は逆にMainProcess内の`Try内の結果ログ`が出ず、`Catch内のログ`が出ました。
呼び出し元にも例外が発生したと伝えるにはしっかり`throw`をする必要がありそうです。

**ということは、**
・内部で起きた例外は内部で後処理して呼び出し元には`成功失敗のみ`を伝えたいとき
　　→戻り値をboolにしてCatch内では必ずFalseで返す、など。
・呼び出し元にも明確に`例外が発生した`と返す
　　→Catch内でしっかりthrowを呼ぶ

これでよさそうですね。

　
**でも気になる・・。**
今回はUniTask.Delayが例外を出したけど自前の非同期関数でキャンセル時に例外を出すにはどうすれば・・・。
続きは次の記事で
  
**次の記事（続き）**
[【Unity】UniTaskのキャンセル処理（その４）](https://qiita.com/isshi777/items/b44880653c613cc1d12b)