OmniAICreator/Qiita-1.07M huggingface dataset:
JavaScriptにおけるデバウンス / スロットリングの設計戦略とリアルタイム制御構造


## 概要

リアルタイムにユーザー入力を処理するとは、「すべてを即時に処理すること」ではない。  
それは**“必要なタイミングだけを抽出し、過剰な処理を制御する”ための戦略的設計**である。

JavaScriptでは、スクロール・リサイズ・キー入力・マウス操作など**高頻度のイベント**が大量に発生する。  
それらを**無制限に処理することは、UI崩壊・パフォーマンス劣化・クラッシュ**につながる。

本稿では、**デバウンス（debounce）とスロットリング（throttle）**を明確に定義し、  
どのように設計的に使い分けるかを解説する。

---

## 1. デバウンス（Debounce）とは

```ts
function debounce(fn, delay) {
  let timeout;
  return (...args) => {
    clearTimeout(timeout);
    timeout = setTimeout(() => fn(...args), delay);
  };
}
```

- ✅ 一定時間「入力が止まった後」に実行
- ✅ 主に **検索フォーム・オートセーブ・リアルタイムバリデーション** などに使用

---

## 2. スロットリング（Throttle）とは

```ts
function throttle(fn, interval) {
  let last = 0;
  return (...args) => {
    const now = Date.now();
    if (now - last >= interval) {
      last = now;
      fn(...args);
    }
  };
}
```

- ✅ 一定間隔で**強制的に実行を制限**
- ✅ 主に **スクロール・リサイズ・マウス移動処理** などに使用

---

## 3. 違いの比較

| 特性             | Debounce                          | Throttle                         |
|------------------|-----------------------------------|----------------------------------|
| 実行タイミング     | 入力が止まってから                | 一定間隔で強制実行               |
| ユースケース       | フォーム送信、検索、バリデーション | スクロール、リサイズ、カーソル追従 |
| 発火回数          | 最後の1回                         | 定期的に複数回                    |

---

## 4. 高速環境での制御とアニメーション挙動

```ts
// rAFと組み合わせて負荷軽減しつつ滑らかに描画
let ticking = false;

window.addEventListener("scroll", () => {
  if (!ticking) {
    window.requestAnimationFrame(() => {
      handleScroll();
      ticking = false;
    });
    ticking = true;
  }
});
```

- ✅ `requestAnimationFrame` を使うことで**FPSと描画タイミングを同期**
- ✅ イベント処理と描画負荷を切り離せる

---

## 5. ユースケース別設計指針

| ユースケース          | 推奨制御方法        |
|-----------------------|---------------------|
| 検索ボックスの入力     | Debounce（300ms前後） |
| ウィンドウサイズ変更   | Throttle（200ms前後） |
| リアルタイム変換        | Debounce + 最終送信保証 |
| スクロール中のDOM制御   | Throttle + requestAnimationFrame |
| 文字数カウント / フォーム入力 | Debounce（100〜300ms） |

---

## 設計判断フロー

```text
① ユーザー操作が「停止した後に」実行すべきか？ → Debounce

② 一定間隔で「定期的に」処理したいか？ → Throttle

③ リアルタイム性が必要でも「頻度が高すぎる」か？ → rAF + 制御構造

④ イベントを100%検知したいか？ → Debounceのtrailingフラグを有効化

⑤ ユーザー体験を阻害しない処理タイミングか？ → イベント発火点と描画負荷を分離
```

---

## よくあるミスと対策

### ❌ 入力のたびにAPIリクエストを飛ばす（100msで10回以上）

→ ✅ **Debounceで遅延制御し、1回に抑える**

---

### ❌ スクロール中に毎回処理が走ってFPSが激落ち

→ ✅ **Throttle + rAFで滑らかに制御**

---

### ❌ Throttleのインターバルが短すぎて意味がない

→ ✅ **200ms〜500msに設計値を上げることで処理頻度を現実的に**

---

## 結語

デバウンスとスロットリングは「処理を減らす手段」ではない。  
それは**“ユーザー行動の粒度に応じて、実行タイミングと頻度を意図的に設計するための制御構造”**である。

- Debounce は「静止後に実行」  
- Throttle は「頻度を制限して定期実行」  
- 描画系は rAFで描画サイクルと同期させる

**JavaScriptにおけるリアルタイム制御とは、  
“入力を解釈し、実行の意図とタイミングを分離することでUXと性能を両立させるための設計戦略”である。**
JavaScriptにおける状態フラグ設計とif分岐の構造化戦略：脱フラグ・脱ネストで設計を明示化する


## 概要

状態フラグとは「true/falseを表す変数」ではない。  
それは**“制御の分岐点を表す記号であり、設計意図の複雑性を反映した構造的トリガー”**である。

複雑化したフラグ管理、入り組んだif文、深いネスト。  
これらは往々にして**「仕様ではなくコードの都合によって」生まれる構造的負債**である。

本稿では、**状態フラグをどう定義し、if分岐をどう構造的に整理するか**という  
**“脱ネスト・脱フラグ”設計戦略**について解説する。

---

## 1. 状態フラグの罠：フラグが増えるほどコードが壊れる

```ts
if (isAdmin && !isSuspended && hasAccess) {
  renderDashboard();
}
```

- ✅ 単純な論理だが、**3つの真偽値の組み合わせは8通り**
- ❌ 組み合わせが増えるほど **条件が意図とズレる**

---

## 2. 意味的な状態を「値」で持つ（フラグをやめる）

```ts
// ❌ フラグで状態管理
if (isLoading) ...
if (isError) ...
if (isSuccess) ...

// ✅ 意味をenum/定数で明示
const status = "success"; // "loading" | "error" | "success"

switch (status) {
  case "loading": ...
  case "error": ...
  case "success": ...
}
```

- ✅ 状態の意味を **「型 + 値」で定義** → 拡張・判定が明確に
- ✅ 条件式ではなく **状態遷移を管理する発想**

---

## 3. 複雑な条件は「命名関数 or ガード節」で整理する

```ts
function canAccess(user) {
  return user.isAdmin && !user.isSuspended && user.token !== null;
}

if (!canAccess(currentUser)) return showError();
```

- ✅ 条件式を「名詞化」することで**意図が明示される**
- ✅ ネストを浅く保つ構造（ガード節）に変換

---

## 4. フラグの「逆」条件は読みやすく書き換える

```ts
// ❌ 二重否定で読みづらい
if (!isNotFound) { ... }

// ✅ 肯定表現に置き換える
const isFound = !isNotFound;
if (isFound) { ... }
```

- ✅ ロジックよりも「人間の読みやすさ」が優先されるべき
- ✅ 否定条件はリファクタ対象

---

## 5. 状態管理にEnum的構造を導入する（TypeScriptにも好相性）

```ts
const STATUS = {
  LOADING: "loading",
  SUCCESS: "success",
  ERROR: "error"
};

switch (status) {
  case STATUS.LOADING:
  case STATUS.SUCCESS:
  case STATUS.ERROR:
    ...
}
```

- ✅ 文字列のハードコーディングを避ける
- ✅ 状態追加時も意図が見える・崩れにくい

---

## 設計判断フロー

```text
① フラグが3つ以上同時に存在しないか？（論理爆発リスク）

② 条件文の長さが「3つ以上の論理結合」になっていないか？

③ 否定条件（!isX）の多用で読みにくくなっていないか？

④ 状態の意味がフラグではなく「状態名」として表現できないか？

⑤ 条件式を「名前付きの関数 or 命名された変数」にできないか？
```

---

## よくあるミスと対策

### ❌ `if (a && !b && c)` のような無名の論理評価

→ ✅ **canActivate() のような意味を持つ関数に変換する**

---

### ❌ フラグを3つ並列で管理して状態の整合性が壊れる

→ ✅ **状態を「ひとつの値（enum, status文字列）」として定義する**

---

### ❌ ネストが深く、else if地獄になっている

→ ✅ **ガード節（先にreturn）で条件ごとに切り出す**

---

## 結語

状態フラグとは「制御用の真偽値」ではない。  
それは**“状態の流れを示す構造化された情報”**であり、  
その表現が適切でなければ、コードの読みやすさと保守性は急速に劣化する。

- フラグではなく「状態名」として意味を表現し  
- if条件は「意図を名前にする」構造で管理し  
- ネストや否定を減らすために設計で整理する

**JavaScriptにおけるフラグと分岐の設計とは、  
“状態の意味を正しく名前づけ、構造としてコードに表すための論理設計戦略”である。**
初期選択可能なスクロールタブを作る

# はじめに
今回はSwiftUIを使って良くある初期選択が可能なスクロールタブを実装していきます
### コード
```swift
// 該当位置までスクロールさせるにはScrollViewReaderが必要
ScrollViewReader { scroll in
    ScrollView(.horizontal, showsIndicators: false) {
        HStack(spacing: 8) {
            ForEach(0..<viewModel.tabs.count, id: \.self) { index in
                let tab = viewModel.tabs[index]
                segmentItem(title: tab.title, isSelected: viewModel.isSelected(index: index))
                    .id(index)
                    .onTapGesture {
                        // タップ処理
                    }
                    .padding(.horizontal)
                }
                // 生成時に選択済みの箇所までスクロールさせる
                // anchorはどこまでスクロールさせるかの選択
                .onAppear {
                    scroll.scrollTo(viewModel.selectedIndex, anchor: .leading)
                }
            }
```
### 最後に
意外と使う機会が多いので、備忘録的に残してみました
どなたかのお役に立てれば幸いです
JavaScriptにおける型変換（暗黙・明示）の設計的理解とエラー制御戦略

## 概要

JavaScriptにおける型変換とは「値が勝手に変わること」ではない。  
それは**“コードの文脈に応じて型が変換されることを理解し、その動作を意図的に制御・防御するための戦略設計”**である。

JavaScriptは動的型付け言語であり、**数値・文字列・真偽値・null/undefined・オブジェクト間の変換**が頻繁に起こる。  
しかしそれらは**「直感に反した挙動」や「意図しないバグ」の温床にもなる**。

本稿では、**暗黙の型変換と明示的変換の動作と落とし穴**を整理し、  
**安全な型設計・防御的プログラミングの考え方**を解説する。

---

## 1. 暗黙の型変換（coercion）の代表例

```ts
console.log(1 + "2");       // "12"
console.log("3" * "4");     // 12
console.log(null == 0);     // false
console.log(undefined == null); // true
```

- ✅ `+` は **文字列が混じると連結**
- ✅ `*`, `-`, `/` は **数値に変換されて演算**
- ❌ `==` は **曖昧な型変換を含む**

---

## 2. 明示的な型変換の設計例

```ts
const str = String(123);   // "123"
const num = Number("42");  // 42
const bool = Boolean("");  // false
```

- ✅ 明示的に変換することで**意図をコードに残せる**
- ✅ `parseInt`, `parseFloat` は **文字列から数値への特化型**

---

## 3. toString / valueOf による内部変換

```ts
const obj = {
  valueOf() { return 10; },
  toString() { return "object"; }
};

console.log(obj + 1); // 11
```

- ✅ **valueOf優先** → プリミティブへの変換が内部で呼ばれる
- ❌ **object + number → 意図しない挙動**が発生しやすい

---

## 4. 数値変換時の罠

```ts
Number("0x10")    // ✅ 16
parseInt("08")    // ❌ 8（10進と認識されず）
parseInt("08", 10) // ✅ 8
```

- ✅ `parseInt` は **radix（基数）指定が必須**
- ❌ `"08"` や `"09"` のような先頭0つき数値に注意

---

## 5. NaNとの比較・防御戦略

```ts
console.log(NaN === NaN);  // ❌ false
console.log(Number.isNaN(NaN)); // ✅ true
```

- ❌ `NaN` は自分自身とすら一致しない
- ✅ 比較には `Number.isNaN()` を使うのが安全

---

## 6. == vs === の使い分け再考

```ts
false == 0       // ✅ true（型変換あり）
false === 0      // ❌ false（型違い）

"0" == 0         // ✅ true
"0" === 0        // ❌ false
```

- ✅ `===` を基本とし、`==` を使うときは**仕様理解 + 設計意図明確化**

---

## 設計判断フロー

```text
① 暗黙変換に頼っていないか？（特に + や ==）

② 明示的に変換すべき場面で typeof や constructor を使っているか？

③ 入力値の型が常に保証されるか？ → エラーハンドリングや型チェックの設計

④ NaNやundefinedなど「変換不能値」が混入しない設計か？

⑤ 明示的変換で意図をコードに残しているか？
```

---

## よくあるミスと対策

### ❌ `==` によって `"0"` と `false` が等価に扱われる

→ ✅ **===で型も値も一致させる**

---

### ❌ `"08"` を `parseInt` したら意図と違う値が返ってくる

→ ✅ **第2引数に `10` を明示的に与える**

---

### ❌ NaN同士を `===` で比較して false になる

→ ✅ **`Number.isNaN()` を使用して確実な判定を行う**

---

## 結語

型変換とは「JavaScriptが勝手にやってくれるもの」ではない。  
それは**“構文の中に潜む意図しない変換を制御し、意図を可視化して安全な型設計を行うための戦略”**である。

- 暗黙変換は原則避け  
- 明示的に変換することでコードの意図を可視化し  
- 変換不能な値や境界値（NaN / undefined）に対する戦略を組み込む

**JavaScriptにおける型変換とは、  
“言語仕様の不透明さと設計意図の橋渡しを行うための安全制御構造”である。**
JavaScriptにおけるイベント駆動 vs ポーリング設計：リアクティブ構造の戦略的比較



## 概要

非同期を扱う上で、JavaScriptには2つの根本的なアプローチがある。  
それが **「イベント駆動（Event-driven）」** と **「ポーリング（Polling）」** である。

両者は単なる実装手法の違いではない。  
それは**“どこで変化を検知するか”**というリアクティブアーキテクチャの構造的な差異を意味する。  
目的・頻度・性能要件・データ性質に応じて、設計を誤れば「過剰な監視 or 取りこぼし」のどちらかに偏る。

本稿では、両者の違いとメリット・デメリット、使い分けの判断軸を構造的に解説する。

---

## 1. イベント駆動（Event-driven）とは

```ts
document.addEventListener('click', handler);
ws.onmessage = handleMessage;
observer.observe(target);
```

- ✅ **対象側で変化が発生したときに“通知”される構造**
- ✅ 変化が発生しなければ**無駄な処理が走らない**

---

## 2. ポーリング（Polling）とは

```ts
setInterval(async () => {
  const data = await fetch('/api/status');
  update(data);
}, 5000);
```

- ✅ **一定周期で状態をチェックし、自分で差分を検出する構造**
- ❌ 「変化がないのにリクエストが発生」 → **リソース消費が増大**

---

## 3. 使用目的による選定戦略

| 用途                              | 推奨方式       |
|-----------------------------------|----------------|
| ユーザー操作（クリック、入力）   | イベント駆動   |
| ファイル読み込み完了             | イベント駆動   |
| 他サービスからの状態取得        | ポーリング     |
| WebSocketやPush通知がある場合    | イベント駆動   |
| APIがpull型のみ提供              | ポーリング     |

---

## 4. ハイブリッド設計のパターン

```ts
let lastState = null;

setInterval(async () => {
  const state = await fetchState();
  if (state !== lastState) {
    onStateChange(state);
    lastState = state;
  }
}, 10000);
```

- ✅ ポーリングでも **変化時だけ反応**すればリソース削減可能
- ✅ **初回だけポーリング → WebSocketに切り替え**のような戦略も有効

---

## 5. パフォーマンス設計視点

```text
【イベント駆動】
- メリット: 無駄な処理なし / 瞬時に反応
- デメリット: 通知が飛ばないと何もできない（Pushが必須）

【ポーリング】
- メリット: 外部サービスが受動的でも制御可能
- デメリット: 頻度が高すぎると重い / 遅延 or 過検出
```

---

## 設計判断フロー

```text
① データの発生源は「Push型（能動的）」か「Pull型（受動的）」か？

② 状態の変化頻度は高いか？（高頻度ならPushの方が効率的）

③ タイムラグ許容度は？（ポーリングは最短でも遅延が発生）

④ 外部APIの仕様上、イベント通知が可能か？

⑤ ユーザー体験として「即時反応」が必須か？
```

---

## よくあるミスと対策

### ❌ 状態変化がまれなのに高頻度でポーリングしている

→ ✅ **適切な周期設計 + 差分検知 + 一時停止制御**で最適化

---

### ❌ Push通知を信用しすぎて取りこぼし発生

→ ✅ **定期ポーリングで冗長チェックするフォールバック構成**

---

### ❌ イベントリスナを登録しっぱなしでリーク

→ ✅ **removeEventListener / disconnect / unsubscribe の設計を組み込む**

---

## 結語

イベント駆動 vs ポーリングとは、単なる「手法の違い」ではない。  
それは**“変化をどこで捉えるか、誰が検知を担うか、リアクティブ設計をどう構築するか”**という戦略の選定である。

- Pushが可能ならイベント駆動が優秀  
- 受動的APIや状態監視にはポーリングが不可欠  
- 双方の特性を理解した上で、必要に応じたハイブリッド設計を構築する

**JavaScriptにおけるイベント vs ポーリングとは、  
“変化の発見と即応性の制御を通じて、UI・UXの一貫性を支える非同期制御の構造戦略”である。**
JavaScriptにおける真偽値とFalsy判定の落とし穴：型変換と条件分岐の設計的戦略

## 概要

JavaScriptの真偽値は「trueかfalseか」ではない。  
それは**“型に依存する曖昧な変換ルールの上に成り立つ評価系”**であり、  
**"Truthy / Falsy の正体を理解せずに条件分岐を組むと、意図しないロジックバグを生む”**。

JavaScriptは動的型付け言語であり、if文や条件演算子における「評価」は**暗黙の型変換（coercion）**に委ねられる。  
それを**安全に扱うための設計戦略**と、**比較演算・条件評価の明示的制御**をこの記事では解説する。

---

## 1. JavaScriptにおける「Falsy」な値とは？

```ts
const falsyValues = [false, 0, -0, 0n, "", null, undefined, NaN];
```

- ✅ 上記はすべて `if (value)` で **falseと判定される**
- ❌ `""` や `0` など、**実在する値なのに「false扱い」される**

---

## 2. 暗黙的 vs 明示的な条件分岐の違い

```ts
const input = "";

if (input) {
  proceed(); // ❌ 実際には空文字だが、Falsyなので通らない
}

if (input.length > 0) {
  proceed(); // ✅ 「空でない文字列」の明示的な判定
}
```

- ✅ 条件は **目的に応じて明示的に書く**
- ✅ "存在" を問う → `value != null`  
- ✅ "非空" を問う → `value.length > 0`

---

## 3. == vs === による型変換の影響

```ts
0 == false     // ✅ true（型変換あり）
0 === false    // ❌ false（型違い）

null == undefined  // ✅ true
null === undefined // ❌ false
```

- ✅ `==` は「等価」ではなく「**曖昧な変換付き比較**」
- ✅ **設計的には常に `===` を使うのが原則**

---

## 4. 条件評価の失敗例とリファクタ戦略

```ts
function isEmpty(value) {
  return !value; // ❌ 0や""を全て弾いてしまう
}
```

```ts
function isEmptyString(value) {
  return typeof value === 'string' && value.length === 0;
}
```

- ✅ 判定したい対象の「意味」を明示する
- ❌ 型の違いや目的の曖昧化が **UIバグや意図違い**を生む

---

## 5. "truthy/falsyに頼らない" 条件式設計

```ts
// ❌ 暗黙の評価
if (userInput) {
  ...
}

// ✅ 明示的に書くべき設計
if (typeof userInput === 'string' && userInput.trim().length > 0) {
  ...
}
```

- ✅ 条件式には「文脈」がある → それをコードに反映
- ✅ "0" や `""` を「ない」とみなすのは **文脈依存**

---

## 設計判断フロー

```text
① この条件分岐は「値の存在」を見ているのか？「値の中身」を見ているのか？

② 条件式の評価が文脈とズレていないか？（e.g. 0, ""）

③ == を使っていないか？（使うなら明確な理由があるか？）

④ 明示的な判定ができる設計か？（型 / 範囲 / 中身）

⑤ falsyな値を意図的に許容するなら、明文化されているか？
```

---

## よくあるミスと対策

### ❌ `if (value)` で 0 や "" まで弾いてしまう

→ ✅ **存在確認なら `value != null`、中身確認なら `.length` や `.trim()`**

---

### ❌ `==` を使って型の違いに気づかないままロジックが破綻

→ ✅ **原則 `===` / `!==` で明示的な比較を行う**

---

### ❌ falsy判定に頼りすぎて意味の伝わらない分岐になっている

→ ✅ **条件式は「意味の名詞化 + 明示」で構造的に記述**

---

## 結語

Truthy / Falsy とは「true/falseの代替」ではない。  
それは**“型と構造に依存した暗黙の変換であり、設計的な意図が表現されていない限り、ロジックの罠となる”**。

- 比較は常に `===` を基本とし  
- 存在と中身の違いを分けて記述し  
- 条件分岐は「文脈」と「意図」を可視化する形で表現する

**JavaScriptにおける真偽値判定とは、  
“設計意図と型の関係を安全に可視化するための制御構造のデザインである。”**
JavaScriptにおけるスプレッド構文 / 分割代入の設計的使い方と安全制御


## 概要

スプレッド構文や分割代入とは「書き方のショートカット」ではない。  
それは **“データの構造を明示的に操作し、可視性と安全性を担保しながら状態を再構築するための設計手段”** である。

JavaScriptにおける `{ ...obj }` や `[a, b] = arr` は直感的だが、  
**参照のコピー / シャローな複製 / 後勝ちマージ / 無効なキー展開**など、  
使い方を誤ると**構造の破壊と状態の誤伝播**を引き起こす。

本稿では、**スプレッド構文・分割代入の内部挙動と設計的判断軸**を徹底的に整理する。

---

## 1. スプレッド構文とは「シャローコピー（浅い複製）」

```ts
const original = { a: 1, b: { nested: true } };
const clone = { ...original };

clone.b.nested = false;
console.log(original.b.nested); // ❌ false（参照が共有されている）
```

- ✅ スプレッドは「1階層分のコピー」であり、**ネスト構造は共有**
- ❌ 深い構造をスプレッドで複製したつもりでも、**実際は共有渡し**
---

## 2. 分割代入は「存在しないキーにもアクセスしうる」

```ts
const obj = { name: 'Alice' };
const { name, age } = obj;

console.log(age); // ✅ undefined（存在しなくても破綻しない）
```

- ✅ 分割は「安全なアクセス構文」だが、**存在確認には向かない**
- ✅ defaultを使えば設計的に保証可能：

```ts
const { age = 0 } = obj;
```

---

## 3. 後勝ちマージの危険性と設計対策

```ts
const base = { role: 'guest', admin: false };
const override = { admin: true };

const user = { ...base, ...override }; // ✅ admin: true（後勝ち）
```

- ✅ スプレッドは**右側が優先される**
- ❌ **順番ミスで意図が壊れる** → 設計上、merge関数化するのが安全：

```ts
function mergeUser(base, override) {
  return { ...base, ...override };
}
```

---

## 4. 配列のスプレッドとミューテーション

```ts
const list = [1, 2, 3];
const copy = [...list];

copy.push(4);
console.log(list); // ✅ [1, 2, 3]（破壊されていない）
```

- ✅ 配列コピーには有効
- ❌ ただしオブジェクト同様、**ネストされたオブジェクトは共有される**

---

## 5. 分割代入のリネームと構造再構築

```ts
const user = { id: 1, name: 'toto' };
const { name: displayName } = user;

console.log(displayName); // ✅ 'toto'
```

- ✅ **別名を付けて意図を明確化**できるのが強み
- ✅ 状態や用途が違うときは**リネームで役割を明示**

---

## 6. スプレッド + 構造変更 = 要設計

```ts
function transform({ name, ...rest }) {
  return {
    username: name,
    ...rest,
    updatedAt: new Date(),
  };
}
```

- ✅ **フィールド名のリネーム + 残差マージの安全実装**
- ✅ REST構文で**不要なフィールドを除外・伝播防止**可能

---

## 設計判断フロー

```text
① スプレッドでコピーした構造は「参照が深くない」か？

② 分割代入で安全なデフォルトが設計されているか？

③ スプレッドマージ順は明示的で、後勝ちの意図があるか？

④ ネスト構造の複製が必要なら、deepCopyに切り替えているか？

⑤ 状態構築の中で「意図しないフィールド」が混入していないか？
```

---

## よくあるミスと対策

### ❌ スプレッドでcloneしたつもりが元のオブジェクトを破壊

→ ✅ **ネスト構造ならdeepClone戦略を設計に組み込む**

---

### ❌ マージ順のミスで意図が逆転し、権限付与などが崩壊

→ ✅ **スプレッドは右優先 → 書き順と意図の一致が重要**

---

### ❌ 分割代入で存在しないプロパティを使ってバグ発生

→ ✅ **default値 + 明示的型保証 or fallback戦略を設計**

---

## 結語

スプレッドや分割代入とは「簡単に書ける記法」ではない。  
それは **“構造を明示的に操作し、状態と安全性の両立を支える設計表現”** である。

- 浅いコピーであることを理解し  
- 意図した順序とキー制御で構造を扱い  
- フィールド名の変更 / 除外 / 分離を設計として定義する

**JavaScriptにおけるスプレッド構文と分割代入とは、  
“状態を定義し、構造を制御するための記法と設計戦略”である。**
DigiSpark互換品でマウスもどき(ホイール上下と左ボタンのみ）を作る。

足の操作でコード譜表示サイトをスクロールしながら弾き語りするためのデバイスを作成。
（自作デバイスで日常遣いしてるのはこれだけ）
スイッチ３つ。信号配置は以下の通り
|Pin|接続先|機能
|:--:|:--:|:--:|
|P0| SW1(IN)|ｽｸﾛｰﾙｱｯﾌﾟ
|P1| SW2(IN)|左ｽｲｯﾁ
|P2| SW3(IN)|ｽｸﾛｰﾙﾀﾞｳﾝ
|P3|NC|(USB D-)
|P4|NC|(USB D+)
|P5|NC|(Reset)|

~~Eagleをアンインストールしてしまったので回路図は割愛。~~
回路は@nak435様投稿の↓の記事の回路と同じ。
https://qiita.com/nak435/items/5e9320342729ae76e40d

P0,P2に繋がるSW1/SW2の反対側はGND。（INPUT_PULLUPで開放時H）
P1はLEDが繋がってるので PullUpせず、反対側は５Vに繋ぐ。

ソースコードは以下の通り。

~~~C++

#include <DigiMouse.h>

int step =  -1;
void setup() {
  pinMode( 0, INPUT_PULLUP);
  pinMode( 1, INPUT);//PB1はLED繋がってる
  pinMode( 2, INPUT_PULLUP);
  
  DigiMouse.begin(); //start or reenumerate USB - BREAKING CHANGE from old versions that didn't require this
}

void leftkeyClick(int pin, int cond)
{
    DigiMouse.setButtons(1);
    //離されるのを待つ
    while(cond==digitalRead(pin)){
      DigiMouse.delay(10);
    };
    DigiMouse.setButtons(0);
}

void rightkeyClick(int pin, int cond)
{
    DigiMouse.setButtons(-1);
    //離されるのを待つ
    while(cond==digitalRead(pin)){
      DigiMouse.delay(10);
    };
    DigiMouse.setButtons(0);
}

void loop() {
  // If not using plentiful DigiMouse.delay(), make sure to call
  // DigiMouse.update() at least every 50ms
  
  if( LOW==digitalRead(0)){ //コレはPULL-UP
   DigiMouse.scroll(step);  
  }  else if( LOW==digitalRead(2)){ //コレはPULL-UP
    DigiMouse.scroll(-step);
  }
  else if(HIGH==digitalRead(1)){  //コレはPULL-DOWN
    leftkeyClick(1, HIGH);
  }
  DigiMouse.delay(100);
}
~~~
以上
access2000の作法 その42

# 概要
access2000の作法、調べてみた。
練習問題やってみた。

# 練習問題
重複をチェックせよ。

# サンプルコード

```
Private Sub コマンド37_Click()
		Key = Me.Filter
		q = Me.発行番号.Value
		Dim db As ADODB.Connection
		Set db = Application.CurrentProject.Connection
		Dim rs As ADODB.Recordset
		Dim sql As String
		Set rs = New ADODB.Recordset
		sql = "SELECT * FROM main WHERE bango='" & q & "' 
		rs.Open sql, db, adOpenKeyset, adLockOptimistic
		If rs.RecordCount > 0 Then
			MsgBox "この番号は、使われています。"
			Exit Sub
		End If
End Sub


```

# 重複レコードを検索する
- クエリ ウィザードを使用して重複レコードを検索するには、次の手順に従います。

- [作成] タブの [クエリ] グループで [クエリ ウィザード] をクリックします。 

- [新しいクエリ] ダイアログで [重複クエリ ウィザード]、[OK] の順にクリックします。

- テーブルの一覧でテーブルを選び、[次へ] をクリックします。

- 照合するフィールドを選んで [次へ] をクリックします。

- 使用可能なフィールドの一覧で、更新するデータが含まれるフィールド (複数可) を選んで [次へ] をクリックします。

- クエリ名の候補を承諾するか名前を入力して [完了] をクリックし、クエリを実行します。



以上。
文字と塗りつぶし図形を使った中まど文字の設定方法

文字と塗りつぶし図形を使った中まど文字の設定方法
→文字をアウトライン化していないので後から文字の内容を変更できる
→ダイレクト選択ツールで文字を移動させることができる
![20250403-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4051538/7af9af47-8751-4568-b6f4-ea5523f485f7.png)
<br><br>

１、任意の文字と中抜きしたい図形を用意する。
![20250403-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4051538/1c2eb27e-6984-4984-95de-38a335e6c096.png)
<br><br>


２、文字と図形を重ねて、選択してグループ化する
→GTRL+G
![20250403-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4051538/39c8d6df-bad6-417e-bddc-b780d24fb2c5.png)
<br><br>


３、効果→パスファインダー→中まどを実行する
![20250403-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4051538/971dcbf2-dee3-4ad5-93d9-f1e2b72bd21c.png)
<br><br>


４、完成
→文字の位置などを調整するときはダイレクト選択ツールで文字の部分だけを選択すると移動させることができる。
![20250403-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4051538/0768ace8-538f-4597-a452-0db24a4f13ee.png)
<br><br>
ブロックを使う配列のメソッドmap, select, findの覚え方

## 背景
上記のコマンドの違いを何回調べても忘れるので、覚え方を記載する。

## map
英単語の動詞mapは位置関係、地図を作るという意味。
そこからベクトルをイメージする、例えば[x,y]
 **ブロックの戻り値で新しい配列[x,y]** を作る、つまりmapというイメージが湧く

## select
findとの違いが分かりにくいので、エイリアスメソッドのfind_allを使う
そうすれば、 **ブロックの戻り値が真になったものを全て見つける** ,つまりfind_allというイメージが湧く

## find
先ほどのfind_allと比較すると、findだけ、全てではない？、つまり一つだけ選ぶというイメージ。
そこから **ブロックの戻り値が真になった初めの一つだけの要素を抽出する** という覚え方ができる。
Laravel11+FortifyのForgot passwordでアカウントがなくても成功時と同じメッセージを表示する

LaravelのFortifyのForgot passwordの機能において、デフォルトではパスワードリセットしたいアカウントを入力したときに存在するアカウントだと「メールを送信しました」というようなメッセージが表示され、アカウントが存在しない場合はその旨を知らせるメッセージが表示されます。

これだとそのシステムにアカウントがあるかどうかが分かってしまうのでセキュリティ的にはあまり良くありません。
なのでいずれの場合も「メールを送信しました」というメッセージを表示させるということをしたい時があると思います。
少し調べたのですがあまり情報がなかったのでここに記載しておきます。

# 実装方法

まずroutes/web.phpにコードを追加します。
forgot-passwordが呼び出されたときに自前のPasswordResetLinkControllerを呼び出すようにしています。

```web.php
use App\Http\Controllers\Auth\PasswordResetLinkController;

Route::get('/forgot-password', [PasswordResetLinkController::class, 'create'])
    ->middleware(['guest'])
    ->name('password.request');

Route::post('/forgot-password', [PasswordResetLinkController::class, 'store'])
    ->middleware(['guest'])
    ->name('password.email');
```

次にapp\Http\Controllers\AuthにPasswordResetLinkController.phpを作成し中身を以下のようにします。
元の動作としては
if ($status === Password::RESET_LINK_SENT)
のような条件文を入れて正常なときとアカウントがなかった時でメッセージを表示分けするわけですが今回は同じメッセージで良いのでどんな場合でも同じメッセージを返すようにしています。

メッセージは「パスワードリセットリンクのメールを送信しました。届かない場合はメールアドレスが間違っていないか、迷惑メールフォルダに入っていないかを確認してください」的な感じにするとさらに親切かと思います。

```AuthにPasswordResetLinkController.php
<?php

namespace App\Http\Controllers\Auth;

use Illuminate\Http\Request;
use Illuminate\Contracts\Support\Responsable;
use Laravel\Fortify\Http\Controllers\PasswordResetLinkController as FortifyPasswordResetLinkController;
use Illuminate\Support\Facades\Password;
use Laravel\Fortify\Contracts\SuccessfulPasswordResetLinkRequestResponse;

class PasswordResetLinkController extends FortifyPasswordResetLinkController
{
    public function store(Request $request): Responsable
    {
        $request->validate(['email' => 'required|email']);

        $status = Password::sendResetLink(
            $request->only('email')
        );

        return app(SuccessfulPasswordResetLinkRequestResponse::class, ['status' => "メールを送信しました"]);
    }
}
```

以上で完了です。
アカウントが存在しない場合でも同じメッセージが表示されるか確認してみてください。
JavaScriptの落とし穴: 数値0がfalsy扱いされることによるバリデーションバグ

##発生した問題
フォームから選択された account_role の値（0：選手）が正しく処理されず、「アカウントタイプを入力してください」というバリデーションエラーが発生していました。


##原因
JavaScriptでは数値の 0 は falsy 値として扱われます。そのため、バリデーション関数内で以下のようなコードがあると問題が発生します：

```
javascriptコピー
if (!formData.account_role) {
  // エラーを設定
  errors.account_role = "アカウントタイプを入力してください";
}
```
ユーザーが選手（account_role = 0）を選択した場合、0 は falsy と評価されるため、この条件は true となり、値が存在しないと誤って判定されてしまいます。


##解決策
以下のいずれかの方法で解決できます：
##厳密な比較を使用する
```
javascriptコピー// 未定義またはnullの場合のみエラーを出す
if (formData.account_role === undefined || formData.account_role === null) {
  errors.account_role = "アカウントタイプを入力してください";
}
```


##型変換してから確認する
```
javascriptコピー// 数値型に変換してから条件をチェック
const roleValue = parseInt(formData.account_role, 10);
if (isNaN(roleValue)) {
  errors.account_role = "アカウントタイプを入力してください";
}
```


##存在確認を適切に行う
```
javascriptコピー// プロパティの存在を確認
if (!Object.prototype.hasOwnProperty.call(formData, 'account_role')) {
  errors.account_role = "アカウントタイプを入力してください";
}
```

##サーバーに送信する前の処理
バックエンド側に送信する際は、型をチェックしてから処理しましょう：

```
javascriptコピー// 送信前に型チェック
if (typeof formData.account_role === 'string') {
  formData.account_role = parseInt(formData.account_role, 10);
}
```

##JavaScriptのfalsy値について
JavaScriptでは以下の値がfalsy（偽と評価される）として扱われます：

-false
-0（数値のゼロ）
-""（空文字列）
-null
-undefined
-NaN

これらの値に対して論理否定演算子（!）を使用すると、true が返されます。そのため、値の存在チェックを行う際は、この点に注意が必要です。


##まとめ
JavaScriptでのフォームバリデーションを実装する際は、数値の 0 が有効な値である場合、単純な ! による存在チェックではなく、undefined や null との厳密な比較、または適切な型変換を行いましょう。このような細かい落とし穴に気をつけることで、ユーザー体験を損なうバグを防ぐことができます。
OpenAI: GPT-4o mini の料金計算ロジック

## この文書について

非エンジニアの方に説明する機会があったので、記録しておきます。	

■ OpenAI の料金表はこちら
https://openai.com/ja-JP/api/pricing/

今回は、「GPT-4o mini」を計算します
※ 2025.4.3 時点の料金
* 入力：$0.150 / 100万トークン
* 出力：$0.600 / 100万トークン

初心者の方向けに詳しく書くと、
* 入力は、プロンプト（命令書）の文字量
* 出力は、レスポンス（回答）の文字量
* チャット1回 ＝ 入力 + 出力 です

---

## まず日本語1文字に何トークンを消費するか

### 日本語におけるトークン換算の目安

| 種別       | 概算トークン数/文字 | 備考 |
|------------|--------------------|------|
| 日本語の1文字（漢字・ひらがな・カタカナ） | **1～1.2 トークン** | 句読点や記号も含めると増えることもある |
| 日本語の文章（平均）              | **1文字 ≒ 1.1トークン** | 長文のサンプルから計算した平均的な値 |

これで、100万トークン ÷ 1.1 ≒ **約90万文字の日本語入力** と考えてよさそうです。

### 入力
* $0.150 / 100万トークン(日本語で約90万文字)
    *  日本語1文字あたり: 0.000000167ドル
        *  1ドル150円の場合: 0.00002505円

### 出力
* $0.600 / 100万トークン(日本語で約90万文字)
    *  日本語1文字あたり: 0.000000667ドル
        *  1ドル150円の場合: 0.00010005円

---

※ 従量課金としての「見積書」を出す場合、この部分の説明になると思います。

---

## 具体的な見積もり

* 要約の場合を例にあげます

### 入力
* HTML から文字だけを除いて1,000文字の場合、$0.000167

### 出力
* 1,000文字なら $0.000667
    * ※1,000文字以内で要約を作るとした場合

### 合計
* 入力: $0.000167 + 出力: $0.000667 = $0.000834（≒ 約0.1251円）

---

### 実際の要約処理の流れ

* 前処理: PHP の file_get_contents で要約するページの HTML を取得
    * ヘッダ、フッタ、ナビ、広告コードなどを除く処理を行う
* プロンプトと合わせて、前処理で取得した本文をリクエスト
* レスポンスも合わせて（ページによりますが）、1,000～3,000文字程度のチャットになる
* 結論として、0.1～0.3円で、要約が作れることが分かりました

---

※ ウェブ検索を行うと、前処理は不要です（1回約10円かかります）
　 前処理を実装するかしないかで、かなりコストが変わってきます。

---

## PHP での換算関数

AI というと、Python で利用される方が多いと思いますが、私は PHPer なので…。PHP での関数を残しておきます。

```php
/**
 * OpenAI の利用コストを計算する(GPT-4o mini)
 * 料金表: https://openai.com/api/pricing/
 * 2025年3月現在の料金表を元に計算
 *
 * @param int $promptTokens 使用した入力トークンの数。
 * @param int $completionTokens 使用した出力トークンの数。
 * @param float $exchangeRate 為替レート（USD/JPY）。
 * @return array 日本円でのコスト（USD, JPY）
 */
function calCostGpt_4o_MiniInJPY($promptTokens, $completionTokens, $exchangeRate)
{
    // 1,000トークンあたりの単価 (GPT-4o mini)
    $pricePerMillionInputTokens = 0.15; // Input
    $pricePerMillionOutputTokens = 0.60; // Output

    // トークンのコストを計算
    $promptTokensCostInUSD = ($promptTokens / 1000000) * $pricePerMillionInputTokens;
    $completionTokensCostInUSD = ($completionTokens / 1000000) * $pricePerMillionOutputTokens;

    // 合計コストを計算
    $totalCostInUSD = $promptTokensCostInUSD + $completionTokensCostInUSD;

    // 日本円でのコストを計算
    $costInJPY = $totalCostInUSD * $exchangeRate;

    return [$totalCostInUSD . 'ドル', round($costInJPY, 2) . '円'];
}
```

---

## OpenAI 公式ツールでトークン数を計算する

* [Tokenizer](https://platform.openai.com/tokenizer)
    * テキスト内のトークンの合計数を確認できます

---

参考になりましたら、幸いです。
きれいなバラのような図形を作成する

完成時は下記のようになります。<br><br>
![unnamed.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4051538/5e501e1e-5627-4fe7-a2ec-068a375c4a88.png)

<br><br>
１、スターツールで点の数を３０ほどで作成する
→作成後大きさやひだの長さを調整する
![unnamed (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4051538/475f053a-70d2-4564-816a-4440f9c7da22.png)

<br><br>
２、塗りに円形でグラデーションをかける
→作成するときはいろいろと試す
![unnamed (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4051538/bce7638b-f535-4586-aec1-ae31d48c0798.png)

<br><br>
３、効果→パス→ランダム・ひねりをかける
→水平、垂直を８％で設定
→水平、垂直の数値をいじって調整する
![unnamed (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4051538/c019982b-0b49-4d53-b053-67c7e81a4d5b.png)

<br><br>
４、コピーをして同じ場所に張り付け、１枚をできるだけ小さくする
→グルーピングを行っておく
![unnamed (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4051538/74e01977-3522-4c69-a981-1947277ab7fa.png)

<br><br>
５、オブジェクト→ブレンド→作成を行なう
→違う場合は「オブジェクト→ブレンド→ブレンドオプション」にて設定する
→間隔にてステップ数にして数字を５０くらいに変更する
![unnamed (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4051538/6c67e149-83f0-48b5-a8a7-bf205764578d.png)

<br><br>
６、ブレンドオプションでステップ数などでひだの見た目を調整する
![unnamed (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4051538/22ea12ff-880d-40fe-84e9-80344b54b052.png)


完成
Tableauで日本地図を使って都道府県内の割合を可視化する方法

## この記事で学べること
tableauで日本地図を作成し、都道府県内ごとに割合を可視化する方法を紹介します。できることのイメージは以下の通りです。

例えば、「性別：男性」×「家族形態：一人暮らし」の属性をもつ人が各都道府県内で何%いるのか知りたいとき、それが日本地図上で可視化できるようになります。このようにその属性を持つ人が都道府県内ごとに何%くらいいるのかがわかります。また、これを応用することで都道府県内での売上割合や市場シェアなども可視化することが可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4051412/3faa20ea-91a4-4684-9470-ce3d142da4fa.png)



 # 想定読者
 ・talbeauの基本操作を理解している人
 ・tableauのLOD計算について理解している人（以下、LOD計算のわかりやすい記事です。）
 ・都道府県内ごとの人口・売上・市場シェアなどを可視化したい人

 https://qiita.com/tableau_oji_san/items/d60478cbfb0f9c0a7115

# 使用したデータについて
chatgptに日本人のデモグラデータを作成してもらい、それで実施しました。カラム構成は「id/性別/都道府県/職業/年収/学歴/家族構成」です。レコード数は2,000です。

 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4051412/cc5ab364-587f-4c26-82ba-16d8eb7b8183.png)


 ※ダミーデータなので実態には即しておりません。

 # 手順
 1.データをtableau workbookに読み込む
 2.[都道府県]の型を「都道府県/州」に変更
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4051412/cbc0038e-dceb-4e8c-aa46-48e416816e7c.png)

3.[都道府県]を画面中央にドラッグ&ドロップ
4.マークの種類を「マップ」に変更することで塗りつぶしにする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4051412/6a668afd-943c-46d5-a5f2-00274487a28e.png)


5.計算フィールドの作成
{INCLUDE [都道府県]:COUNT([Id])}/{FIXED [都道府県]:COUNT([Id])}
【計算フィールドの説明】
・分子：
　{INCLUDE [都道府県]:COUNT([Id])}
　VizLODの影響を受ける状態で都道府県ごとのidのカウントを行う
・分母：
　{FIXED [都道府県]:COUNT([Id])}
 　VizLODを無視して各都道府県ごとのidのカウントを行う
  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4051412/3e267415-b1ad-4bfb-8681-de4786acb0fc.png)


6.作成した計算フィールドを「色」にドラッグ＆ドロップ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4051412/44e8dd84-b1ec-48f2-934d-c0cee70b755a.png)

7.ツールヒントの表示をパーセンテージに変更
「色」に入れたメジャーの書式設定を変更することでパーセンテージにする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4051412/51dac1c6-7134-4cbb-97d3-a7158b2e6231.png)

8.日本以外の地形を非表示にする
地図を右クリックし、バックグラウンドマップレイヤーの設定に入り、チェックボックスをすべて外す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4051412/271cd796-8bc3-4051-bcfc-aa62140c1ab4.png)

9.属性のシートを作成し、ダッシュボードに配置
今回は「性別」「家族構成」「職業」「年収」を作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4051412/47609eb3-01d9-4545-8f93-0f103c19e0b5.png)

10.アクションフィルターの設定
ソースシートに地図以外、ターゲットシートに地図を入れる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4051412/53519e22-8191-4bf0-8519-1890808d15a0.png)

11.完成
例えば、「性別/男性」を押すと各都道府県内に男性が何%いるのかが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4051412/265cbea5-689a-4542-a43b-7fd157100f12.png)

複数選択も可能です。「性別/男性」×「年代/20代」のようにフィルターすると以下のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4051412/b28e5f9f-ae96-41f1-9889-60057b941f58.png)

※ダミーデータを用いているので確からしい数値にはなっていない点ご注意ください。
※何もフィルターをかけていない状態だとすべての都道府県で100%となります。

## まとめ
LOD計算を使うことで都道府県内での割合を日本地図上に表示することができました。
🎯 Pythonで極める！最先端の画像認識AI実装ガイド（OpenCV × 深層学習）



画像認識技術は、近年のAI分野で最も重要な領域の一つです。特に**Python**と**OpenCV**を活用することで、誰でも手軽に最先端の画像認識AIを構築できます。本記事では、

✅ **深層学習（Deep Learning）を活用した画像認識の基本**  
✅ **OpenCVを用いた画像前処理とデータ拡張**  
✅ **CNN（畳み込みニューラルネットワーク）の実装**  
✅ **事前学習済みモデル（Transfer Learning）で精度を向上**  
✅ **リアルタイム画像認識システムの構築**  

これらのポイントを詳しく解説し、Pythonだけで高精度な画像認識AIを作る方法を実践します。

---

## **1️⃣ 画像認識AIの基本と活用例**

画像認識技術は、以下のような幅広い分野で活用されています。

🔹 **自動運転**：カメラ映像を分析し、歩行者や信号を検出する  
🔹 **医療診断**：X線やMRI画像から疾患を特定  
🔹 **セキュリティ**：顔認識システムによる個人認証  
🔹 **製造業**：不良品の自動検出  

これらの技術の中心には、深層学習を活用した**畳み込みニューラルネットワーク（CNN）**が存在します。


## **2️⃣ OpenCVによる画像前処理とデータ拡張**

画像認識の精度を高めるためには、適切な前処理とデータ拡張が重要です。OpenCVを活用して、以下の処理を実装します。

### **📌 画像の読み込みと前処理**
```python
import cv2
import numpy as np

# 画像を読み込む
image = cv2.imread("sample.jpg")

# グレースケール変換
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# ノイズ除去
blur = cv2.GaussianBlur(gray, (5, 5), 0)

# エッジ検出
edges = cv2.Canny(blur, 50, 150)

cv2.imshow("Edges", edges)
cv2.waitKey(0)
cv2.destroyAllWindows()
```

👉 **ポイント：ノイズ除去やエッジ検出を行うことで、CNNの学習精度を向上できる！**


### **📌 データ拡張（Data Augmentation）**

データ拡張を行うことで、より多様なデータを学習させることが可能になります。

```python
from tensorflow.keras.preprocessing.image import ImageDataGenerator

datagen = ImageDataGenerator(
    rotation_range=30,
    width_shift_range=0.2,
    height_shift_range=0.2,
    horizontal_flip=True)
```

💡 **データのバリエーションを増やすことで、モデルの汎化性能が向上する！**


## **3️⃣ CNN（畳み込みニューラルネットワーク）の実装**

CNNを構築し、画像認識モデルを作成します。

```python
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense

# CNNモデルの構築
model = Sequential([
    Conv2D(32, (3, 3), activation='relu', input_shape=(128, 128, 3)),
    MaxPooling2D(pool_size=(2, 2)),
    Conv2D(64, (3, 3), activation='relu'),
    MaxPooling2D(pool_size=(2, 2)),
    Flatten(),
    Dense(128, activation='relu'),
    Dense(10, activation='softmax')  # 10クラス分類
])

# モデルのコンパイル
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
```

✅ **CNNを活用することで、画像の特徴を自動的に抽出できる！**


## **4️⃣ 事前学習済みモデル（Transfer Learning）の活用**

ゼロから学習するのではなく、既存の高精度なモデルを利用することで学習時間を短縮し、精度を向上させることができます。

```python
from tensorflow.keras.applications import VGG16

# VGG16モデルをロード（最後の全結合層を除く）
base_model = VGG16(weights='imagenet', include_top=False, input_shape=(128, 128, 3))

# 転移学習のための新しい全結合層を追加
model = Sequential([
    base_model,
    Flatten(),
    Dense(128, activation='relu'),
    Dense(10, activation='softmax')
])
```

👉 **事前学習済みモデルを活用することで、高精度なモデルを効率的に作成できる！**


## **5️⃣ リアルタイム画像認識システムの構築**

カメラを使ったリアルタイム画像認識を実装します。

```python
cap = cv2.VideoCapture(0)
while True:
    ret, frame = cap.read()
    if not ret:
        break
    
    # ここにモデルの予測処理を追加
    
    cv2.imshow("Real-time Image Recognition", frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
cap.release()
cv2.destroyAllWindows()
```

✅ **カメラ映像をリアルタイムで処理し、AIモデルと組み合わせることで応用範囲が広がる！**


## **📌 まとめ**

PythonとOpenCVを活用することで、画像認識AIをゼロから構築できることが分かりました。特に、

✅ **画像前処理やデータ拡張で学習の精度を向上**
✅ **CNNを用いた高精度な画像認識の実装**
✅ **事前学習済みモデルを活用して学習時間を短縮**
✅ **リアルタイム画像認識システムの構築**

これらのポイントを押さえることで、より高度な画像認識AIを作成できます。ぜひ試してみてください！ 🚀
【資格】AWS SAPに1発合格しました！！！

# はじめに
先日、AWS SAP(ソリューションアーキテクトプロフェッショナル)の試験を受けて、見事1発で合格することが出来ました:smile: 合格ラインギリギリ...

![スクリーンショット 2025-04-03 111556.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87924/5e81800c-feef-433c-b52e-564964493266.png)

ざっくり自分がやったことなどを紹介します。

# AWS SAPとは？
AWS SAPはAWS公式の認定資格であり、AWSでシステムを構築する上での、設計・実装全般の知識を問う資格の最上位資格になります。試験料金としては300USDと比較的高額です。
下位の資格として、SAA(ソリューションアーキテクトアソシエイト)があります。

資格によって試験時間や合格点が違うのですが、SAPの場合は180分で75問で、合格ラインは750点になります。
詳しい試験の概要や、試験範囲の割合は[こちら](https://d1.awsstatic.com/ja_JP/training-and-certification/docs-sa-pro/AWS-Certified-Solutions-Architect-Professional_Exam-Guide.pdf)に記載されています。

![スクリーンショット 2025-04-03 112526.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87924/7dc8fe3e-4784-4ec2-8cd5-dc2334457071.png)

![スクリーンショット 2025-04-03 112447.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87924/f5b4b492-ed01-4256-b061-ba05aa5d5625.png)


# 私自身の経歴
IT業界に入って10年になります。主にバックエンドの開発・設計を行ってきました。
AWSの経験としては4,5年くらいになります(AWS専属ではないため、実質3年くらいだとは思います)
AWS公式的には、プロフェッショナル資格は**2年以上のクラウド経験があることが望ましい**となっているので、もう少し経験が浅い人でも受けてみるのは良いと思います。
※私もほんとはもっと早く受けたかったのですが、一発で受かりたかったので今の時期に受けました。

1つ1つのAWSサービスで出来ることというよりは、複数サービスを組み合わせたりして、以下のような要件をかなえるための問題が多かった印象ではあります。
- **DR(ディザスタリカバリ)**を考慮したインフラ構成の検討
- **複数環境の統制**をするためのAWSサービスの組み合わせ(Organizationsなど)
- **オンプレミスからクラウドへ移行**、もしくは、**オンプレミスとクラウドで通信**する際のAWSサービスの選定
- **運用効率**を考えたマイクロサービスアーキテクチャへの移行
- **コスト削減**のためのAWSサービスの変更や割引プランの適用


なお、SAPに合格するまでに保有していた資格としては、
- Certified Cloud Practitioner
- Solutions Architect - Associate
- Developer - Associate
- SysOps Administrator - Associate
になります。
割と新しめのAI系やML系の資格はまだ持ってないです。

# やったこと
私がやったことは主に、以下の3つになります。

- 所属会社でのインフラ設計・構築
- 資格対策本での座学
- Udemyでの模擬試験実施

## 所属会社でのインフラ設計・構築
所属会社では主にCDKでのインフラ構築をしています。
そこで身に付けた複数環境へWebアプリケーションを構築するために必要な
- CI/CD周り(CodePipelien、CodeBuild、S3など)
- ECS、ECR
- EC2
- ALB
- Route53、ACM
- CloudFront
- S3
- WAF
- DB周り(Aurora、Dynamo)
- VPC
- IAM、Organizations
などの実務経験は役に立ちました。

## 資格対策本での座学

おそらく、AWS SAPの対策本で一番手に入りやすいこちらの本で勉強しました。
各AWSサービスの説明と、特定の要件に沿ったAWSサービスの説明をしてくれて、各章での演習問題と最後に模擬試験の形で問題を解くことが出来ます。
こちらを2周読みました！

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87924/7b2eaab7-5175-4d72-9609-e0a9f0f2fe05.png" width=50%>

## Udemyでの模擬試験実施

[AWS Solution Architect Professional (AWS-SAP-C02) 演習テスト](http://udemy.com/course/aws-solution-architect-professional-aws-sap-test/?couponCode=ST15MT20425G2)という講座を買いました。
75問×5回分の模擬試験を受けることが出来ます。

実際の試験と似たような問題が結構あったりして、非常に良かったです。
※**試験合格**という目標だけに特化するなら【Udemyでの模擬試験実施】だけでも受かるかもしれません:thinking: 

# おわりに
今回はAWS SAPの試験を受けた際にどんな風に勉強したか、などをまとめました。
これから受けようと思っている方の参考になれば、幸いです:bow:
Raspberry Pi OS Bookwormで画面が自動でブランクにならない問題と解決法（Wayland vs X11）

# Raspberry Pi OS Bookwormで画面が自動でブランクにならない問題と解決法（Wayland vs X11）

## 💡 背景

Raspberry Pi OS（Bookworm）を使っていて、「一定時間放置しても画面がブランク（ブラックアウト）にならない」問題に直面しました。

私はChatGPTに相談しながら解決しました。

以前の Bullseye では `xset` で設定できていたのに、Bookwormにしてから全く効かない…。

とChatGPTは申しております。
この記事はほとんどChatGPTに書いてもらっています。
執筆時点で情報なので将来にわたって同じ現象とは限らないのですが、困っている人がいたら参考にしてください。

## 👀 症状

- `xset s on` や `xset s 300` を実行しても画面が暗くならない  
- `xset +dpms` を実行すると `server does not have DPMS Extension` というエラー  
- `echo $XDG_SESSION_TYPE` の出力が `wayland`

## 🧠 原因

Raspberry Pi OS Bookworm から、**Wayland がデフォルトのディスプレイサーバ**になりました。

Wayland 環境では、従来の `xset` や `xrandr` による画面制御が無効 or 非対応となっており、これが原因です。

## ✅ 解決方法：X11（Legacy）に切り替える

### 1. `raspi-config` から X11 に切り替える

```bash
sudo raspi-config
```

- `Advanced Options`
- `Wayland / Legacy X11`
- **Legacy X11** を選択
- 再起動

### 2. セッションの確認

```bash
echo $XDG_SESSION_TYPE
```

`x11` と表示されればOK。

## ✅ X11 環境で画面ブランクを有効にする

```bash
xset s on          # スクリーンセーバーを有効に
xset +dpms         # ディスプレイ省電力を有効に
xset s 300         # 300秒（5分）でブランク
```

## ✅ 自動で設定を反映させる

### 方法1：`~/.xprofile` に追加

```bash
xset s on
xset +dpms
xset s 300
```

### 方法2：`/etc/xdg/lxsession/LXDE-pi/autostart` に追加（システム全体）

```bash
@xset s on
@xset +dpms
@xset s 300
```

## 💥 ハマりポイント

- `raspi-config` の切り替えが「Display Options」ではなく「Advanced Options」にある  
- `xset` が使えない理由が Wayland と気づきにくい  
- ターミナルで `^[OQ` が勝手に入力される → 原因は「別のUSBキーボードが押しっぱなし」だった  

## ✅ まとめ

| 状況 | 対応 |
|------|------|
| Raspberry Pi OS Bookworm | デフォルトは Wayland |
| `xset` が効かない | Waylandでは非対応 |
| `raspi-config` で切替可能 | `Advanced Options > Wayland/Legacy X11` |
| X11にすれば画面ブランク設定が可能 | `xset` で制御できるようになる |

## 📝 環境情報

- Raspberry Pi OS Bookworm（2023年10月リリース）
- Raspberry Pi 3B+
- 複数USBキーボード接続 → 不具合の原因に
🔥 LLMファインチューニング完全ガイド：LangChain & OpenAIで実現する最適化戦略





大規模言語モデル（LLM）の進化により、企業が独自のデータを活用してAIの性能を最大化する方法が求められています。本記事では、

✅ **LLMのファインチューニングとは？**  
✅ **LangChainを活用したRAG（Retrieval-Augmented Generation）との違い**  
✅ **OpenAIのAPIを用いた効果的なモデルカスタマイズ**  
✅ **実際のユースケースとベストプラクティス**  

これらのポイントを深掘りし、実践的な手法を解説します。

---

## **1️⃣ LLMのファインチューニングとは？**

ファインチューニングとは、事前学習済みのLLMに対して追加のデータを用いて特定のタスクに適応させるプロセスです。例えば、以下のような用途があります。

- **業界特化型のチャットボット**（金融、法律、医療など）
- **社内FAQボットの精度向上**
- **特定の言語・トーン・ドメインに最適化**

ファインチューニングは、事前学習済みのモデルをゼロからトレーニングするよりも少ない計算リソースで高いパフォーマンスを発揮できる点が強みです。


## **2️⃣ LangChainとRAGの活用：どちらを選ぶべきか？**

最近のLLMチューニングにおいて、**RAG（Retrieval-Augmented Generation）**と**ファインチューニング**のどちらを採用するべきかが議論されています。簡単に違いを説明すると：

| **手法** | **特徴** | **メリット** | **デメリット** |
|---------|----------|-------------|-------------|
| **ファインチューニング** | モデルの重みを更新して特定のデータに最適化 | 特定ドメインに最適化可能 | 継続的な更新が必要 |
| **RAG** | 外部の知識ベースを用いてリアルタイムで情報を取得 | 最新情報を取得可能 | プロンプト設計が複雑 |

LangChainはRAGを実装する際に非常に便利なライブラリであり、特に検索システムやFAQボットの構築に適しています。

💡 **結論：長期的な知識定着が必要ならファインチューニング、リアルタイムな情報更新が重要ならRAGが有効。**


## **3️⃣ OpenAI APIを活用したファインチューニングの手順**

OpenAIの`fine-tuning` APIを使ってLLMをカスタマイズする基本的な流れを見ていきましょう。

### **📌 手順 1：データ準備**
ファインチューニングでは、高品質なデータが成功のカギを握ります。以下のようなフォーマットでデータを準備します。

```json
{
  "messages": [
    {"role": "system", "content": "あなたはプロフェッショナルな法律アシスタントです。"},
    {"role": "user", "content": "契約書の作成方法を教えてください。"},
    {"role": "assistant", "content": "契約書には以下の重要な要素が含まれる必要があります..."}
  ]
}
```

👉 **ポイント：実際のユーザー対話データを収集・整理することが重要！**


### **📌 手順 2：データアップロード**
データを用意したら、OpenAIのCLIを使ってアップロードします。

```sh
openai tools fine_tunes.prepare_data -f training_data.json
```

次に、データが適切にフォーマットされていることを確認したら、ファインチューニングを開始します。

```sh
openai api fine_tunes.create -t "training_data_prepared.json" -m "davinci"
```

⏳ 数時間～数日でファインチューニングが完了し、カスタムモデルが利用可能になります。


### **📌 手順 3：ファインチューニングモデルのデプロイと活用**

モデルのトレーニングが完了したら、API経由で使用できます。

```python
import openai

response = openai.ChatCompletion.create(
    model="ft-your-model-id",
    messages=[
        {"role": "user", "content": "最新の契約法について教えてください。"}
    ]
)
print(response["choices"][0]["message"]["content"])
```

✅ **本番環境では適切なログ管理やモニタリングを行うことが重要！**


## **4️⃣ ベストプラクティスと実際のユースケース**

### **📌 ベストプラクティス**
- **データのクレンジングを徹底**：ノイズの多いデータは性能低下の原因になる
- **適切なモデルサイズを選択**：大きなモデルほど高コストになるため、ユースケースに応じた選択が必要
- **モニタリングと継続的な改善**：ユーザーのフィードバックを取り入れてモデルを改善


### **📌 実際のユースケース**
✅ **Eコマース企業のカスタマーサポート向けボット**  
✅ **法律事務所の専門知識を活用したアシスタント**  
✅ **金融機関のFAQ最適化**  


## **📌 まとめ**

LLMのファインチューニングは、特定ドメインに特化したAIモデルを作成する上で非常に強力な手法です。特に、

✅ **独自データを活用して高精度な応答を提供**
✅ **LangChainやRAGと組み合わせて動的な知識を活用**
✅ **OpenAI APIで効率的にトレーニング・デプロイ**

これらのポイントを意識することで、企業のAI活用が次のレベルへと進化します。ぜひ、実際に試してみてください！ 🚀
Windowsで名前重複しているファイルを削除するスクリプト

```
# 削除対象の文字列
$deleteString = "任意の文字列"

# 任意の文字列 の後に半角スペースがある場合も考慮した正規表現
$regex = '任意の文字列\s?(\d+)'  # 「任意の文字列」の後に半角スペースが0回または1回

# ファイルをグループ化するためのハッシュテーブル
$fileGroups = @{}

# ファイル検索とグループ化（「無料高画質」を含むファイルのみ）
Get-ChildItem -Recurse | Where-Object { $_.Name -match "任意の文字列\s?\d+" -and $_.Name -like "*$deleteString*" } | ForEach-Object {
    $match = $_.Name -match $regex
    if ($match) {
        $number = $Matches[1]
        if ($fileGroups.ContainsKey($number)) {
            $fileGroups[$number] += $_.FullName
        } else {
            $fileGroups[$number] = @($_.FullName)
        }
    }
}

# 重複ファイルの削除（1つだけ残す）
$fileGroups.GetEnumerator() | Where-Object { $_.Value.Count -gt 1 } | ForEach-Object {
    $filesToDelete = $_.Value | Select-Object -Skip 1  # 1つは残す
    $filesToDelete | ForEach-Object {
        try {
            Remove-Item $_ -Force
            Write-Host ('Deleted file: {0}' -f $_)  # 文字化け防止のため英語メッセージ
        } catch {
            Write-Warning ('Failed to delete file: {0}. Error: {1}' -f $_, $_.Exception.Message)
        }
    }
}
```
Gitマスターへの道：プロが使う10の裏技 & ベストプラクティス

# 🛠️ Gitマスターへの道：プロが使う10の裏技 & ベストプラクティス

Gitは単なるバージョン管理システムではなく、プロジェクトの効率性や開発者の生産性を大幅に向上させる強力なツールです。しかし、多くの開発者が基本的なコマンドに留まり、その潜在能力を十分に活かしきれていません。

本記事では、プロのエンジニアが実際の開発現場で活用しているGitの「裏技」や「ベストプラクティス」を10個厳選してご紹介します。これを読めば、あなたもGitマスターの仲間入りです！

---

## **1. git rebase -i で履歴を美しく整える**
チーム開発では、コミット履歴を分かりやすく整理することが重要です。`git rebase -i` を使えば、過去のコミットを編集、結合、削除することができます。

```bash
git rebase -i HEAD~5
```

例えば、直近5つのコミットを対象にして、不要なコミットを削除したり、複数のコミットを1つにまとめたりできます。特にPRを送る前に履歴をきれいにするのに有用です。

## **2. git stash を使いこなす（作業中の変更を一時保存）**
作業中の変更をコミットせずに一時的に保存したい場合、`git stash` が便利です。

```bash
git stash
```

その後、必要なときに取り出せます。

```bash
git stash pop
```

また、`git stash list` で保存した変更の一覧を確認できます。

## **3. git bisect でバグを高速に特定**
バグの原因となるコミットを特定するのに、`git bisect` は非常に強力です。

```bash
git bisect start
```

例えば、動作する最新のコミットと、バグが発生するコミットを指定し、Gitが自動で二分探索してくれます。

```bash
git bisect good <正常なコミットID>
git bisect bad <バグがあるコミットID>
```

その後、Gitが提示するコミットごとにチェックを行い、バグの原因を特定できます。

## **4. git cherry-pick で特定のコミットを別ブランチへ適用**
特定のブランチの変更を、別のブランチに適用したい場合に `git cherry-pick` を使います。

```bash
git cherry-pick <コミットID>
```

例えば、`feature-branch` で修正したバグを `main` に適用したい場合に便利です。

## **5. git commit --amend で直前のコミットを修正**
直前のコミットメッセージを変更したい場合、`git commit --amend` を使います。

```bash
git commit --amend -m "新しいコミットメッセージ"
```

また、直前のコミットに新しいファイルを追加することもできます。

```bash
git add <ファイル名>
git commit --amend --no-edit
```

## **6. git reflog で消えたコミットを復活**
ブランチを間違えて削除してしまったり、`git reset` で戻れなくなったときに `git reflog` が助けになります。

```bash
git reflog
```

これにより、最近の操作履歴が一覧表示されるので、該当のハッシュを使って復元できます。

```bash
git checkout <ハッシュ>
```

## **7. git reset --soft vs --hard の違い**
`git reset` はブランチを特定の状態に戻すコマンドですが、オプションによって動作が異なります。

- `--soft`: コミットのみ取り消し、変更内容はそのまま
- `--mixed`（デフォルト）: コミットとステージングを取り消し、変更内容はそのまま
- `--hard`: コミットも変更内容もすべて削除（注意！）

```bash
git reset --soft HEAD~1  # 直前のコミットを取り消す（変更は保持）
git reset --hard HEAD~1  # 直前のコミットを完全に削除
```

## **8. .gitignore を有効活用する**
不要なファイルをGitの管理対象から除外するために `.gitignore` を設定します。

例えば、以下の `.gitignore` はよく使われます。

```
node_modules/
.env
*.log
```

Gitに既に追加されてしまった不要なファイルを無視する場合は、以下のコマンドを実行します。

```bash
git rm --cached <ファイル名>
```

## **9. git blame で変更履歴を追跡**
特定の行が「誰によって、いつ変更されたのか」を知るために `git blame` を使います。

```bash
git blame <ファイル名>
```

各行ごとにコミットIDや作者が表示され、変更の経緯を把握できます。

## **10. git log のカスタマイズで履歴を見やすく**
標準の `git log` は情報が多すぎて見にくいですが、カスタマイズすれば見やすくなります。

```bash
git log --oneline --graph --decorate --all
```

これにより、ブランチの関係が視覚的に表示され、履歴が一目で分かりやすくなります。

---

## **🔚 まとめ**
Gitは奥が深く、適切に使いこなせば開発効率が飛躍的に向上します。本記事で紹介した10の裏技を活用し、よりスマートなバージョン管理を実践してください！

**💡 皆さんのおすすめのGitテクニックがあれば、ぜひコメントで教えてください！**
🚀 ChatGPT APIを活用した完全自動化ガイド【Python & Node.js】



## 🧠 はじめに

近年、LLM（大規模言語モデル）の進化により、APIを活用した業務自動化が急速に進んでいます。本記事では、ChatGPT API を使って、**フルオートメーション**を実現する方法を詳しく解説します。

Python と Node.js を用いた実装を中心に、API 連携やスクリプト自動化のテクニックを紹介し、実践的なノウハウを共有します。これを読めば、**単なるチャットボットを超えた生産性向上ツール** を構築できるでしょう！

---

## 📌 1. ChatGPT APIの基本理解

### 🎯 ChatGPT APIとは？
ChatGPT API は OpenAI が提供する **大規模言語モデルのインターフェース** です。開発者はこのAPIを活用し、**文章生成・要約・翻訳・コード補完など** 多岐にわたる用途で使用できます。

### 🏗️ APIキーの取得方法
まず、[OpenAIの公式サイト](https://platform.openai.com/) にアクセスし、APIキーを取得しましょう。

- **アカウント登録**
- **APIキーの発行**
- **無料枠の確認（使用上限あり）**

---

## 🏗️ 2. PythonでのChatGPT API活用

Python はデータ処理や自動化に適した言語です。ここでは **requests ライブラリ** を使った基本的なAPI連携を解説します。

### 🔧 必要なライブラリのインストール
```bash
pip install openai
```

### 📝 APIリクエストの基本コード
```python
import openai

openai.api_key = "your_api_key_here"

response = openai.ChatCompletion.create(
    model="gpt-4",
    messages=[{"role": "user", "content": "こんにちは、ChatGPT！"}]
)

print(response["choices"][0]["message"]["content"])
```
このスクリプトを実行すると、ChatGPT からの応答が表示されます。

---

## ⚡ 3. Node.jsでのChatGPT API活用

Node.js は非同期処理に優れ、**リアルタイムアプリケーション** に最適です。

### 📦 必要なライブラリのインストール
```bash
npm install openai axios
```

### 📝 APIリクエストの基本コード
```javascript
const { Configuration, OpenAIApi } = require("openai");
const config = new Configuration({ apiKey: "your_api_key_here" });
const openai = new OpenAIApi(config);

async function askGPT() {
    const response = await openai.createChatCompletion({
        model: "gpt-4",
        messages: [{ role: "user", content: "こんにちは、ChatGPT！" }],
    });
    console.log(response.data.choices[0].message.content);
}
askGPT();
```
このコードを実行すると、Python 同様に ChatGPT からのレスポンスが返ってきます。

---

## 🤖 4. ChatGPTを活用した自動化スクリプト

ChatGPT API を活用すると、以下のような自動化が可能です：

✅ **メールの自動返信システム**
✅ **カスタマーサポートチャットボット**
✅ **Slack/Twitterの自動投稿**
✅ **文章要約・翻訳の自動化**
✅ **レポートや記事の自動生成**

### 📩 例：メールの自動返信（Python）
```python
import openai
import smtplib

openai.api_key = "your_api_key_here"

# メール本文の生成
def generate_reply(email_content):
    response = openai.ChatCompletion.create(
        model="gpt-4",
        messages=[{"role": "user", "content": email_content}]
    )
    return response["choices"][0]["message"]["content"]

# メール送信処理
def send_email(to, subject, body):
    server = smtplib.SMTP("smtp.example.com", 587)
    server.starttls()
    server.login("your_email@example.com", "your_password")
    message = f"Subject: {subject}\n\n{body}"
    server.sendmail("your_email@example.com", to, message)
    server.quit()
```
このスクリプトを実行すると、受信したメールに対して ChatGPT が自動で返信を生成できます。

---

## 🏁 まとめ & 次のステップ

ChatGPT API を活用すれば、**業務効率化やタスクの自動化** を簡単に実現できます。本記事では Python & Node.js を使った API 連携方法と、応用的な自動化スクリプトの例を紹介しました。

次回の記事では、**「Gitの達人になるための10の秘伝コマンド」** を詳しく解説する予定です。お楽しみに！
SQLBoilerを採用するとすべてのテーブルで主キーを「ID」という名前に統一することはなぜ？


SQLBoilerはORMツールとして、一貫した規約を重視する傾向があります。すべてのテーブルで主キーを「ID」という名前に統一することは、以下の理由から一般的かつ妥当なアプローチと言えます：

### 主キーを「ID」に統一することのメリット

1. **一貫性と予測可能性**：
   - すべてのテーブルで同じ命名規則を使用することで、コードの予測可能性が高まります
   - 新しい開発者がプロジェクトに参加しても、主キーの命名規則を覚える必要がありません

2. **コード生成ツールとの相性**：
   - SQLBoilerのようなコード生成ツールは、このような規約に基づく一貫性を前提に設計されています
   - 命名規則が統一されていることで、自動生成されるコードも一貫したパターンになります

3. **業界標準との整合性**：
   - Ruby on Rails、Laravel、Django など多くの主要フレームワークでも、デフォルトで主キーに「id」を使用しています
   - 多くのORMツールもこの規約に従っています

4. **外部キー参照の単純化**：
   - 関連テーブルから参照する際、「user_id」のように「エンティティ名_id」という明確なパターンができます
   - これにより、どのテーブルを参照しているかが命名から明確になります

### 実際のデータベース設計における主キー命名の考え方

データベース設計において、主キーの命名には主に2つの学派があります：

1. **「ID」で統一する学派**：
   - ORMと相性が良く、一貫性があります
   - Webアプリケーション開発で最も一般的なアプローチです
   - SQLBoilerがこのアプローチを採用しています

2. **「テーブル名_id」または「テーブル名ID」で命名する学派**：
   - より自己説明的で、SQL文を読む際にどのテーブルの主キーか明確になります
   - 従来の関係データベース設計で好まれることがあります
   - 大規模なエンタープライズシステムでは、この方式が選ばれることもあります

### 結論

SQLBoilerで主キーをすべて「ID」に統一することは、標準的かつ一般的なアプローチです。特にGoのようなプログラミング言語のコンテキストでは、一貫性とシンプルさを重視する傾向があり、SQLBoilerはその考え方に沿っているといえます。

もし主キー命名を変更したい場合は、SQLBoiler自体を設定・カスタマイズするか、データベーススキーマを変更する必要がありますが、現在の設計は多くのプロジェクトで採用されている標準的なアプローチですので、特に問題はないと考えられます。
Git怖くないシリーズその3(全5回)：現実的なブランチ戦略

## ブランチ戦略とは
- Gitの特徴である分散とブランチを活用して、スムーズな並行開発と壊れにくリリースビルドを実現するための手法


----
## よく目にする戦略
- Git-Flow
- GitHub-Flow
- GitLab-Flow

----
## よく目にする戦略

・・・は複雑！！

----
## Gitによるソース管理の現実

- SIerに集まってくる技術者はGitに不慣れな場合も多い
- 意味のある名前付けにはセンスが必要
- 製造と保守が分かれていてブランチの意味合いが混じることが少ない

----
## 現実的なブランチ戦略(1/3)

- 最小限のブランチ種類
- 機械的なブランチ名
- チケットやタスク番号と確実に連動させたい

----
## 現実的なブランチ戦略(2/3)

- main：リリース対象のブランチ
  本番環境の最新と一致
  管理者しか触らない
- dev：開発完了した機能をすべて含む最新仕様の状態
  デプロイして実際に触れるようにしておくべき
  管理者しか触らない
- 開発ブランチ：各開発者がdevから派生して作成するブランチ


----
## 現実的なブランチ戦略(3/3)

1. 各開発者は開発を終えたらdevに対してマージを依頼
   出来ればスクオッシュしておきたい
1. 管理者は差分を確認しながらマージを実施
1. 可能なら、ここでテストを実行（NGになったらマージ依頼を差し戻し）
1. devにプッシュ、各開発者に周知
1. 各開発者はdevの最新状態をローカルに反映

----
## mainブランチをいつリリースするか

- リリース計画に従って実施
- devブランチをマージ
- リリースノートがあるなら、編集
- リリース実施
- devブランチにリリースノートの内容を反映
- リリースタグを切る　**←★重要★**

----
## 開発ブランチの名付け

```
<派生元ブランチ名>-<担当者名>-<チケットorタスク番号>
```

```
<派生元ブランチ名>-<チケットorタスク番号>-<担当者名>
```

- 管理者としては後者がありがたい。番号順に並んだほうが探しやすいので
- 作業に番号が振られている前提
  ITSかせめてタスク管理表を作成する必要あり

----
## 最後に
- いろんな戦略がありますが、シンプルなのがやっぱり強いです
- 要所でタグを切っておくのは非常に大事です