OmniAICreator/Qiita-1.07M huggingface dataset:
【rails】Deviseのパスワードリセット後の自動ログインに関するセキュリティ問題とその対策


## はじめに

こんにちは。アメリカ在住で独学エンジニアを目指している Taira です。
現在、Rails チュートリアルのアウトプットとしてアプリを製作しています。
devise を使用して認証機能をセットアップしているのですが、とても便利な一方、あまり理解もせずに利用しているとセキュリティ面でよくない挙動をするのではないのかと思い、備忘録として記事にしようと思いました。

## パスワードリセット後の遷移先

Rails の認証ライブラリである Devise を使用していると、ユーザーがパスワードを忘れた際に、パスワードをリセットして新しいパスワードを登録した後、**自動でログインされるという動作がデフォルトで設定されています**

この仕様はユーザー体験としては便利ですが、セキュリティの観点からは注意が必要です。

---

### 【問題点】

#### 1. トークンの漏洩による不正ログインのリスク

パスワードリセットリンクはメールで送信されます。そのリンクにはセキュリティトークンが含まれており、このトークンを使えば誰でも新しいパスワードを設定し、そのままログインできてしまいます。つまり、メールが第三者に見られてしまった場合、その人が不正にログインできるリスクがあります。

#### 2. 共用端末からのアクセスによる危険性

共用のパソコンや公衆 Wi-Fi などの安全でない環境でパスワードリセットを行った場合、パスワード設定後に自動でログインされると、端末に情報が残ってしまい第三者にアカウントを乗っ取られる危険があります。

---

### 【対策】

#### 自動ログインを無効化する

Devise では、パスワードリセット後の自動ログインを無効化することが可能です。具体的には、`Devise::PasswordsController`をカスタマイズして `after_resetting_password_path_for` メソッドをオーバーライドします。

```ruby
# app/controllers/users/passwords_controller.rb
class Users::PasswordsController < Devise::PasswordsController
  protected

  # パスワード変更後にログインせず、ログイン画面にリダイレクトする
  def after_resetting_password_path_for(resource)
    new_session_path(resource_name)
  end
end
```

ルーティングもカスタムコントローラーを指定するように修正します：

```ruby
# config/routes.rb
devise_for :users, controllers: {
  passwords: 'users/passwords'
}
```

これにより、ユーザーはパスワードリセット後に自動ログインされず、ログイン画面にリダイレクトされるようになります。

---

### 【まとめ】

パスワードリセット後の自動ログインは利便性の高い機能ですが、セキュリティリスクを伴います。特にトークンの漏洩や共用端末での利用時には不正ログインのリスクが高まります。

そのため、セキュリティを重視するアプリケーションでは自動ログインを無効にし、リセット後に改めてログインさせることで、安全性を高めることが推奨されます。
Spring for GraphQL TIPS〜部分更新したい〜

## はじめに

ブログを更新するAPIを想像してください。
あなたは、ブログの記事タイトルだけを更新したいとします。  
でもAPIの仕様によっては、タイトルだけじゃなく本文とかも全部送らないといけないことがありえます。
「変えたいのはタイトルだけなのに他のフィールドも送らなきゃなのはナンセンス」って考えたりしませんか？

また他にも新しいフィールドが追加されたときに生じる問題もあります。  
たとえば、予約投稿のために`scheduledPublishDate`というフィールドを追加したとします。  
古いクライアントはその存在を知らないので送ってきません。  
でもサーバーが「フィールドが送られてこなかった＝nullで更新」と解釈すると、  
意図せず`scheduledPublishDate`の値が消えるという事故が起きます。

これを防ぐには、「送られてきたフィールドだけを更新する」ための部分更新の仕組みが必要です。  
つまり、RESTでいうPATCH相当のことをGraphQLでもやりたい、という話です。

なお、[動くサンプルコード](https://github.com/kogayushi/spring-for-graphql-tips-by-small-startup)も用意しています。
## Spring for GraphQLでどうやるのか

GraphQLでは、更新対象外のフィールドをundefinedで表現する事が可能です。  
ここで重要なのは、サーバー側がundefinedを識別して、「undefinedのフィールドは変更しない」ように実装することです。


### `ArgumentValue` で`null`と`undefined`を区別する

Spring GraphQLの`ArgumentValue<T>`を使うことで実現できます。  
このクラスを使うことで以下の3つの状態を区別可能になります。

| 状態        | 説明            | 処理    |
|-----------|---------------|-------|
| undefined | リクエストに含まれていない | 更新対象外 |
| null      | 明示的に送られた      | 値を削除  |
| 値         | リクエストに含まれている  | 値を更新  |

このように分けて扱えるようにすることで、更新・削除・対象顔のフィールドを明示的に区別できます。

### Inputの定義

記事編集用のInputはこのようになります。

```kotlin
data class EditArticleInput(
    @field:NotNull
    val articleId: UUID?,

    val title: ArgumentValue<
        @NotBlank
        @Size(min = 3, max = 100)
        String
    >,

    val content: ArgumentValue<
        @NotBlank
        @Size(min = 10, max = 5000)
        String
    >,

    val scheduledPublishDate: ArgumentValue<LocalDateTime?>
) {
    val articleIdAsNotNull by lazy { articleId!! }
}
```

各フィールドを ArgumentValue<T> でラップすることで、「送られてきたか？」「nullか？」「値があるか？」を区別可能になります。


### Beanバリデーション

バリデーションもちゃんと効きます。
たとえば`@NotBlank`や`@Size`を`ArgumentValue`のジェネリクスの中に書いておけば、 値が送られてきたときだけバリデーションされるようになります。

undefinedのときはバリデーションはスキップされます。

## まとめ

`ArgumentValue`を使うと、Spring for GraphQLでも以下のことが実現できました。

- 更新したいフィールドだけ送る
- 送られてこなかったフィールド(undefined)はそのまま保持
- nullのときは削除する
Spring for GraphQL TIPS 〜肥大化するGraphQLスキーマへの対処〜

## はじめに

GraphQLのスキーマ定義は、プロダクトの成長に伴い、肥大化していくことは避けられません。  

ここでは、肥大化するスキーマ定義への工夫を2つ紹介します。

なお、[動くサンプルコード](https://github.com/kogayushi/spring-for-graphql-tips-by-small-startup)も用意しています。



## ファイル分割でスキーマを整理する
### なぜ分割するのか

1ファイルで管理するのはすぐに限界がきますが、分割することでノードごとに1つのファイルにグループ化できます。  
それにより更新対象のスキーマ定義ファイルを見つけやすくなります。

### どうやって分割するか

`resources/graphql`ディレクトリ以下に、ノードごとにスキーマ定義ファイルを分けます。

| ファイル名 | 説明 |
| --- | --- |
| schema.graphqls | 空のQuery, Mutation, Subscriptionだけ定義 |
| article.graphqls | 記事関連の定義 |
| comment.graphqls | コメント関連 |
| user.graphqls | ユーザー関連 |

それぞれ、`extend type Query`や`extend type Mutation`を使ってルート型を拡張しています。

たとえば、`article.graphqls`は以下のようになります。

```graphql
extend type Query {
  articles: [Article!]!
}

extend type Mutation {
  postArticle(input: ArticleInput!): Article!
  editArticle(input: EditArticleInput!): Article!
  likeArticle(input: LikeArticleInput!): Void
  unlikeArticle(input: UnlikeArticleInput!): Void
}

extend type Subscription {
  updatedArticles(articleIds: [ID!]!): Article!
}
```

Spring for GraphQLは、これらを全部読み込んで一つのスキーマとして統合してくれるので、このような分割が可能です。

## グラフ構造の全体像を把握できるように可視化する

スキーマが大きくなってくると、全体像が見えなくなってきます。  
「これとこれがどう繋がってるんだっけ？」みたいなことが起きがちです。  
そのため、スキーマを図にして可視化することを考えました。

手段はいろいろあると思いますが、今回はGraphQL Voyagerを使った例を紹介します。

### Voyagerの導入方法
| ファイル名 | 説明 |
| --- | --- |
| src/main/resources/templates/graphql-voyager.html | VoyagerのHTMLテンプレート |
| GraphQLVoyagerController.kt | `/graphql-voyager`にマッピングしてHTML返すコントローラー |

アクセスすると、テンプレート内のJSがGraphQLエンドポイントにイントロスペクションを投げて、 スキーマの構造がそのまま図として見えるようになります。ノードやフィールドをクリックしてたどれるので、構造の確認がかなりラクになります。

```javascript
// graphql-voyager.html の一部
const { voyagerIntrospectionQuery: query } = GraphQLVoyager;
const response = await fetch('http://localhost:8080/graphql', {
  method: 'post',
  headers: {
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ query }),
});
const introspection = await response.json();

GraphQLVoyager.renderVoyager(document.getElementById('voyager'), {
  introspection,
});
```

たったこれだけで可視化できます。  
サーバー上で動かす場合は、取得先のURLを適切に変更してください。

## まとめ

プロダクトの成長に伴い、スキーマが肥大化していくことはどうしても避けられません。  
ですので、肥大化したスキーマをどう扱いやすくするかを考えて対処するしかないでしょう。  
他にもいろいろな工夫があると思いますので、これ以外の方法についてご存知の方はぜひ教えてください。
プロデル、調査 その27

# 概要
プロデルが、CLRらしいので、調べて見た。
ｃ＃で、プラグインを作ってみた。

# 参考にしたページ

https://github.com/utopiat-ire/RdrWMPPlugin

https://produ.irelang.jp/docs/plugins/RdrWMP/wmpctrl.htm

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/cc7ec0c0-6e82-4dc3-be86-41532f3bc8f3.png)

# サンプルコード

```

「Produire.WMP.dll」を利用する
「Produire.WinControl.dll」を利用する

メイン画面を表示する
待機する

メイン画面とは
  	ウィンドウを継承する
  	はじめ手順
    		初期化する
    		WMPというWindowsMediaPlayer部品を作る
      			その位置と大きさは｛10，50，310，200｝
      			その位置固定方向は「右＋左＋下＋上」
    		WMPを初期化する
    			タイマー１というタイマーを作る
    			タイマー１の"間隔"は1000
  	終わり
	初期化する手順
  		この内部領域大きさは｛333，380｝
  		この内容は「Windows Media Player On プロデル」
  		このドラッグドロップは○
  		この位置と大きさは｛15，15，349，418｝
  		リストビュー1というリストビューを作る
    			その表示方法は「詳細」
    			その見出し一覧は｛「属性」，「値」｝
    			その見出し幅は｛99，184｝
    			その移動順は4
    			その位置と大きさは｛9，256，314，112｝
    			その位置固定方向は「右＋左＋下」
  		開くボタンというボタンを作る
    			その内容は「開く」
    			その移動順は3
    			その位置と大きさは｛96，9，83，27｝
  		ラベル1というラベルを作る
    			その内容は「00:00/00:00」
    			その移動順は2
    			その位置と大きさは｛12，16，63，12｝
	終わり
  	WMPのメディア情報が変更された時の手順
    		リストビュー１をすべて消す
    		WMPの現在メディアの属性一覧の見出しのすべての属性名について、それぞれ繰り返す
      			リストビュー１に、属性名を追加する
          		その詳細は｛(WMPの現在メディアから属性名という属性を取得したもの)｝
    		そして
  	終わり
  	WMPの再生位置が変更された時の手順
    		ラベル1の内容は「[WMPの再生位置情報] / [WMPの現在メディアの長さ情報]」
  	終わり
  	WMPの状態が変更された時の手順
    		WMPの再生状態が「再生中」なら
      			タイマー１を開始する
    		そうでなければ
      			タイマー１を停止する
    		そして
  	終わり
  	タイマー１が時間になった時の手順
    		ラベル1の内容は「[WMPの再生位置情報] / [WMPの現在メディアの長さ情報]」
  	終わり
  	開くボタンがクリックされた時の手順
    		開く画面のフォルダ名は、マイミュージック
    		開く画面のフィルタは「メディア|*.mpg;*.wmv;*.avi;*.mp3;*.wma;*.wav|すべてのファイル|*.*」
    		開く画面を表示する
    		開く画面のキャンセルなら、終了する
    		ファイル名は、開く画面のファイル名
    		WMPのアドレスは、ファイル名
    		曲情報を更新する
  	終わり
  	曲情報を、更新する手順
    		//ラベル1の内容は「[WMPの再生位置情報] / [WMPの現在メディアの長さ情報]」
  	終わり
終わり




```

以上。
Auroraレプリカの作成時　メニューに「Aurora レプリカ作成の項目」が表示されない場合の対処

                                                                            　　　2024/10/23
   # 【AWS Aurora】Aurora レプリカの作成メニューが表示されない場合の対処

## ❓ マネコンより操作すると

Amazon Aurora でクラスターを作成した後、  
**「アクション」メニューに 「Aurora レプリカ作成」の項目が表示されません。**

![Auloraレプリカ作成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3761697/cb51ff2d-9e9c-4c71-88e0-a68ee85caa04.png)



---

## ✅ 対処方法

Aurora クラスターにレプリカを追加したい場合は、  
**「リーダーの追加」** を選択する

これは Aurora におけるレプリカの追加操作に相当する。

---

## 📘 参考ドキュメント

[DB クラスターに Aurora レプリカを追加する – Amazon Aurora（公式）](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/aurora-replicas-adding.html)

---

## 📝 補足

- Aurora では「レプリカ追加」という表記ではなく「リーダーの追加」と表示される仕様です。
【太治奨揮】コードの先にある小さな幸せ

こんにちは、フリーランスのシステムエンジニア、太治奨揮です。

普段は技術や開発のTips、設計の考え方などを真面目に書くことが多いのですが、今回はちょっと趣向を変えて、**「仕事の中で見つけたこの人にしか気づけない喜び」**について書いてみたいと思います。

ソフトウェア開発はもちろん、論理的で効率的な作業が求められます。
でも、コードを書いているときやお客様とやりとりをしている中で、数字や仕様だけでは測れない**「人間らしい幸せ」を感じる瞬間がある**んですよね。

例えば、長い議論や試行錯誤を経て、クライアントの「これが欲しかった！」という反応をもらったとき。
ただの実装者として機能を届けるのではなく、「共に考え、共に育てた」成果物が相手のビジネスに生きるとわかった瞬間は、何ものにも代えがたい喜びです。

また、バグを見つけて修正した時のささやかな達成感も好きです。
技術的には小さな修正でも、チームやサービス全体の信頼感に繋がるという意味で、エンジニアとしての誇りを感じます。

僕が大切にしているのは、「スピード感と丁寧さの両立」。
忙しい中でも「丁寧に」クライアントと向き合うことで、単なる作業者ではなくパートナーとして認めてもらえることに喜びを感じます。

こうした喜びは、数字や納期、機能一覧には載りません。
でも、現場で泥臭く伴走するエンジニアだからこそ感じられる、小さなけれど確かな幸せです。

もしこの記事が、同じようにエンジニアとして働く方の共感や、仕事のモチベーションに少しでも繋がれば嬉しいです。

また、技術的な話も書きますので、そちらもぜひ読んでいただければ幸いです。
それではまた！
猿でもわかるAIプログラミングシリーズ 🐵💻  欠損値（NaN）の処理パターンを比較してみた



## 欠損値（NaN）の処理パターンを比較してみた【実務で使えるヒント付き】


### 🧩 1. はじめに：データが欠けているのは“当たり前”

現場でAIやデータ分析に関わっていると、**完璧なデータなんて存在しない**という現実にすぐ直面します。
例えば：

* センサーが通信エラーを起こして一部の値が消えていた
* アンケートで回答者が一部の質問をスキップした
* ログデータに一部のフィールドが記録されていなかった

このような\*\*「欠損値（NaN）」\*\*をどう扱うかは、モデルの精度にも、分析の正確性にも、業務上の判断にも大きな影響を与えます。

今回は、実務でよく使われる「欠損値処理パターン」を比較しながら、**どんなときに、どの方法を選べばよいか？** を整理してみましょう。

---

### 🔍 2. 欠損値処理の選択肢（ざっくり解説）

Pandasを使えば、欠損値の検出・処理は簡単にできますが、\*\*「どう処理するか」\*\*は目的に応じて選択が必要です。

主な処理パターンは以下の通りです：

| パターン                   | 説明                   | よく使う場面             |
| ---------------------- | -------------------- | ------------------ |
| ① 削除する                 | 欠損値を含む行や列を丸ごと削除      | 欠損がごく一部だけの場合       |
| ② 代入する（平均・中央値など）       | 欠損値を統計値で補完           | 数値データの簡易補完         |
| ③ 前後から埋める（ffill/bfill） | 時系列や連続データで前の値/後の値を使う | IoTやログなどの連続計測データ   |
| ④ モデルで予測補完             | 欠損値そのものを機械学習で予測      | 欠損が多くても予測精度を保ちたい場合 |

---

### 💻 3. 実践：各パターンをコードで比較してみよう！

#### データ準備

```python
import pandas as pd
import numpy as np

# サンプルデータ
data = {
    '温度': [23.5, 25.1, np.nan, 24.8, 25.0],
    '湿度': [45, np.nan, 47, 44, 46],
    '気圧': [1012, 1013, 1011, np.nan, 1010]
}
df = pd.DataFrame(data)
print(df)
```

出力例：

```
     温度    湿度     気圧
0  23.5  45.0  1012.0
1  25.1   NaN  1013.0
2   NaN  47.0  1011.0
3  24.8  44.0     NaN
4  25.0  46.0  1010.0
```

#### ① 欠損値のある行を削除（`dropna`）

```python
df_drop = df.dropna()
print(df_drop)
```

→ 欠損を含む行は**すべて削除**され、結果的に行数が減ってしまいます。
業務でデータ量が貴重なときには注意が必要です。

#### ② 平均値で補完（`fillna(df.mean())`）

```python
df_mean = df.fillna(df.mean(numeric_only=True))
print(df_mean)
```

→ 欠損を**列ごとの平均値で埋める**。簡単＆早いが、外れ値があると精度に悪影響。

#### ③ 前の値で埋める（`ffill`）

```python
df_ffill = df.fillna(method='ffill')
print(df_ffill)
```

→ 時系列に意味があるときに便利。ただし、**最初の行が欠損している場合には注意**。

#### ④ モデルで予測補完（KNNImputerを例に）

```python
from sklearn.impute import KNNImputer

imputer = KNNImputer(n_neighbors=2)
df_knn = pd.DataFrame(imputer.fit_transform(df), columns=df.columns)
print(df_knn)
```

→ 欠損を**他の列の値から類似性ベースで補完**する手法。計算コストは高めですが、精度は良好。

---

### 🧠 4. 実務Tips：気をつけるべきポイント

* `dropna()` を多用しない：データ損失が大きくなりやすい
* 外れ値に注意：`mean()`や`median()`補完は**事前に分布の確認**が重要
* 時系列なら`ffill`/`bfill`：ただし**ジャンプがあると危険**
* モデル補完は強力だが、**事前のスケーリング処理**が必要な場合も

---

### 🚀 5. 応用編：カスタムルールで埋めてみよう

現場では、**単純な平均や前方補完だけでは不十分**なケースも多いです。
例えば「特定の曜日にはセンサーが止まる」と分かっている場合は、そのルールに従って補完するのがベターです。

```python
# 例：特定インデックスだけ固定値で補完
df_custom = df.copy()
df_custom.loc[2, '温度'] = 24.5  # 実績値に基づいて埋めるなど
print(df_custom)
```

---

### 📌 6. まとめ：どの処理が正解かは「目的次第」

| 処理パターン              | 長所            | 短所          |
| ------------------- | ------------- | ----------- |
| dropna()            | 簡単、確実にNaNが消える | データロスが大きい   |
| fillna(mean/median) | 高速、実装が容易      | 外れ値の影響を受ける  |
| ffill/bfill         | 時系列に適している     | 初期値がNaNだと困る |
| モデル補完               | 高精度な補完が可能     | 実装・計算が複雑    |

---

## ✨ 今後の展望

近年では、欠損値補完も機械学習や深層学習で行う研究が進んでおり、例えば **AutoMLのパイプライン内に補完が自動組み込み**されるケースもあります。

しかし、\*\*「なぜ補完するのか？」「それが業務判断にどう影響するのか？」\*\*を意識することが、単なるコーディングを超えた“実務力”につながります。

---

この記事が、皆さんの実務や趣味のAI開発のヒントになれば嬉しいです。
次回は「AIで毎日のTODOリストを自動生成する方法」を予定しています。お楽しみに！

---

ご質問やフィードバックがあれば、コメント欄へお気軽にどうぞ🙌
フォローしていただけるとシリーズの続編も見逃しません！
JavaScript 非同期処理について

# `fetch()`
- ネットワーク越しにデータを取得するためのものです。
    - Webサイトからデータを取得したり、APIを使ってサーバーとやり取りしたりする際に使用されます。
- `fetch()` は非同期処理になっていて、**これが実行された時点でバックグラウンドで通信が開始される**という仕組みになっています。

:::note info
**非同期処理とは、「時間がかかるかもしれない処理」を、その完了を待たずにバックグラウンドで進めながら次の処理に進める仕組み**のことです。
:::

- そのバックグラウンドで行われる非同期処理が今どういう状態なのかは、`fetch()` の返り値で知ることができます。
    - 返り値ですが `Promise`と呼ばれる種類のオブジェクトで、非同期処理の状態に応じて値が変わる、特殊なオブジェクトになっています。

# `Promise`
`fetch()`を実行した時に、非同期処理が現在どのような状態なのかを表すオブジェクトです。
`Promise`はライフサイクルにおいて、以下のいずれかの状態にあります。

### `Pending` (保留中):
- 初期状態。非同期処理がまだ完了していない、またはまだ開始もされていない状態です。
- 注文した料理がまだ作られている途中。

### `Fulfilled` (解決済み):
- 非同期処理が成功して完了した状態です。結果の値（料理）が利用可能です。
- `Promise.prototype.then()` メソッドで登録されたコールバック関数が実行されます。
- 料理が完成し、受け取った状態。

### `Rejected` (拒否済み):
- 非同期処理が失敗して完了した状態です。エラー理由（材料切れ）が利用可能です。
- `Promise.prototype.catch()` または `Promise.prototype.then(null, onRejected)` で登録されたコールバック関数が実行されます。
- 料理が作れず、その理由を伝えられた状態。


# 非同期処理の書き方
非同期処理の書き方は、下記の2つがあります。
- `await`/ `async`を使う書き方
- `.then()`/`.catch()`を使う書き方

それぞれ見ていきましょう。

# `await`/ `async`
- `await`とは、「バックグラウンドで非同期処理を実行させ、その結果（戻り値）が返ってくるまで、`async`関数内のそれ以降のコードの実行を一時停止して待ってくれる」ものです。
    - 他のコードは走り続けることができるので、UIがフリーズしたり、Webページが応答しなくなったりするのを防ぎます。
- `Promise` が解決したら、`async`関数内のそれ以降のコードの実行を再開します。

## 基本構文
```JavaScript
const showUsers = async () => {
try {
    const response = await fetch(
      'URL'
    );
    const users = await response.json();
    console.log(users);
  } catch (err) {
    console.log('Error! ');
    console.log('Errorlog' + err);
  }
};
```
- `await`が使われている関数には、必ず先頭に`async`をつけます。
- **`await`での実行結果がエラーなく返ってきた場合、`response`として受け取ることができます。**
- `try`文で実行中、途中でエラーとなった場合は`catch`文の処理へとうつります。


# `.then()`/`.catch()`
```JavaScript
function showUsers() fetch('URL')
    .then((res) => {
      return res.json();
    })
    .then((users) => {
      console.log(users);
    })
    .catch((err) => {
      console.log('Error! ');
      console.log('Errorlog' + err);
    });
}
```
- 一つ目の`then`で`response`を受け取ります。うまく行った場合次の`then`に値を返します。
:::note info
値を渡すために`return`とする必要があります。
:::
- 二つ目の`then`で`response`結果を改めて受け取り、表示します。
- `catch()`で続けてかけば、エラーの場合の処理を定義することができます。

## なぜ `res.json()` を `return`して次の `.then()`に渡すのか？ 

こちらの疑問は、awaitでの`response.json();`になぜ`await`をつける必要があるのか？にも当てはまります。

### 1.`fetch()`が返す最初の`Promise`は「`HTTPレスポンス`」オブジェクト
- fetch('URL') が解決すると、まず`Response`オブジェクトが返されます。
- この`Response`オブジェクトには、HTTPステータスコード（例: 200 OK）、ヘッダーなどのメタデータが含まれますが、肝心の実際のデータ（JSONデータやテキストデータなど）はまだ読み込まれていません。

### 2.`res.json()`は「レスポンスボディの読み込みとパース」を非同期で行う
- `res.json()`というメソッドは、`Response`オブジェクトのボディ部分（中身のデータ）を読み込み、それをJSON形式として解析するための非同期処理です。
- この`res.json()`自体も、別の新しい Promise を返します。
- この新しい Promise は、「ボディの読み込みとJSON解析が完了したら解決する」という約束を持っています。

### 3.`Promise`チェーンのルール
- `.then()`の中で`Promise`を`return`すると、次の `.then()`はその返された`Promise`が解決されるまで「待機」します。
- そして、返された`Promise`が解決したとき、その解決値が次の`.then()`の引数として渡されます。
:::note info
既出になりますが`await`は、その結果（戻り値）が返ってくるまで、`async`関数内のそれ以降のコードの実行を一時停止して待ってくれる」ものなので順番に実行することができます。
:::
【Project Euler】#002

https://qiita.com/umekikazuya/items/7062d91ddb8db112ef84

2問目です。今日はフィボナッチ数列！
## 問題
> フィボナッチ数列の各新項は、前の2項を足すことによって生成される。1と2から始めると、最初の10項は1,2,3,5,8,13,21,34,55,89...となる。
> フィボナッチ数列の項のうち、値が400万を超えないものを考え、偶数の項の和を求めよ。

フィボナッチ数列を400万まで算出しつつ、偶数項のみ加算する、って感じですね。

https://projecteuler.net/problem=2

## わたしの回答
```go
func main() {
	fibonacciNumbers := []int{1, 1}
	result := 0
	sum := 0
	for sum < 4000000 {
		sum = fibonacciNumbers[len(fibonacciNumbers)-1] + fibonacciNumbers[len(fibonacciNumbers)-2]
		if sum%2 == 0 {
			result += sum
		}
		fibonacciNumbers = append(fibonacciNumbers, sum)
	}
	fmt.Println(result)
}
```

ループを回しながらフィボナッチ数列を生成しつつ、偶数項があった場合に「答え」用の変数に加算していく感じですね。

最初、配列を作るループの後に偶数を加算するループ回してたりしてました...。
**いわゆる O(n)...。**

## GPT-4oの回答
```go
func sumEvenFibonacci(limit int) int {
	prev, curr := 1, 2
	sum := 0

	for curr <= limit {
		if curr%2 == 0 {
			sum += curr
		}
		prev, curr = curr, prev+curr
	}

	return sum
}

func main() {
	const limit = 4000000
	result := sumEvenFibonacci(limit)
	fmt.Println(result)
}
```

## Gemini2.5 Flashの回答
```go
func main() {
	a, b := 1, 2
	sum := 0

	for a <= 4000000 {
		if a%2 == 0 {
			sum += a
		}
		a, b = b, a+b
	}

	// 結果を出力
	fmt.Println("フィボナッチ数列で400万を超えない偶数値の項の合計:", sum)
}
```
あー、GPTもGeminiも変数でやってるのか...。スライス不要ですね。
変数のほうが可読性いいし、メモリ効率もいいですよね...。

## 感想
Geminiのコード読みやすいな。
【Project Euler】#001

https://qiita.com/umekikazuya/items/7062d91ddb8db112ef84

1問目です！

## 問題
> 10以下の自然数のうち、3または5の倍数をすべて列挙すると、3、5、6、9となる。これらの倍数の合計は23である。  
> 1000以下の3または5の倍数の和を求めよ。

他媒体とかでも似たような問題、よく見ますね。

https://projecteuler.net/problem=1
## わたしの回答
```go
func main() {

	sum := 0
	for i := 0; i < 1000; i++ {
		if i%3 == 0 || i%5 == 0 {
			sum += i
		}
	}
	fmt.Println(sum)
}
```

## GPT-4oの回答
```go
func main() {
	sum := 0
	for i := 1; i < 1000; i++ {
		if i%3 == 0 || i%5 == 0 {
			sum += i
		}
	}
	fmt.Println(sum)
}
```

## Gemini2.5 Flashの回答
```go
func main() {
	sum := 0
	for i := 1; i < 1000; i++ {
		if i%3 == 0 || i%5 == 0 {
			sum += i
		}
	}
	fmt.Println(sum)
}
```

## 感想
どう解いたとしても、答え似てくるよなぁと思いました。

久々にAIのサジェストなしで書いたから、手が止まる感じが久々な感覚でした。
ちょっと頭のキレも弱ってる感じがしました...。

でもやってみると楽しいですね！同僚も巻き込んでいっしょにやれてるので楽しさ倍増です！！
RAGAS



```
import pandas as pd
from datasets import Dataset
from ragas.metrics import (
    faithfulness,
    answer_relevancy,
    context_precision,
    context_recall,
)
from ragas import evaluate

# ここでは chat_llm と embeddings の定義を省略していますが、
# 実際のコードでは適切に定義してください。
# from langchain_google_genai import ChatGoogleGenerativeAI
# from langchain_google_genai import GoogleGenerativeAIEmbeddings
# chat_llm = ChatGoogleGenerativeAI(model="gemini-1.5-flash", temperature=0)
# embeddings = GoogleGenerativeAIEmbeddings(model="text-embedding-004")

# 1. データをPandas DataFrameとして準備
data = {
    "question": [
        "ラーメンはどこの国発祥ですか？",
        "うどんの麺の特徴は？",
        "博多はどんなラーメンが多い？",
        "最近のラーメンの進化について教えてください"
    ],
    "answer": [
        "ラーメンは中国から発祥し、日本で独自の進化を遂げた麺料理です。",
        "うどんの麺の特徴は太くて柔らかいです。",
        "博多ではとんこつラーメンが多いです。",
        "最近はヘルシー志向やベジタリアン対応、地域ごとの特色を活かした新しいラーメンが登場し、多様性が拡大しています。"
    ],
    "contexts": [
        ["ラーメンは、中国から発祥し、日本で独自の進化を遂げた麺料理です。この料理は小麦粉から作られた細い麺と、鶏、豚、魚介など多様な材料から抽出されたスープ、そして様々な具材で構成されます。日本各地には地域ごとのラーメンスタイルが存在します。"],
        ["他の麺料理との比較では、麺の種類やスープ、具材に大きな違いが見られます。うどんは太くて柔らかい麺、そばはそば粉を使用した麺、パスタは小麦粉と卵で作られた麺で、それぞれ独自の食感と風味があります。"],
        ["日本各地には地域ごとに異なるラーメンスタイルが存在し、札幌の味噌ラーメン、博多のとんこつラーメン、東京の醤油ラーメンなどが特に有名です。"],
        ["最近はラーメンが多様な形で展開されています。地域ごとの特色を活かした新しいタイプのラーメンが登場することもあり、その多様性はさらに広がりを見せています。"]
    ],
    # RAGASのcontext_precisionが要求する 'reference' 列を追加
    "reference": [ # 'ground_truths' ではなく 'reference' を使用
        "中国",
        "太くて柔らかい",
        "とんこつラーメン",
        "ヘルシー志向のものやベジタリアン対応、地域ごとの特色活かしたものの登場によって多様性が拡大している"
    ]
}

df = pd.DataFrame(data)
df




# 2. Pandas DataFrame を datasets.Dataset に変換
ds = Dataset.from_pandas(df)
ds


# ============================================================
# GeminiAPIの場合
# ============================================================
import os
from dotenv import load_dotenv

# langchain_google_genaiから必要なクラスをインポート
from langchain_google_genai import ChatGoogleGenerativeAI
from langchain_google_genai import GoogleGenerativeAIEmbeddings

# .env ファイルから環境変数をロード
load_dotenv()

# Google API キーの取得
# 通常、API キーは GOOGLE_API_KEY 環境変数から自動的に読み込まれますが、
# 明示的に指定する場合は以下のようにします。
api_key = os.getenv("GOOGLE_API_KEY")

# Chat モデルの定義 (Gemini 1.5 Flash の場合)
chat_llm = ChatGoogleGenerativeAI(
    model="gemini-2.0-flash-lite",
    temperature=0,
    google_api_key=api_key # 必要であれば明示的に指定
)

embeddings = GoogleGenerativeAIEmbeddings(
    model="models/text-embedding-004", # ここを修正しました！
    google_api_key=api_key # 必要であれば明示的に指定
)



# ============================================================
# Ragusによる評価の実行
# ============================================================

from ragas import evaluate
from ragas.metrics import faithfulness, answer_relevancy, context_precision, context_recall
# content_precisionには、元データにreference列が必要になる


# context_precisionとcontext_recallはground_truthsとLLMが必要です
# metrics=[faithfulness, answer_relevancy], # LLMが必要な最低限の指標
metrics = [
    faithfulness,
    answer_relevancy,
    context_precision,
    context_recall,
    ]

result = evaluate(
	ds,
	metrics=metrics,
	llm=chat_llm,
	embeddings=embeddings
	)

# 結果の変換と表示
df_result = result.to_pandas()
df_result

```
【大嶋淑之】新潟で映像制作中のほっこり話

こんにちは、大嶋淑之です。
普段は映像制作やフリーランスの仕事術について書くことが多いですが、今日はちょっと一息つけるような、新潟での仕事中にあったほっこりエピソードをシェアします。

ある日のこと、企業のプロモーション動画を撮影するために、新潟の田園風景が広がる場所へ向かいました。
撮影スタッフは僕一人。準備をしながら周囲を見渡すと、近くの農家のおばあちゃんが畑仕事をしているのが見えました。

撮影を始めると、突然おばあちゃんが近づいてきて、「何してるの？」と声をかけてくれました。
普段はあまり他人に話しかけることがない地域の方が、自分の仕事に興味を持ってくれることが素直にうれしくて、自然と笑顔がこぼれました。

おばあちゃんは昔からこの土地で農業を営んでいて、季節の移ろいについて色々と教えてくれました。
「ここはね、春は特に空気が澄んでて映像映えするよ」と教えてもらったことが、その後の撮影にも活きました。

撮影の合間にお茶をいただきながら、昔話や地元の美味しいお米の話題で盛り上がり、仕事の緊張がふっと和らぎました。
こうした地域の人との交流が、映像制作の原動力になるんだなと改めて感じた瞬間です。

都会では味わえない、この距離感と温かさが新潟での仕事の醍醐味。
忙しい日常の中でも、こんなほっこりした時間があるからこそ、クリエイティブなアイデアも生まれてくるのだと思います。

これからも、映像を通じて新潟の魅力を伝えるだけでなく、地元の人との繋がりを大切にしながら仕事を続けていきたいと思います。
Project Euler 始めます。

「このAIが普及してる中で競プロ！？」って思う方いるかと思います。
（いわゆる、AtCoderやLeetCode的なやつ）

エンジニア系だけでも、コード生成・レビュー・全自動等、いろいろと普及していますよね。

私自身、AIに対して強い抵抗があるわけではないです。
（イベントに参加したり、個人開発でいろんなツール試したりと模索してます。むしろ積極的に使いたい派）

「業務の効率化」を実現できますし、精度も高いですよね。
AIで業界がさらに発展していくのはいいことだと思ってます。

## Project Eulerを始めようと思った経緯

**AIに思考力を奪われたくないですよね。**

僕自身、めんどくさかった単純作業や思考の整理、コードレビューで**めちゃくちゃ助けてもらえてる**んですが、**助けてもらうつもりだったのが、考えることまで放棄してませんか？人格乗っ取られてないでしょうか？**

思考力は鍛えてても損しないよなぁと思ったのが、始めてみようと思ったきっかけです。

あと、計算量やN+1の考慮が甘いなぁと感じ、弱点克服も兼ねて...。

## Project Euler
https://projecteuler.net/

思考力は鍛えてても損しないよなぁと思ったのが、始めてみようと思ったきっかけです。
※ 数字とか競プロに興味は全く無いです。

AtCoderやLeetcodeなどいくつか調べてみたんですが、海外で有名なProjectEulerを同僚に紹介してもらって、やってみようかなぁと思った次第です。

ぼく「正直言って得意です！！！」

ってわけじゃないんですが、弱点克服も踏まえてちょこちょこと取り組んでいけたらなぁと思ってます。

仕事前の15分, 20分の目覚ましにちょうどよさそう。

## ルール
- AIには頼らない。
  → **解き方知ったらやる意味なくなるから。**
- 考えてもわかんない問題は飛ばしてOK。🙆‍♂️
  → **向いてない問題に付き合ってるほど暇じゃないです。**
- 解き終わったら、GPT4oとGemini2.5にも解答してもらう。
  → AIの**合理的かつ無慈悲な解答**を見て、なにか得るものはあるはず。

※ 僕だけの独自ルールです。

## まとめ
次の記事くらいから解いたものをアウトプットしていけたらなぁと思ってます。
（学習記録も兼ねて）

No.10くらいまでは解きたい...。
2週間、隙間時間とかで細々とやれたらなぁって思ってる所です。
「AWS Organization」の組織の全ての機能を有効にするとは

                                                                                  2024/9/19

# 「Organizationの組織の全ての機能を有効にする」とは何を意味するのか？
　「サービス」全てを「信頼されたアクセス」として有効にすることなのか？

 どういう状態になっていることを、意味するのかわかりませんでした。


## 調査の結果

「Organizationの組織の全ての機能を有効にする」ことは、**サービスを全て有効化することを意味するわけではない**

---

## AWS Organizations における機能セット

AWS Organizations には、以下の 2 つの機能セットが存在する。

- **すべての機能**
- **一括請求（コンソリデーティッドビリング）**

**ここで「全ての機能を有効にする」とは、**機能セットを「一括請求」から「すべての機能」に変更する**ことを意味する** 

### 機能セットの違い

#### 一括請求（コンソリデーティッドビリング）

- メンバーアカウントの料金が、組織の管理アカウントに一括で請求される 「共有請求機能のみ」を提供。

#### すべての機能

- 共有請求機能に加え、管理アカウントからメンバーアカウントを詳細に制御する機能を利用可能。

具体的には以下のような機能が含まれます：

- **統合されたサービス
  各サービスにおいて、管理アカウント（または委任されたアカウント）から、組織内アカウントを集中管理・設定できる。

- **AWS Organizations のポリシー機能
  - サービスコントロールポリシー（SCP）：最大アクセス許可を制御  
  - タグポリシー：リソースにアタッチされたタグの標準化

---

## 注意点

- 一度「すべての機能」に変更すると、**「一括請求」には戻せない。**
【保存版】エンジニアでも"それっぽくなる"モダンデザインの超実践Tips

## はじめに

エンジニアやってるとよく聞く悩み：

* デザインは苦手
* 色が決まらない
* 余白が不安になる
* フォント選びが闇
* 結局「ダサい」と言われる

わかります。自分もそうでした。
でも、実は「ここだけ抑えれば8割マシになる」ポイントが存在します。

この記事では、**デザイン専門家じゃないエンジニアでも即実践できる**モダンUIのコツをまとめます。

CodePenでデザインが見られます。フレームワーク不使用なので、コピペで使っちゃってください。
https://codepen.io/mukai3/pen/RNPVZpL

---

## ① 余白は "不安な2倍" 取る

**エンジニアは余白をケチりがちです。**

* ボタンの内側パディング：上下16px、左右24px以上
* セクション間のマージン：最低32px
* コンテンツ上下余白：画面幅の5〜10%取ると安定

**迷ったら広めに。** 余白は「呼吸」です。

---

## ② 色は"3色ルール"で固定

* ベースカラー（背景・土台）
* アクセントカラー（ボタン・強調）
* テキストカラー（本文・説明）

具体例：

* ベース：#F9FAFB（薄グレー）
* アクセント：#3B82F6（ブルー）
* テキスト：#111827（ほぼ黒）

**「色数が多い＝オシャレ」ではありません。**

---

## ③ フォントは迷わず"2種まで"

* 見出し：`Inter` or `Noto Sans`
* 本文：同じフォントをサイズだけ変える

フォント選びは沼なので、迷ったらGoogle Fontsの上位人気から選べば外しません。

---

## ④ 影は"薄く、距離短く"

ドロップシャドウのおすすめ：

```css
box-shadow: 0px 4px 8px rgba(0,0,0,0.1);
```

**影は自己主張させない。"気づかれない存在感"が理想。**

---

## ⑤ 角丸は"均一に"

* ボタン・カード・モーダル：全て8px〜12pxで統一
* 中途半端にバラけると途端に素人感が出ます

```css
border-radius: 8px;
```

---

## ⑥ アイコンは"統一ライブラリ"に頼る

* `Heroicons`
* `Lucide`
* `Material Icons`

**アイコンを統一するだけで、プロ感3倍増し。**

---

## ⑦ 配色は"既製品パレット"を活用

* [Tailwind CSS Color Palette](https://tailwindcss.com/docs/customizing-colors)
* [Coolors](https://coolors.co/)
* [Adobe Color](https://color.adobe.com/ja/create)

自分で0から作るのはプロでも難しい。
既製の配色をそのまま使うのが賢い選択です。

---

## ⑧ モダン感は"行間"で作れる

* 行間（line-height）は1.5〜1.75倍推奨
* 行間を広げると一気に今っぽくなります

```css
line-height: 1.6;
```

---

## ⑨ レスポンシブは"幅600px"を基準に作る

* スマホでもPCでも破綻しにくい幅感
* カード幅も600px以内に抑えると安定感が出ます

---

## ⑩ 迷ったら"Tailwind UI"を丸パクリする

* [Tailwind UI](https://tailwindui.com/)
* [shadcn/ui](https://ui.shadcn.com/)

**デザインのプロが作ったものを真似るのが最短。**

---

## おわりに

デザインは「センス」ではなく「型」で7割は解決できます。
しかも、これらは全て **エンジニア的な再現性** を重視したコツです。

これからポートフォリオや個人開発を作る人の参考になれば嬉しいです！
Jamf Proで拠点ごとにプリンター設定ポリシーを配布してみた

# Jamfで拠点ごとにプリンター設定ポリシーを配布してみた

## 🦆 はじめに

こんにちは！情シスでデバイスの管理をしているぴぺと申します🦆  
今回は、**Jamfを使って拠点ごとに異なるプリンター設定を自動で配布する方法**について書いていきます！

拠点ごとに違うプリンターを使っていると、「ユーザーが自分で設定する」のってなかなか難しいですし、情シス側のサポートも大変ですよね。  
そこで、**Jamfのネットワークセグメント機能とポリシー機能を組み合わせて、自動配布できる仕組み**を作ってみました。

---

## 💡 背景と課題

- 各拠点で異なるプリンター（IPアドレスベース）を使っている  
- ユーザーが自分で設定するのは手間＆ミスが多い  
- 情シスメンバーはリモートワークしているので、できれば現地に行かずに遠隔で対応したい
- Self Serviceからワンクリックでプリンタをインストールできるようにしたい
- 所属していない拠点のプリンタ設定は表示されないようにしたい

---

## ⚙️ 実施したこと

### 1. ネットワークセグメントを拠点ごとに設定

例：

- **Office A**：192.168.0.1〜254  
- **Office B**：192.168.1.1〜254  

> ※ Jamf Proの「ネットワーク」 > 「ネットワークセグメント」から追加します

---

### 2. プリンターをJamfに登録 & ポリシー作成準備

まず最初に、Jamfの管理画面でプリンターを登録しておく必要があります🖨️  
以下の手順で、プリンター情報を事前に入力しておきましょう。

**手順：**

1. `設定 > コンピュータ管理 > プリンタ` に移動  
2. 「＋ 新規」ボタンをクリック 
3. 以下を入力：
   - **表示名（Display Name）**：例）OfficeA_VendorName_model  
   - **URI**：例）ipp://192.168.0.1  
   - **PPDファイルへのパス**：/Library/Printers/PPDs/Contents/Resources/ファイル名.ppd
   - 事前にメーカーの公式ページからPPDファイルを入手しておきましょう。

これで登録が完了したら、ポリシーを作成します！

> 🛠 メーカーによってはインストール用スクリプトを作成する必要がありますが、
> 今回は割愛します。
> この記事では、ポリシー作成の流れをざっくりご紹介します。

- 「ポリシー」>「新規」で新規ポリシーを作成  
- 「プリンタ」を選んで、先ほど登録したプリンターを選択
- 「Self Service でポリシーを使用可能にする」にチェックを入れておく


---

### 3. スコープでネットワークセグメントを指定

- 「Scope」>「制限」  
- それぞれの拠点に対応するセグメントを選択

これで、「該当拠点のネットワークにいるときだけプリンターポリシーが配布される」ようになります！
別拠点のネットワークに接続している場合はポリシーが表示されないので、ユーザーが迷わず自分の拠点用プリンタだけ選べるようになります。

---

## 🧠 運用してみてわかったこと

- セグメントの設定ミスで配布されないことがある → **IPレンジをしっかり確認**🦆  
- 一部プリンターメーカーはPPDやドライバ準備が手間 → **事前に準備しておくと◎**

---

## ✅ まとめ

Jamfのネットワークセグメント＋ポリシー機能を活用することで、

- 拠点ごとのプリンター自動配布が可能
- ユーザー側での手間やミスが激減🙆  
- 情シス側も **“リモート対応だけで完結”** できる！

地味だけど便利な設定なので、ぜひ活用してみてください🐤

---

## 🐤 最後に

「うちではこうやってるよ〜」「もっと効率いい方法あるよ！」というフィードバック大歓迎です🦆  
コメントもらえると、とっても励みになります！
どうしても人間と認めてもらえなかった話

昨日は何度やってもうまくいかなかった話をアップします。
office365を使っていた機体ですが、共有機にするため、購入時にインストールされていたOffice2021をダウンロードしてインストールする際になかなかうまくいかなかったエピソードです。

１）まずダウンロードサイトアクセス
https://setup.office.com/?ms.officeurl=setup
２）新たにダウンロード用のアカウント作成のためメールアドレス作成→次へ
３）国の選択→日本
４）生年月日の選択
５）姓名を入力

ここで問題のページに遷移

<img width="250" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/960935/993d2ebb-9e68-4ce2-8198-31263f0f17ed.png">


次に長押しボタンがでます。

<img width="250" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/960935/f86f60c1-fd1b-4735-a725-f2070dd5e937.png">


ここで画面の指示通り、長押しと書いたボタンを指示通り長押しクリックしますが

<img width="250" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/960935/951f448c-eba8-4be4-bd66-7840ccdb0084.png">


NoSuchKeyThe specified key does not exist.No such object:public-sensor-pages/msft/px/captcha_close
（日本語訳）
そんなキーはありません。指定されたキーは存在しません。そのようなオブジェクトはありません。パブリックセンサーページ/msft/px/キャプチャを閉じる。

でも今朝行ったら、
まず昨日とは違って、パズルを解くというのがでて、
<img width="250" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/960935/f6fc5e8e-0cfe-4251-94d5-81dd0561078e.png">

上記をキャンセルすると
<img width="250" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/960935/6e982440-f29d-48a6-ac0d-ec501259a4b6.png">

長押しボタンが出てきますが、昨日と違ってボタン前に人マークのアイコンがあります。

長押し中
<img width="250" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/960935/7636bca9-2f1a-4394-b116-0faca4607894.png">

<img width="250" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/960935/12a19789-6b6c-4f0d-94ca-74030d80fe32.png">

パスキーの作成Windowに移って
<img width="250" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/960935/fa6efa0d-b7ac-45ee-9e0b-4383599ccb37.png">

きちんとプロダクトキー入力画面にになり、
OFfice２０２１をダウンロード＆インストールとなりました。

昨日は何だったんだろう？
Functor fmapの解説と、具体例いろいろ

まずは Functor, fmap の構文を確認しておこう。

```haskell
class Functor f where
    fmap :: (a -> b) -> f a -> f b
```

https://hackage.haskell.org/package/base-4.21.0.0/docs/Data-Functor.html

この構文から分かることは、

* Functor は型クラスである
* fmap は Functor 型クラスのメソッドである
* Functor はデフォルト実装を提供していない

ということ。

もう少しよく見ると、

* fmap の型 (a -> b) -> f a -> f b から、f は型コンストラクタである必要がある（例：Maybe や [] など）
    * つまり、f は「型を1つ取って新しい型を作る関数」のようなもの
* fmap は「通常の関数 a -> b を、f の文脈の中に持ち込む」ことができる、いわば「関数の持ち上げ（lifting）」を行う
* f の中身には手を触れず、構造だけを保ったまま、要素に対して関数を適用する

ことが分かる。

# 具体例いろいろ

```haskell
ghci> fmap (+2) [1, 3, 9] -- これは完全に普通の map と同じ
[3,5,11]
ghci> map (+2) [1, 3, 9]
[3,5,11]

-- f に Maybe 型を取る例
ghci> fmap (+2) (Just 3) 
Just 5
ghci> fmap (+2) (Nothing)
Nothing

-- (Int -> String) -> Maybe Int -> Maybe String
ghci> fmap show (Just 123) 
Just "123"

-- (Int -> Bool) -> [Int] -> [Bool]
ghci> map even [1, 2, 3, 4] 
[False,True,False,True]

-- (Int -> Bool) -> Either a Int -> Either a Bool
ghci> fmap (> 0) (Right 3) 
Right True

-- Left は関数が適用されない
ghci> fmap (> 0) (Left "error") 
Left "error"
```
スタバから自宅Ubuntu環境に接続〜自宅サーバへの第一歩〜

ずっと前にLinuxの勉強がしたく、古いPCにUbuntuを入れたことがあった。
それからずっと放置していたのだが何となくもっとないなと感じて、それを使って活用させたいな思った。
Neovimに触れてみようかなと思ったのでそれ用に使おうかと思った。
⇨本体はファンの音がうるさいし、ノートPCとしては重い（物理的）しバッテリーがもうだめで電源付けっぱじゃないアカン。
なので
- 目指すのは外出先のMacbookから自宅のUbuntuちゃんにアクセスできること
- VPNに関してはTailsclaeが手取り早そうだったのでそれを使うことに決めた

下記にざっくりまとめた。テキトーに。

# ☁️ やりたいこと

- 自宅Ubuntuをサーバー化
- 家の固定IPを設定
- ホームルーター(home 5G)でポート開放なし
- 外出先からssh & vim

---

## ステップ①: ローカルIPを固定する

### 1. ルーター側でDHCP固定

- ホームルーターの管理画面で
  - 接続元のMACアドレスを指定
  - IPアドレスを `192.168.xxx.xxx` などに固定

### 2. Ubuntu側はDHCPのまま (NetworkManager使用)

- GUI編集:（CLIよりGUIが分かりやすい！のである）
  - ネットワーク > IPv4 > 手動 > IP、ゲートウェイ、DNS設定

※ip aとかpingで確認もするよ！！

---

## ステップ②: SSHログインを有効に

```bash
sudo apt update
sudo apt install openssh-server
sudo systemctl enable ssh
sudo systemctl start ssh
```

同じネットワーク内PCから:
```bash
ssh tanamaru@192.168.xxx.xxx
```
---

:sunny:これでお家ではもうできるね！！！


## ステップ③: Tailscale でVPN置換

### Ubuntu側:
```bash
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
```

- Googleアカウントでログイン
- `tailscale ip` で `100.x.x.x`が付与

### Mac側:
- https://tailscale.com/download からDL
- ログイン > 拡張機能を許可

---

## ステップ④: SSHで自宅Ubuntuへ接続

```bash
ssh tanamaru@100.x.x.x
```

- `tanmaru` = Ubuntu側のユーザー名
- 初回は `yes` やパスワード入力が必要

---

## これでVimに外からでも触れられる
気分が向いたらガッツリ触ります



## 振り返り

Devboxでもよかったかもしれんが、料理と同じであまり物を活用させたかったのです
時間に余裕ができたらProxmoxで自宅サーバでも立てようかなと思ってるのでその入門としても勉強になったかな。たぶんね。
Gitでファイルの変更履歴を確認する方法まとめ

# はじめに
不具合の修正をしていて、あれ？直っているけど、いつ直ったんだろうとか思った時に調べたいことがあると思います。
その時に使える方法をまとめたいと思います。

# ファイルのコミット履歴を確認する

:::note info
ファイルのパスは指定は、VS Codeの場合、対象のファイルを右クリックして、相対パスのコピーを行い、ペーストすると楽です。
:::

### コミット履歴だけ確認
```
git log src/sample.js
```

:::note info
履歴が長い場合、Enterを押すと次の行が表示されます。qを入力してEnterを押すと終了します。（他のコマンドも同様です）
:::

### コミット履歴と内容を確認

```
git log -p src/sample.js
```

### 編集した人を指定する
```
git log --author user -p src/sample.js
```

# ファイルの行ごとの変更履歴を確認する 

git blameというコマンドで行ごとの変更履歴が確認できます。
ここらへんの行の変更が不具合の原因っぽいなーって時に、行数指定で絞り込み、使うことが多いです。
### ファイル全行
```
git blame src/sample.js
```

### 行数指定
```
git blame -L 4,6 src/sample.js
```


# コミットからどのPRを確認する
対象のコミットが確認できたら、コミットハッシュ値を確認します。
`commit 1123x912x300a0490c84ed58k2123307d0ae0fea`という部分です。

GUIだとPull requestsのフィルターにペーストして検索すれば、そのコミットを含んだPRがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475427/96b908fd-2c48-409c-8908-4d80fd5bd58c.png)


CUIを使いたい場合は、以下の方法で確認できそうです。

https://zenn.dev/yukyan/articles/5b22413773bf9a
SourceTreeでunityプロジェクトを管理する方法

### 必要なもの
- GitHub
- unityプロジェクト
- SourceTree
### 手順1:GitHubでリポジトリを作成
![スクリーンショット (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3943148/3a3a775c-4aec-48e4-9cd0-42f27fe7a5f0.png)
Add ignoreでgithubを選択してください(リポジトリに移さなくても大丈夫なファイルが除外されます。)
### 手順2:CodeからリポジトリのURLをコピー
![スクリーンショット (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3943148/95830d9a-8961-4d08-93be-a614e8325127.png)
### 手順3:SourceTreeを開いてClone
![スクリーンショット (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3943148/24be06c4-1792-4ce9-9dd7-2e87104cf004.png)
上の参照は手順2でコピーしたコード、下の参照はローカルに新規ディレクトリを作成してそれを参照
### 手順4:新規ディレクトリにgitファイルとgitignoreが作成されていることを確認
![スクリーンショット (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3943148/d1a3b145-67e8-4eae-8858-5d1b55b6971d.png)
gitファイルは隠しファイルになっていることがあるので注意。
### 手順5:管理したいunityプロジェクトの内容をクローン下ファイルに移す
![スクリーンショット (7).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3943148/afb75f0d-66a7-48d5-942d-5b90807f7107.png)
ドラッグ&ドロップかCtrl+c ctrl+vで移す。
### 手順6:ファーストコミットとリモートにプッシュ
![スクリーンショット (8).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3943148/6596bed8-b7cc-41a0-91e4-1e3f6b23b97b.png)
![スクリーンショット (9).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3943148/ae780dd5-acd7-459e-8564-ac9f6b5a5db0.png)
### 手順7:リモートで保管できていることを確認
![スクリーンショット (10).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3943148/0272a03e-777a-4bb3-93e7-c458f2d98bfa.png)
### 以上
『テストの7つの原則』 〜 パート③ 〜

## はじめに

現在、アプリ開発者としてプロダクトの持続的な成長や

ユーザーへのコミットに寄与するためにも、

SDLC全体を見渡して開発をすること、

および、それにはテストに関する体系的な知識が必要だと考え、

それを効率良く学べるJSTQB Foundation Levelの資格試験の勉強をしており、

そこでのインプットを記事にしたいと思います。
<br>

今回はその中でも「テストの7つの原則」の一部について

記事にしたいと思います。
<br>

なお今回は

#### 早期テストで時間とコストを節約

<br>
こちらの原則について記事にしてみようと思います。

## 早期テストで時間とコストの節約とは

開発をしているとこんなシーンに遭遇することがあります。
<br>

『また出戻りだよ。。。』

『それ、聞いてないよ。。。』

『えっ、これが欲しいんじゃないの。。。』

『うわっ、リグレすごい。。。』

『デグレした、あちこちバグだらけ。。。』

『もー、ちゃんとしてよ。。。』

『もー、こんなん嫌や。。。』

etc...
<br>

こう言うのって付き物なのでしょうが、

やはり極力避けたいですよね😅
<br>

『何事も早め早めに』

『備えあれば憂いなし』

<br>
この考え方ってテストにおいても有効なのではないでしょうか。

シラバスではレビューも含めて[^1]
<br>

『**レビューもテスト(静的テスト)の一部**』

<br>
として紹介されていますが、

要求分析・要件定義と言ったいわゆる上流フェーズからきちんとテストをしていれば、

防げた問題も有りそうよね🤔
<br>

あの時のきっちりかっちりみっちりなやり取りが、

結果としては後々の要らぬ苦労を無くすことができて、

ステークホルダーみんながwin-winになるので、

開発においては早い段階から様々なテストを入れておきたいところですね。。。
<br>

または、早めにレビューを受けておく、ないしはそれを行うことで、

みんなの認識の不一致を早めに見つけて修正を行うこともできるので、

結果としてより良い結果になりやすいと言ったこともあるかとは思います。
<br>

『ただとはいえ現実は...』
<br>

と言ったこともありますよね😅

多分このあたりのコントロール方法についてや、

コンテキスト特有の問題もあるかと思われますので、

それは別のメスの入れ方が求められているのかも知れません。。。

## 参照

https://jstqb.jp/syllabus.html

https://book.impress.co.jp/books/1124101026

[^1]:ここでのレビューはコードレビュー以外にも要求分析、要件定義、ユーザーストーリー作成といったフェーズで作成される成果物に対するレビュー（これで本当にいいんだっけ？）や、仕様書に対するレビュー、設計に対するレビュー、テストに対するレビューなどの様々な意味を持ちます。
Zustand / React Query を組み合わせた状態管理設計Tips【実務で失敗しないパターン整理】

## はじめに
フロントエンド案件が複雑化する中で、状態管理は設計の成否を大きく左右します。特に受託開発やSaaS開発では「状態管理が破綻して炎上する」ケースがよく発生します。

この記事では、実務で安定するパターンとして最近採用事例が増えている **「Zustand × React Query構成」** の使い分けと設計方針を整理します。

---

## 想定読者

* 状態管理設計で悩んでいる方
* Redux疲れしてきた方
* Next.js＋TypeScriptで実務案件を進めたい方

---

## 状態管理の責任範囲を切り分ける思想

```bash
React Query：APIから取得するサーバー状態（Remote State）
Zustand：ローカル状態（UI状態 / フラグ / 一時保存）
```

この分離が安定設計のコツです。

* **永続データ（DB依存）** → React Query
* **一時的なUI状態** → Zustand
* **認証トークンやセッション管理** → Zustand

---

## React Query の実務ポイント

### ✅ API呼び出しの型安全設計

```typescript
import { useQuery } from '@tanstack/react-query';
import { api } from '@/libs/fetcher';

interface User {
  id: number;
  name: string;
}

const { data, isLoading, error } = useQuery(['user', id], () => api<User>(`/api/users/${id}`));
```

* `queryKey` 設計を一貫させる
* エラーハンドリングは `errorBoundary` 併用
* `staleTime` / `cacheTime` で無駄リクエスト抑制

### ✅ 無限スクロール対応も標準機能で安定

```typescript
import { useInfiniteQuery } from '@tanstack/react-query';

const { data, fetchNextPage } = useInfiniteQuery(
  ['users'],
  fetchUsers,
  {
    getNextPageParam: (lastPage) => lastPage.nextCursor,
  }
);
```

---

## Zustand の実務ポイント

### ✅ グローバルUI状態の整理に最適

```typescript
import create from 'zustand';

type UiState = {
  isSidebarOpen: boolean;
  toggleSidebar: () => void;
};

export const useUiStore = create<UiState>((set) => ({
  isSidebarOpen: false,
  toggleSidebar: () => set((state) => ({ isSidebarOpen: !state.isSidebarOpen })),
}));
```

### ✅ Session / Auth情報もZustand管理が楽

```typescript
type AuthState = {
  token: string | null;
  setToken: (token: string) => void;
};

export const useAuthStore = create<AuthState>((set) => ({
  token: null,
  setToken: (token) => set({ token }),
}));
```

* CookieやStorageと併用することも多い
* Provider不要で手軽に使えるのが強み

---

## よくある失敗パターンと回避策

### ❌ なんでもZustandに突っ込む

* API取得結果を全部Zustandに置く
* キャッシュ無管理 → N+1地獄に

👉 **サーバー状態はReact Queryに任せる**

### ❌ ZustandにAPI呼び出し責務を混ぜる

* 副作用処理をZustand内部に持たせすぎる

👉 **API呼び出しは別のサービス層に分離**

### ❌ キャッシュ無効化を意識しない

* UI再描画のたびに無限リクエスト

👉 **staleTime / invalidateQueriesの適切運用**

---

## 設計分離イメージまとめ

| 状態          | 管理先             |
| ----------- | --------------- |
| API取得データ    | React Query     |
| ローディング・エラー  | React Query     |
| UI開閉・モーダル表示 | Zustand         |
| 認証情報        | Zustand         |
| フォーム入力中データ  | Zustand（ケースにより） |

---

## 状態管理設計のコア思想まとめ

* **サーバー状態はReact Queryに任せる**
* **ローカルUI状態はZustandでシンプルに管理**
* **責任範囲を分離すると保守が爆速化する**
* **再利用性・テスト性・拡張性が自然に上がる**

---

## おわりに

状態管理は「適材適所の選定」が9割です。
Zustand×React Query構成は今後ますます実務案件の主流になっていきます。

Qiitaでは今後もこういった**実務設計に刺さる構成Tips**を発信していきますので、ぜひLGTM・フォローお願いします！

---

## 関連タグ

状態管理, Zustand, ReactQuery, TypeScript, Next.js, API連携, SaaS設計, フロントエンド設計, フロントエンド案件, 受託開発
【自己紹介のススメ】自分の名前を布教することによるメリット【爪痕を残せ】

# ごあいさつ
初の投稿となるのでごあいさつ。
しいたけと申します。
一応開発経験として、高校1年～大学2年までUnity(C#)でゲームを制作。
後は特に何もしておらず、2～3年のブランクを抱えて入社。
思い出すことと新たな知識のキャッチアップに奔走する毎日。
…という感じ。

# この記事を書く目的
**新卒応援**のタグを付けさせていただいた。
もしかしたら就活生や弊社の内定をお持ちの方々が、このブログを見に来るかもしれない。
そのような方々のお役に少しでも立てるようにと思い、拙い文章ではあるが、投稿をさせていただく。

# 研修期間中に心掛けたこと
### 自分の名前を覚えてほしい
自分は人に**話しかける**ことが苦手。
これはつまり「会話の中で自分の名前を覚えてもらうことの難易度が極限まで高い」ということ。
そしてさらなる事実。
### 弊社、同期100人超え
自分の苦手なことを100回以上するのはもはや不可能。

ニンジンが嫌いな子どもに、ニンジンを100本食べさせても、ニンジンを好きになるわけがないのである。

ではどうすればよいのか。私が出した結論は**一網打尽**である。

# 実践したこと
弊社の研修は、終業30分前に全体の前で今日学んだ事などを発表する場面がある。その際、最初に必ず
「お疲れ様です。○○（自分の名前）です。」
と言うのである。
100人以上の前で自分の名前を名乗れば、それを布教できるスピードは爆速である。
GW中にそれを発見し、GW明けから私は実践することにした。

# 工夫したこと
覚えてもらうなら、覚えやすく。
**DiSC**という人間の行動特性を4つ（D, i, S, C）に分けるものがあり、その研修を行った。
そして偶然にも私の名前の一部にそのアルファベットが含まれていたのである。
（例えば相沢さんの場合、DiSCが i のような感じ）
それを利用し、100人の前で発表した結果、
### 自分の名前の布教に成功したのである。

# メリット
**知名度爆増**
**明らかに声を掛けられる回数が増える**
**自己紹介をしたときに、「ああ！あの○○さんね！」と言われる**
この3点に尽きる。
研修を運営している先輩社員によると「噂はかねがね聞いております」ということが実際に起こるらしい。
**自分の名前を売っておくことは圧倒的に得なのである。**

# 最後に
爪痕は残しておいた方が良い。そしてそれは当然良い印象となるものに限る。爪弾きにされることのないように。
【JAWS-UG初心者支部】AWS BuilderCards体験！！

# AWS BuilderCards体験会に参加！！
2025年6月3日、JAWS-UG初心者支部がConnpassで募集していた  
[AWS BuilderCards体験会](https://jawsug-bgnr.connpass.com/event/355198/) に参加してきたので、その体験談です。

AWS BuilderCardsは、AWSのサービスでアーキテクチャ構成し、よりWell-Architectedな構成を作ることでポイントを多く獲得した人が勝者となる"カードゲーム"です。

特徴的なのは、**毎ターンアーキテクチャを考えてビルドする**というゲームシステム。  
ゲームとはいえ、その都度「どのような構成にするのか」を考え直す必要があり、AWSリソースの学習として非常に有意義な体験でした。

## チーム編成の工夫が絶妙だった

JAWS-UG初心者支部での体験会に参加して、AWS BuilderCardsのプレイに関して冒頭で共有されたのが、

> 「分からないことは自由に質問していい」  
> 「サービスについてはその場でネット検索してOK」

という姿勢でした。

AWSのサービスは数も多く、すべてを把握している人は少ないと思います。 
その前提を明確にしてもらえたことで、初心者の方も安心して参加でき、経験者にとっても“説明する力”や“対話力”が試される場になっていました。

参加者は「初心者枠」「一般参加枠」「猛者枠」に分かれており、バランスよくチームが組まれていました。

猛者枠はゲームプレイヤーとしてではなく指導的な立場としてチームに入っていましたが、一方的に教えるのではなく、**ファシリテーターのように支えるスタンス**で場を整えていて、初心者枠の方も積極的に発言・質問しているのが印象的でした。

私自身はルールを聞いたことがあるだけで、実際のプレイはしたことがありませんでした。一般参加枠として参加しましたが、

- 「このサービスってどう使うんですか？」  
- 「この組み合わせってできますか？」

といった質問を猛者に気軽に投げかけることができ、非常に学びのある空気感だと感じました。  

知識量に関係なく、**全員で学び合えるグループ編成**がとても良かったです。

## 勝ち負けではなく「説明と対話」が主役

AWS BuilderCardsはゲーム形式ではあるものの、勝ち負けより重要なのは、

- **この構成が可能であること説明できるか**  
- **他者の意見を取り入れて構成を見直せるか**

といった、構成に対する責任感と柔軟性です。

オンプレ・クラウドを問わず、「構成を語れるかどうか」が設計において本質的に重要だと再確認しました。

また、AWS Builder Cardsでは、業務ではあまり使わないAWSサービスも多数登場します。  
そのたびに「これなんだっけ？」と調べたり、「どんな時に使うの？」とチームで話し合ったりする中で、**自然と知識が広がっていく感覚**がありました。

ゲームとして楽しいだけでなく、**実用的な学びが随所にある**のが非常に魅力的でした。

## ゲームプレイ感想

私を含めてグループはAWS BuilderCards初めての人ばかりでしたので、ルールについては習うより慣れろでやっていくうちに覚えることができました。

よりWell-Architectedな構成にするため、自分の山札にAWSリソースのカードを増やしていくのですが、自分の山札に既にあるカードを記憶してくのが大変でした。
最初の段階でどんな構成を作るつもりかあらかじめイメージしていないと効率よくポイントを取得できないなと感じました。

その他のカードゲームでもそうですが、**カードをドローする効果は強かった**です。
最初の山札はオンプレミスカードしかないのですが、AWSリソースのカードを増やすと構成の幅が広がったり、オンプレミスカードをリタイアさせたりできるので、序盤で優先的に取ったほうが良い？と思いました。

体験会の中で１プレイが終わるところまではできませんでしたが、慣れれば手際よくできそうでした！！

※ゲームルールの詳細は公式ルールやその他の記事を見てみてください🙏

## 自分の職場でもやってみたい！

今回の体験で、「これは社内でもぜひ実施したい」という思いが強まりました。

初心者〜経験者まで一緒に楽しみながら学べて、  設計思考だけでなく、**対話力・説明力**も鍛えられるAWS Builder Cards！単なる研修では得られない学びが詰まっています。

## さらにうれしいサプライズも！

また、今回の体験会では、**AWS Builder Cardsのカードセットを1人1セットプレゼントしていただけました！**

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762239/574ba388-91e3-43e3-b225-0846387eb3fb.jpeg width=400 style="text-align: center;">


事前には特に案内がなかったので、参加者の多くが驚きつつも喜んでいたように思います。  
私自身も「まさかもらえるとは…」とちょっとテンションが上がりました。

なかなか手に入らない日本語版BuilderCardsなので、イベントの内容を後から振り返ったり、社内でもAWS BuilderCardsでワークショップを実施してみたりと、活用の幅が広がります。

あくまで今回の体験会ではという話ですが、**実物のカードを通じて"構成を考える感覚"** が再現できるのは嬉しいポイントでした。

## おわりに

AWS BuilderCards体験会は、「知らないことを前提に、どう考え、どう説明し、どう学ぶか」を丸ごと体験できるワークショップでした。

ゲームとして楽しみながら、AWSサービスへの理解も深まり、さらに“人と一緒に構成を考えることの面白さ”を再認識することができました。

運営してくださったJAWS‑UG初心者支部の皆さま、会場をお貸しいただきました株式会社トラストバンクさま、ありがとうございました。
転職エージェントだけじゃ物足りない？ChatGPT Deep Researchで“刺さる求人”を掘り当てる方法

こんにちは！

今日は「転職エージェントだけじゃ物足りない？ChatGPT Deep Researchで“刺さる求人”を掘り当てる方法」というテーマで書いていきます。最近、「エージェント経由の求人は似たような案件ばかり」「もっと自分にドンピシャな会社を見つけたい」という声をよく聞きます。もし同じモヤモヤを抱えているなら、少し寄り道していってください。

---

## 1. みんなが感じている“転職エージェント三大あるある”

1. **紹介求人が偏る**
   エンジニアならSIer、Web系なら自社開発──そんなテンプレ案件が並びやすいです。

2. **スキルマッチが雑**
   フロント中心の人にインフラ案件を勧められること、ありますよね。

3. **「とりあえず応募しませんか？」の圧**
   エージェントもビジネスなので、紹介数を伸ばしたい事情があります。

こうした“あるある”は、エージェントが抱える案件数やビジネスモデル上、ある程度避けがたいようです。

---

## 2. よくあるアドバイス、ちょっと待って

> 「複数エージェントを併用しましょう」

確かに正論です。ただ、2社目も3社目も結局同じような案件が並ぶこと、多くないでしょうか。大量に送られてくる求人票に目を通す、面談調整のメールラッシュに疲弊する未来も見えます。そこで一歩引いて考えたいポイントがあります。
ちなみに、 **どのエージェントと組むかを調べるステップもDeep Researchに任せると意外とラク**です。

---

## 3. 「欲しいのは“量”より“深さ”じゃない？」

求人検索で本当に困るのは、「自分のスキルや志向にピタッとはまる情報が少ない」ことです。広く浅く探していると、結局どこも似た会社に見えてしまいます。

---

## 4. とはいえ、エージェントを切り捨てるのも不安

* 年収交渉
* 面接の日程調整
* 非公開求人

これらはエージェントの得意分野です。全部自分でやろうとすると、想像以上に時間と心力を削られます。

---

## 5. そこで「Deep Research × エージェント」のハイブリッド

### 5-1. ChatGPT Deep Researchって何？

ものすごくざっくり言うと、「GPT-4クラスのモデルに“検索エンジン兼スクレイピングアシスタント”を足した機能」です。
レジュメを投げて「これに合う求人を引っ張ってきて」と頼むと、採用ページ、プレスリリースまで横断して候補を出してくれます。

### 5-2. フローを具体的に

1. **Discover**
   Deep Researchにレジュメと希望条件を投げ、長めの候補リストを作ります。
   例：

   ```text
   私の強み：Python / GCP / LLM
   やりたいこと：生成AIプロダクトのPoCから運用まで
   場所：フルリモート優先
   ```
2. **Filter**
   リストをざっと読み、「これは面白そう！」と思える3〜5社に絞ります。
3. **Connect**
   その会社を取り扱っていそうなエージェントに「この企業、内情どうです？」と依頼します。ここでエージェントの交渉力を借りるわけです。
4. **Feedback Loop**
   面接結果をDeep Researchにフィードバックし、次の検索では条件を微調整します。

---

## 6. メリットと注意点

| 項目      | Deep Research | エージェント    |
| ------- | ------------- | --------- |
| 求人の幅    | ◎ 市場全体        | △ 取り扱い企業  |
| 情報の深さ   | ○ 公開情報ベース     | ◎ 社内事情も把握 |
| 交渉・日程調整 | ✕ 自力          | ◎ 代行      |
| 工数      | △ 自己リサーチ要     | ○ 面談調整のみ  |

**注意点**は、「情報の真偽チェックを必ず自分で行う」ことです。公式サイトや社員のSNSでクロスチェックする癖をつけましょう。

---

## 7. というわけで、ゆるやかなまとめ

転職活動で迷子になる原因は、「情報が足りない」か「情報が偏っている」か、だいたいこの二択です。Deep Researchを使えば情報量は一気に増えますし、エージェントを併用すれば交渉面の負担も減らせます。
“刺さる求人”を探すコツは、**広く深く**ではなく、**広く → 絞って → 深く**の順番に探すこと。もしエージェントの紹介にモヤモヤしているなら、今日はGPTにレジュメを投げてみるところから始めてみませんか？

あなたの転職が、もう少しワクワクするプロジェクト探しになることを願っています。
学習1日目

# 目的
学習記録・備忘録として。
短くても可能な限り毎日投稿を目指します。

# 今日やったこと
① MacBook Air (M4)の購入
② Macの初期設定
③ Ruby on Rails の環境構築(？)

## ① MacBook Air (M4)の購入
職場でWindowsに慣れているけれど、気分の上がるものを使いたいということで数年ぶりのMac購入しました。
動作と物理的な軽さに驚いています。

## ② Macの初期設定
細かい部分は省略します。
トラックパッドの感度を最大に、デフォルトブラウザをGoogle Chromeに、キーボードのライトをオフに etc...

## ③ Ruby on Railsの環境構築(？)
一応rails newコマンドが問題無く通ったので、成功のはずです。
下記を行いました。

homebrewの公式ページにアクセスし、書いてあるコマンドをコピペ。
```
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```

その後 brew -v を打っても command not found と言われました。
homebrewのインストール実行結果を見てみると、パスを通すコマンドが記載されていたので、その通りに実行したら成功しました。

rbenvをインストール。
```
brew install rbenv ruby-build
```

パスを通して初期化。
```
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.zshrc
echo 'eval "$(rbenv init -)"' >> ~/.zshrc
source ~/.zshrc
```

インストール可能なrubyバージョンを確認。
```
rbenv install -l
```

取り敢えず最新の3.4.4をインストール。
```
rbenv install 3.4.4
rbenv global 3.4.4
rbenv rehash
```

railsをインストール。
```
gem install rails
rbenv rehash
```

yarnをインストール。
```
brew install yarn
```

yarn -vをしても command not foundと言われましたが、詰まりそうなので一旦無視しました。

デスクトップでrails newコマンドが正常に実行でき、ディレクトリも作成されたので、取り敢えず完了。

# まとめ
・ 実行結果をよく読むことが大切
・ 各コマンドの意味やyarn等の役割は後で調べる
初心者がデータベース設計を考えたときのこと

# 注意
あらかじめ言っておきますが、筆者は初心者なので、自分なりの解釈でまとめています。「100%信じるぜ！」という気持ちで読まないようお願いします。どうぞよろしく！

# 参考動画
このシリーズを見て学びました。わかりやすいです！
https://youtu.be/T6g-DLWHscw?si=8Sb1WvfDfw6cphR7


# 経緯
ポートフォリオ作成のために、献立作成アプリを開発したのですが、初めてのアプリ開発ということもあり、データベースをどのように考えればよいのだろう？と感じて参考動画を見て、設計してみたので備忘録としてまとめてみました。

# 用語の意味
## リレーション
テーブル同士の関係を示すものです。主に次の3種類があります。
1対多（1:n）
多対多（n:n）→ 中間テーブルを作成することで表現
1対1（1:1）
詳しくは、参考動画の「0:22」あたりが参考になります。

# 作成するアプリ
レシピを複数選ぶと、それに必要な食材が自動で集計され、買い出しリストが作られるようなアプリを想定しています。

# 手順
## 結論
横方向に繰り返しがある → 縦に並べよう

縦方向に繰り返しがある → 1:nの別テーブルに切り出そう

## 0.まずはデータを洗い出そう！
実際にアプリが動く様子を思い浮かべながら、「どんなデータが必要か？」を洗い出していきます。
（あ、これも必要かも？みたいにどんどん出してOKです）
以下のように整理してみました。
![スクリーンショット 2025-06-06 6.15.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3893783/8dc1d2f3-1c8c-4aab-876a-e21877626eb1.png)

## 1.第一正規形を行う
第一正規は、横方向の繰り返しをなくすことが目標です！
手順0で設定したテーブルは材料、数、単位列が横方向に複数行繰り返されていたので、「材料」「数量」「単位」列を一列ずつにしました

![スクリーンショット 2025-06-06 6.17.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3893783/60b64e4f-6374-4df0-ac9c-03b79c039651.png)

## 第2正規系を行う
第2正規形は縦方向の繰り返しをなくすことが目標です。
カレー、生姜焼き、ハンバーグなどのレシピが、材料ごとに複数行に分かれていたため、レシピ情報と材料情報を別のテーブルに分けて管理しました。
レシピテーブルと材料テーブルを用意し、recipe_idでリレーションを作りました。

【recipes】
![スクリーンショット 2025-06-06 6.23.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3893783/83578fa0-d30f-44af-baed-1e0169df964b.png)

【ingredients】
![スクリーンショット 2025-06-06 6.23.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3893783/63332beb-4e5d-4a85-bce9-7a9ac7dc1c0f.png)

## テーブルを作成する
第２正規形まで行ったら以下のようなテーブル設計ができました
![スクリーンショット 2025-06-06 7.19.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3893783/f541b45d-fdec-4c43-a191-8b127a063449.png)

### 英語にする
id,作成日時、更新日時をつけて、日本語を英語にします
![スクリーンショット 2025-06-06 7.29.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3893783/8d6d4e5a-dd7c-45ad-8ebe-fc395e9e84e2.png)
idは主キーになります。

:::note info
命名規則
- 半角英字、数字、アンダースコア（_）を使う
- テーブル名は複数形、カラム名は単数形が基本
- text1のような雑な名前は避ける
- SQLの予約語（if, null, dateなど）は使わない
:::

### 型をつける
![スクリーンショット 2025-06-06 7.43.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3893783/f6af5baa-6de3-4cc9-8c2b-22e00067c33f.png)


### インデクスを作成する
インデクスとは、検索のキーになるカラムにつけます。主キーや外部キーにはつけません。

### NOT NULL制約、ユニークキー制約、外部キー制約をつける
- NOT NULL制約：値が必須であることを保証する
- UNIQUE制約：値が重複しないことを保証する
- 外部キー制約：リレーション先のテーブルに必ず存在することを保証する

# 感想
はじめてデータ設計をしてみましたが、想像以上に「データの洗い出し」が難しかったです。
とはいえ、形にすることで理解が深まったので、これからもガンガン開発していきます！