OmniAICreator/Qiita-1.07M huggingface dataset:
【第８回 クラスメソッド 和田響さん】2024 Japan AWS Jr. Champions インタビュー企画

こんにちは！2024 Japan AWS Jr. Championsのtekutaです！
AWS Japanが6月に開催したAWS Summit Japanにて、2024 Japan AWS Jr. Championsが発表されました。Jr.Championsは、AWSを積極的に学び、アクションを起こし、周囲に影響を与えている若手エンジニア向けの表彰プログラムとなっております。Jr.Championsについて多くの方に知ってもらいたいため、表彰された方々にインタビューをしていきます。
第8回目は、クラスメソッドの和田響さんです！！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310014/bdc73cc9-564e-4169-8000-e704478412e0.png)


https://aws.amazon.com/jp/blogs/psa/2024-japan-aws-jr-champions/

# 質問１：これまでの経歴、現在の業務、AWSを知った経緯を教えてください。
コロナの流行でアルバイトが減ってしまったことをきっかけに、プログラミング言語の勉強を始めました。大学3、4回生のときはWebページ等を作成する会社でインターンをしていました。そのあと、新卒でSIerに入社して、金融システムのAWS移行のプロジェクトに参画していました。
現在はクラスメソッドに在籍しており、マルチアカウントの設計等セキュリティのコンサルティングやクラウド費用削減のコンサルティングを実施しております。
AWSは新入社員研修の中で知りました。

# 質問２：Jr.Championsを目指した理由、選出につながったと考える活動があれば教えてください。
ブログの投稿やイベント登壇等のアウトプット活動、イベントを主催して周りに影響を与えていたことが選出につながったと考えます。

# 質問３：Jr.Championsとして現在どのような活動をしていますか。
技術書展の出版です。すでにAWSありあり失敗談について一冊出版しており、二冊目も執筆集です。Jr.Championsの活動が終わるころには、出版できると思います！
また、学校法人に出向いて、AWSについて説明をする予定があります。

https://techbookfest.org/product/aC3JnqNigevzd0rNCaRNve?productVariantID=g8eMkfYVEKkbYF4t59FqXp

# 質問４：Jr.Championsに選出されてよかったことはありますか。
社外のレベルの高いエンジニアと交流することができてよかったと思います。また、Jr.Championsの称号があることで、AWSの社員との交流機会も増えました。

# 質問５：Jr.Championsに選出されて大変だったことはありますか。
クラスメソッド所属ということで同世代のJr.Chamipionsメンバーからの期待値が上がっていることです。クラスメソッドの先輩方はすごい方が多いためですｋ（笑）

# 質問６：Jr.Championsと併せてAll Certifications Engineersも受賞おめでとうございます！目指そうと思ったきっかけを教えてください。また、勉強法もあれば教えてください。
私が在籍しているクラスメソッド内のAWSの部署ではAll Certifications Engineersを取得している方が多数いるため、自身も取るものという雰囲気を感じたためです（笑）
市販の資格対策本を活用して勉強しました。それでも分からない部分や資格本がないものはBlackbeltを読んで補完しました。ただし、「AWS Certified Machine Learning - Specialty」はAWSのサービス知識よりも機械学習の知識が必要とされるので気を付けてください！

# 質問７：All Certifications Engineersに選出されてよかったことはありますか。
AWSの表彰に名前が掲載されたことで、自身の経歴に強みが出たことです。Jr.Champions兼All Certifications Engineersのダブル受賞しているので、みなさんのファーストコンタクトは好印象でした（笑）

# 質問８：今後の夢や目標はありますか。
Jr.Championsとしての活動でアウトプットを残すことです。自分たちの活動が今後のJr.Championsの存続に関わってくるので、Jr.Championsがあって良かったと思えるようなことをしていきたいです。

# 質問９：Jr.Championsを目指す若手に向けてメッセージをお願いします。
Jr.Championsの活動はやるもやらないも自分次第です。Jr.Championsでやりたいこと、成し遂げたいことを応募する時点で意識しておくことがいいと思います。

# 質問１０：全体を通しての質問
## 好きなAWSサービスはなんですか。
AWS Sucurity HubとAWS Trusted Advisorです。
サービスを有効化して終わりにしている事例が多いですが、実はAWSが便利な機能をたくさん提供しているからです。有効化するだけでなく、有効活用できるように情報発信していきたいです。

# 最後に
AWSに関してレベルの高い環境にいる和田さんですが、その中でもかなり存在感を発揮していると感じました。また、Jr.ChampionsメンバーだけでなくAWSの方とも積極的に関わるコミュニケーション力は、IT人材として見習ってくべきと思います。

次回もぜひご覧ください。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310014/419a7b4c-a85e-3515-3433-7600ad4168a5.png)
意外と知らない!?　Regex.Replace()メソッド

　C#で複雑な置き換え処理を行うために`Regex.Replace()`を使ったことはありませんか？
　その時、第三引数は文字列でしょうか？

　実は、**第三引数にはラムダ式を用いることができます！**
# ラムダ式で書くことによる利点
　ラムダ式を用いると、文字列では表現できない、条件分岐ができます。また、「**ラムダ式**」なので繰り返しも記述できます。私の前の記事、[たった一行でエスケープ文字対応!?](https://qiita.com/mu-MueLangDeveloper/items/f8584e53627125373f9a)で、一見エスケープ文字対応を実装するのが難しそうですが、実装するためのコードが
```csharp
public static string Replace(this string s) =>
    Regex.Replace(s, @"\\.",
    m => m.Value switch { "\\n" => "\n", "\\t" => "\t", "\\\"" => "\"", "\\\\" => "\\" });
```
です。ラムダ式を使うことでこんなにも簡単に実装できるのです。
# 終わりに
　置き換え処理でも、なんらかの処理が必要な時は絶対に使えます。
AxiosのInterceptorsを利用してAPIコール時のCookieセットを共通化する

# はじめに
こんにちは、H×Hのセンリツ大好きエンジニアです。（同担OKです😉）

Next.jsのServer Actions経由でJWTを用いた認証エンドポイントにリクエストする際、Server Actionsで認証エンドポイント毎にCookieをセットするのが大変だったのでAxios Interceptorsを使ってCookieのセットを共通化しました！

その方法をご共有しようと思います！

# Axios Interceptorsとは
簡単に言うと、Axiosでのリクエストやレスポンスが処理される前に、**処理を間に挟むこと**ができる機能になります！

https://axios-http.com/ja/docs/interceptors

これを用いることで、APIをコールする際に共通して同じ処理を実行する事が出来たり、レスポンスのステータスによって共通の処理を実行する事が可能となります！

JWTを扱う場合ですと、`access_token`や`refresh_token`をCookieにセットして認証エンドポイントをコールする時にCookieからトークンを渡すような処理がありますが、そちらを共通してリクエスト前に行う使い方が可能です！

# 実装
基本的には、リクエストでインターセプターを利用する際以下のように記述します。
``` api.ts
// リクエスト インターセプターを追加します
axios.interceptors.request.use(function (config) {
    // リクエストが送信される前の処理
    return config;
  }, function (error) {
    // リクエスト エラーの処理
    return Promise.reject(error);
  });
```

こちらのリクエストが送信される前の処理内に、cookieを取得してリクエストのヘッダー内にセットしていきます！
今回はNext.jsを利用していますが、Cookieのセットはそれぞれのやり方で行ってください！

``` api.ts
import { cookies } from "next/headers";

axios.interceptors.request.use(function (config) {
    // リクエストが送信される前の処理
    const cookieHeader = [];
    // access_tokenとrefresh_tokenをそれぞれ格納していく
    const access_token = cookies.get("access_token");
    if (access_token) {
        cookieHeader.push(`${access_token.name}=${access_token.value}`)
    }

    const refresh_token = cookies.get("refresh_token");
    if (refresh_token) {
        cookieHeader.push(`${refresh_token.name}=${refresh_token.value}`)
    }

    // トークンが存在する場合はリクエストのヘッダーにセット
    if (cookieHeader.length > 0) {
        config.headers["Cookie"] = cookieHeader.join("; ")
    }
    return config;
  }, function (error) {
    // リクエスト エラーの処理
    return Promise.reject(error);
  });
```

上記のようにすると、Axiosを使う場合に共通してCookieをリクエストヘッダーにセットする処理を挿入する事が出来ます！

また、レスポンス時に`access_token`が無いことによる認証エラーが発生した場合に、`refresh_token`を用いてリフレッシュを行うことも共通化できます！

``` api.ts
// リクエスト インターセプターを追加します
axios.interceptors.response.use(function (response) {
    // ステータスコードが 2xx の範囲にある場合、この関数が起動します
    // リクエスト データの処理
    return response;
  }, 
  async function (error) {
    // ステータスコードが 2xx の範囲外の場合、この関数が起動します
    // リクエスト エラーの処理

    // JWTのリフレッシュAPI
    const res = await refresh_jwt();
    // 正常終了以外はログイン画面へ飛ばす
    if (res.status !== 200) {
        redirect("/login")
    }

    // 成功時はCookieにトークンをセットする処理を記述
    
    return Promise.reject(error);
  });
```

今回の例のように、Server Actionsだと直接クライアントにCookieがセットされないため、Axios Interceptorsを利用して共通化しちゃいましょう！

# おわりに
今回はAxios InterceptorsでCookieをセットする処理の共通化についてご紹介しました！

ここまで書いておいてあれですが、Server ActionsでCookieを扱うと二度手間になってしまうのでRoute Handlerを活用するのも良い気がしました。

最後までご覧いただきありがとうございました🙇
NestJSをやめてHonoを採用した理由🔥

## そもそもNestJSを使っていたワケ
弊社では フロントエンドとバックエンドをTypeScriptで統一するというスタックを5年以上続けています。
その中でNestJSは

✅ TypeScriptサポート
✅ 公式ドキュメントが充実してて安心
✅ コーディングルールが明確でチーム開発がスムーズ

等の理由から採用しました。

そしてAPIに型を付けるために aspida を採用し、フロントエンドとバックエンド間での型の共通化を行っていました。

## NestJS × aspidaの困りポイント
NestJSとaspidaの連携では、Swaggerを介した型生成に依存していました。
その過程で顕在化した課題は、「暗黙のルール遵守」 に神経を使う場面が多かったことです。
- swagger用のデコレータの癖
例えば配列を型定義する上で何パターンかのデコレータの付け方が存在します。
しかしswaggerと正しく連携させるためには特定のパターンを必ず用いる必要があります。
- 部分的に型が伝搬しない
Controller層、Service層、DTOと1つのAPIを作成する中でも、同じ型定義を明示的に複数回書かないと型安全にならない事象がありました。それにより型定義を明示的に書き忘れた際に実際の値と型定義が異なる状況を引き起こしました。

これらは慣れれば解決するものの

⛔ 新人さんへの負担が大きい
⛔ 別プロジェクトをやってると作法を忘れがち
⛔ 気づかないバグの温床になる

と解決が望ましい状況でした。

## HonoのRPCが全部解決してくれる
HonoではRPCが利用可能です。
https://hono.dev/docs/guides/rpc

RPCとはざっくり `バックエンドのAPIをフロントから関数のように呼べる仕組み` くらいに思っておけばOKです。
そして関数で呼べるだけではなく、型定義が自動で共有されるから

✨ バックエンドの実装がそのままフロントの型定義になる
✨ デコレータのメンテナンスが不要
✨ APIを変更したら即座に関連箇所でエラー検出

といったことが可能になります。

![0130.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3982301/cf96c529-3bc9-576d-d04c-b440a1d564f6.gif)


弊社ではもともとTurborepoを用いたモノレポ構成を取っていたので、非常にスムーズな導入が可能でした。
## AI時代に勝つカギは型管理
CursorのAIアシスタントやRoo CodeのようなコーディングAIが発達する今、型の正確性はますます重要になっています。なぜなら型エラーが発生した場合に自律的にエラーを修正してくれるからです。
将来的にAIがコーディングの90%以上を担うのは間違いないと感じており、その精度や自律性の向上には型を適切に扱うことが非常に重要になるでしょうね。

## もっとHonoは気軽に使って良い
「Hono＝Cloudflare Workers」のイメージが強いかもしれませんが、実はどこでも動かせます。私たちはPrismaとの兼ね合いでCloudflare Workersは様子見中です。代わりに扱いやすく低コストから動かせるCloudRunへデプロイしています。

AI時代に取り残されない第一歩として、まずはHonoでRPCを試してみませんか？
きっと開発がもっとラクになるはずですよ👍
paiza ラーニング

本日は、paizaラーニングで色々学習しました。
１カ月だけ有料版を使ってみています。
自分みたいな未経験のエンジニアは学びたいことありすぎて迷うことが多いと思うのですが、
paizaはその最初の一歩にしやすい初心者向けの説明が分かりやすくて良いです。
そして、がっつり勉強していく前のイメージの習得にとても良いと感じています。
勉強している途中で、今何の段階か分からなくなることが多いのですが、イメージを事前につかんでおくとそれが少なくなる印象です。
(備忘録)　表の書き方

昨日までで一旦HTML,CSSの基礎(以下参考URLの1~199)を一通り終了。
(参考)　https://www.udemy.com/course/web-application-development/?couponCode=KEEPLEARNING

本日より復習のため、演習を再度解き、躓いた部分を備忘録で残しておきます。

躓きポイント：表の作成
https://chatgpt.com/share/679a4557-c3a0-8004-ba6c-fe8076dae414
「Parseable」より「Parsable」が英語的に適切らしい 〜.NETの型名が正式リリース前に変わってた〜

「パース可能」であることを意味する英単語として「Parsable」があります。

GitHubで検索すると、かなりの件数（2025年1月30日の時点で1M件以上）ヒットします。

https://github.com/search?q=parsable&type=code

さて、実は「パース可能」であることを意味する英単語として「Parseable」もそこそこ使われているみたいです。（2025年1月30日の時点で502k件以上）

https://github.com/search?q=parseable&type=code

---

実はこの「Parsable」と「Parseable」で、.NET関連の型名で小ネタがあります。

.NET 6のタイミングで、プレビューとして「Static Abstracts in Interfaces」と「Generic Math」が追加されました。

詳細はこちら:

* 公式ブログ「[Preview Features in .NET 6 – Generic Math](https://devblogs.microsoft.com/dotnet/preview-features-in-net-6-generic-math/)」
* 公式ドキュメント: 「[ジェネリック型数値演算](https://learn.microsoft.com/ja-jp/dotnet/core/whats-new/dotnet-6#generic-math)」

.NET 6において、プレビュー機能の一部として、`IParseable<T>`が導入されました。(eが入っている)

そんな「`IParseable<T>`」は、.NET 7になる前（正式版になる前）のタイミングで、「`IParsable<T>`」(eが入っていない)に、名称が変わりました。

正式なクラスリファレンス: [`IParsable<T>`](https://learn.microsoft.com/ja-jp/dotnet/api/system.iparsable-1?view=net-9.0)
修正されたのはこのPR: https://github.com/dotnet/runtime/pull/67453

修正された際の[dotnet/designs](https://github.com/dotnet/designs)のAPIデザインMeetingのメモは[こちら](https://github.com/dotnet/designs/pull/257#issuecomment-1082307333)

該当部分を引用すると

> A quick English language check says IParsable is the correct spelling over IParseable, and this matches the W3C's guidance and Wiktionary.

なるほど〜
どうやら「e」が入っていない「Parsable」がフォーマルな使い方としては適切だから、正式リリース前に変えたんですね。

---

でも、「e」が付いている「Parseable」もそこそこ使われているみたい。

「（cとgの後は例外として、）最後の発音しないeは取り除く」らしいんだけれど、英語難しいですね。

* movable
* changeable
* parsable
炎上プロジェクトに火消し役が来てくれたらPMが考えるべきこと

こんにちは。  
年度末が近いですね。  
各所で年度内に納めるべく、緊張感が高まっていることでしょう。  
そんな中で、プロジェクトが炎上してしまったとき、火消しに来てくれた人がいるかもしれません。  
今回は、炎上プロジェクトに火消し役が来てくれた際に、PMが考えるべきことをまとめました。  

## 退社時間についてチームで改めて考える

炎上プロジェクトにおいては、既存のメンバーはすでに疲弊していると考えられます。  
そんな中で、火消し役よりも既存のメンバーが先に帰ったらどうでしょうか。  
火消し役にとっては、当然、面白くはないですよね。  
とはいえ、プロジェクトマネージャーとしては、火消し役が入ってくれたのだから、すでに疲弊している既存のメンバーを少しでも休ませてあげたくなる気持ちもあるでしょう。  

この状況で何もしないと、プロジェクトチーム内で帰宅時間に関する牽制合戦のようなことが起きてしまい、雰囲気が悪くなるかもしれません。  
このタイミングで一度、チームで退社時間について話し合ったほうがよいと考えます。  
ローテーションを組むのも一つの手です。  
議論の結果、「今はそんなことを考えるべきではない、まずは全員で乗り切ろう」という結論になれば、それはそれで良いでしょう。  
重要なのは、一度話し合うことです。  

## 明確な指示を出すか、自由にやってもらうのかをはっきりさせる

炎上プロジェクトにおいては、指示を出すなら明確に、出さないなら自由にやってもらうと明確に伝えるべきです。  
指示には、設計方針やコーディングルールも含まれます。  
指示をしっかり出していないのに、ルールだけ厳守するよう求めてしまうと、火消し役が力を発揮できません。  

プロジェクトが炎上している場合、メンバーには余裕がありません。  
通常時と違い、「自然と慣れる」ということは期待できないでしょう。  
火消し役に力を発揮してもらうためにも、指示を出すならしっかりと出す必要があります。  
もし明確な指示を出せないなら、割り切って自由にやってもらうという選択肢もあります。  
ただし、この場合、火消し役のアウトプットにはその人の色が強く出ることを覚悟しておく必要があります。  

## 火消し役の評価が上がるように行動する

私の経験上、火消し役は評価されにくいと感じます。  
理由は、火消し役が入ったプロジェクトは炎上しているため、そのプロジェクト自体の評価が低くなりがちだからです。  
また、火消し中は多忙なため、アピール要素の収集も難しく、自己アピールの難易度が高くなります。  

火消し役として参加してくれた人が適正に評価されるよう、PMとしてその人の上長に進言するなどの行動を取るのもよいのではないでしょうか。  

## 人を出してくれたプロジェクトチームに感謝を伝える

火消し役の人は、本来自分がやるべき仕事を後回しにして手伝ってくれています。  
つまり、その人が本来所属しているプロジェクトチームは、一時的にその人が離れることをカバーしてくれているはずです。  

しかし、たまに火消し役を出したのに、無事に炎上が収束した後、何のリアクションもないことがあります。  
見返りばかりを求めるのはよくありませんが、感謝の意思が示されないと、モチベーションが下がるのは仕方のないことです。  
また、次にいつ助けてもらうことになるかわかりません。  
今後のためにも、感謝の言葉ぐらいは伝えておいたほうがよいでしょう。  

---

以上、炎上プロジェクトに火消し役が来てくれたらPMが考えるべきことを4つ挙げてみました。  
皆さまのプロジェクトが炎上しないことを祈っています。
Gmailが来た時にAPIを叩きたい①

# はじめに

こんにちは、エンジニアのkeitaMaxです。

今回はGmailが来た時にAPIを叩きたいということで、
毎分メールをチェックして未読メールがあればAPIを叩くという方法で実装してみようと思います。

# AppScriptにコードを書く

AppScriptを使います。

AppScriptを開き、プロジェクトを作成します。
https://script.google.com/home

![スクリーンショット 2025-01-30 0.07.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715123/99d148ee-cc52-6fd5-b605-13739841717c.png)

すると以下のようにコードが入力できる画面に遷移するので

![スクリーンショット 2025-01-30 0.08.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715123/ebebef48-ebff-3832-0a70-1d3d6b2fa46c.png)

以下のコードを入力します。
```js
function checkEmails() {
 var senderEmail = "notifications@github.com"; // 取得したい送信元のメールアドレス
  var searchQuery = "from:" + senderEmail + " newer_than:30m"; // 30分以内のメールを検索
  var threads = GmailApp.search(searchQuery); // スレッドを検索

  // threadsが空でないか確認
  if (threads.length === 0) {
    Logger.log("条件に合うメールがありませんでした。");
    return;
  }
  threads.forEach(thread => {
    const messages = thread.getMessages();
    messages.forEach(message => {
      UrlFetchApp.fetch("{~叩きたいAPI~}", {
        method: "post",
        contentType: "application/json",
        payload: JSON.stringify(message)
      });
    });
  });
}

```

# トリガーの設定

![スクリーンショット 2025-01-30 0.09.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715123/266791d6-03ca-4bd0-a83d-f2972d7902b5.png)

上の画像のトリガーをクリックします。

トリガーを追加から以下のように毎分行うようにします。

![スクリーンショット 2025-01-30 0.11.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715123/ceaca45c-18fc-e70e-d58e-cad6e8f8fea7.png)


これで保存をし、以下のように追加されていれば成功です。

![スクリーンショット 2025-01-30 0.16.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715123/a2d87797-9e8a-0f96-9b65-a7c25f4b2886.png)


# おわりに

この記事での質問や、間違っている、もっといい方法があるといったご意見などありましたらご指摘していただけると幸いです。

最後まで読んでいただきありがとうございました！
PythonでDeepSeekをローカルで実行するコード

DeepSeekがバズっている。会社でこれをローカルマシンで動かすように言われたので、どのように書けばいいか調べてまとめてみた。

※なお、まだコードは実際に実行して試していない。自分が持っているマシンじゃ到底動くはずもないので、会社で試す予定。ここにまとめているのは一旦自分が会社でカンニングするためのメモ用。

## vLLM使う場合

vllmを使う場合は、vLLMサーバーを立ち上げ、そのサーバーに対してAPIリクエストをする形式で実行するみたい。

```python:main.py
import subprocess
import time
import requests

def main():
    # 1) vLLMサーバーをバックグラウンド起動
    #    （Windowsや環境によってはshell=Trueが必要になる場合もあります）
    p = subprocess.Popen(["vllm", "serve", "deepseek-ai/DeepSeek-R1"])
    
    # 2) サーバーが立ち上がるまで少し待機
    time.sleep(10)  # 大きめに待っておく
    
    # 3) Python からリクエストを送る
    url = "http://localhost:8000/v1/chat/completions"
    payload = {
        "model": "deepseek-ai/DeepSeek-R1",
        "messages": [
            {"role": "user", "content": "What is the capital of France?"}
        ]
    }
    response = requests.post(url, json=payload)
    print(response.json())

    # 4) 用が済んだらサーバーを終了
    p.kill()

if __name__ == "__main__":
    main()

```

あるいは下記のように記述してもいいようだ。

```Python:main.py
from vllm import LLM, SamplingParams

def main():
    llm = LLM(model="deepseek-ai/DeepSeek-R1")
    prompt = "What is the capital of France?"
    outputs = llm.generate([prompt], SamplingParams(max_tokens=64))
    print(outputs[0].outputs[0].text)

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

## vLLMを使わない方法

vLLMを使わない場合、下記のように書ける。

```Python:main.py
from transformers import pipeline

messages = [
    {"role": "user", "content": "Who are you?"},
]

# パイプラインの生成
pipe = pipeline("text-generation", model="deepseek-ai/DeepSeek-R1", trust_remote_code=True)

# 推論結果を変数に代入
result = pipe(messages)

# 結果を表示
print(result)
```

また、pipelineを使わない場合、下記のように書けるらしい。


```Python:main.py
from transformers import AutoTokenizer, AutoModelForCausalLM

# トークナイザーの読み込み
tokenizer = AutoTokenizer.from_pretrained("deepseek-ai/DeepSeek-R1", trust_remote_code=True)
# モデルの読み込み
model = AutoModelForCausalLM.from_pretrained("deepseek-ai/DeepSeek-R1", trust_remote_code=True)

# 推論したい文字列
prompt = "Who are you?"

# トークナイズしてテンソル化
input_ids = tokenizer(prompt, return_tensors="pt").input_ids

# モデルを使ってトークン列を生成
output_ids = model.generate(input_ids, max_new_tokens=50)

# 生成されたトークン列を文字列にデコード
output_text = tokenizer.decode(output_ids[0], skip_special_tokens=True)

# 結果の表示
print(output_text)

```

## まとめ
明日会社で環境構築できるように頑張る
達人プログラマーを読み直して

## はじめに
昨年読んだ本書を読み直して、そうだよなぁと思い直したことを書き残していこうと思います。

## 達人プログラマーの性格
1. 新しいもの好き
試すことに行きがいを感じる
1. 研究好き
疑問を感じやすい
3. 批判的
物事がはっきりするまで、言葉を額面通り受け取らない
4. リアリスト
4. 何でも屋
4. 自分の技術に関心をもつ
4. 自分の仕事について考える
一定のタイミングではなく、全ての意思決定に対して継続的かつ批判的な評価をしていく
## 達人の哲学
1. 自分には現状を打破する力がある
1. どんな結果になっても過ちを認め、プロとしての自責を持って言い訳よりも対策を用意すること
1. 割れた窓を放置しない
ここで言う割れ窓はコードだけでなく設計、意思決定、組織等あらゆる事象を含んでおり、見つけ次第治す、直せなくても明示的にわかるようにしなければならない。
すべてが綺麗であれば納期という燃え盛る日が近づいていても、汚す最初の人にはなりたくないという心理が働く
4. 変化の触媒たれ
システムにとって必要なものと方法がはっきり見えているが、承認が必要なときは要求を引き出せるようなプロトタイプを作る？
※ここはもう少し読み込身が必要
5. プロとして成果物に責任を持つため品質要求は明確にする
5. 知識ポートフォリを作成する
    指針
    1. 定期的に投資する
    1. 多様化
    1. リスク管理
    1. 安く買って高く売る
    1. リバランス
    
    作成方法
    1. 年で1の言語を学習
    1. 月1で技術書読む
    1. 技術書以外の本も読む
    コンピュータは人のニーズを満たすためにあるため
    4. 講習に参加する
    4. 異なる開発環境に慣れ親しむ
7. 伝達
    1. 聞き手のことを知る
    情報が相手に伝わったのみ伝達は成就する
    2. 言いたいことを知る
    2. タイミングを選ぶ
    2. スタイルを選ぶ
    2. 見栄えを良くする
    2. 聞き手を巻き込む
    草稿段階から巻き込んでフィードバックを得る
8. ドキュメントは付け足すものではなく作り上げるもの
開発とは切手は切り離せないものであり、コードに適用していると原則同じように扱う

## 終わりに
これ以降の章は別の書籍でも扱っている内容のため割愛します。
データベースの正規化とは？

データベースの**正規化**とは、「データを整理して、重複をなくし、管理しやすくする」ことです。

例えば、**ムダなデータを減らし、更新ミスを防ぐためのルール**と考えると分かりやすいです。
## **1. 正規化が必要な理由**

もしデータを整理せずに保存すると、こんな問題が発生します。

### **① データが重複する**

| ID | 名前 | 商品 | 価格 |
| --- | --- | --- | --- |
| 1 | 田中 | 本 | 1000 |
| 2 | 鈴木 | ペン | 200 |
| 3 | 田中 | ペン | 200 |

→ 「田中さん」のデータが2回出てきています。

### **② 修正が大変になる**

例えば、「ペンの値段が200円→250円に変わった」とします。

でも、データがバラバラに保存されているので、**全部のデータを探して修正**しないといけません。

→ **更新ミスの原因**になります。

### **③ データの追加や削除が難しくなる**

「田中さんが注文をキャンセルした」とき、1行だけ消すと「田中さんの情報自体が消えてしまう」ことも。

データが整理されていないと、**うまく削除できない**問題が発生します。

---

## **2. 正規化のルール**

データを整理するために、「正規化」という方法があります。

基本的に**3つのルール（3つの正規形）**を守ると、きれいに整理できます。

---

### **【第1正規形】（データを1つずつ分ける）**

**✔️ 同じ場所に、複数のデータを入れない**

| ID | 名前 | 商品 | 価格 |
| --- | --- | --- | --- |
| 1 | 田中 | 本, ペン | 1000, 200 |
| 2 | 鈴木 | ペン | 200 |

→ **NG！「本, ペン」のように、複数のデータを1つのセルに入れない**

| ID | 名前 | 商品 | 価格 |
| --- | --- | --- | --- |
| 1 | 田中 | 本 | 1000 |
| 1 | 田中 | ペン | 200 |
| 2 | 鈴木 | ペン | 200 |

✔️ **データを1つずつ分けると、検索や修正がしやすくなる**

---

### **【第2正規形】（データの重複をなくす）**

**✔️ データを「主キー」によって正しく分ける**

| ID | 名前 | 商品 | 価格 |
| --- | --- | --- | --- |
| 1 | 田中 | 本 | 1000 |
| 1 | 田中 | ペン | 200 |
| 2 | 鈴木 | ペン | 200 |

→ **「田中」や「鈴木」の情報が何回も出てくるのがムダ**なので、別の表に分ける

### **分けた後（第2正規形）**

✅ **顧客テーブル（お客様情報を管理）**

| 顧客ID | 名前 |
| --- | --- |
| 1 | 田中 |
| 2 | 鈴木 |

✅ **注文テーブル（注文した商品を管理）**

| 注文ID | 顧客ID | 商品 | 価格 |
| --- | --- | --- | --- |
| 1 | 1 | 本 | 1000 |
| 2 | 1 | ペン | 200 |
| 3 | 2 | ペン | 200 |

✔️ **顧客情報と注文情報を分けることで、重複がなくなり、修正しやすくなる**

---

### **【第3正規形】（情報を「意味ごと」に整理する）**

**✔️ 「主キー」以外のデータが他のデータに依存しないようにする**

| 注文ID | 顧客ID | 商品 | 価格 | メーカー |
| --- | --- | --- | --- | --- |
| 1 | 1 | 本 | 1000 | A社 |
| 2 | 1 | ペン | 200 | B社 |
| 3 | 2 | ペン | 200 | B社 |

→ **「メーカー」は「商品」に依存する情報なので、別のテーブルに分ける**

### **分けた後（第3正規形）**

✅ **商品テーブル（商品の情報を管理）**

| 商品ID | 商品 | 価格 | メーカー |
| --- | --- | --- | --- |
| 1 | 本 | 1000 | A社 |
| 2 | ペン | 200 | B社 |

✅ **注文テーブル（注文情報を管理）**

| 注文ID | 顧客ID | 商品ID |
| --- | --- | --- |
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 2 |

✔️ **情報を「意味ごと」に整理すると、修正がしやすくなる**

---

## **3. まとめ**

✅ **第1正規形** → **1つのセルに1つのデータを入れる**

✅ **第2正規形** → **データを「主キー」によって分ける（重複をなくす）**

✅ **第3正規形** → **情報を「意味ごと」に整理する（関連データは別のテーブルに分ける）**

こうすることで、**データが整理され、修正や検索がしやすくなります！**

もしデータベースを作るときに「この情報、本当にここに入れていいのかな？」と思ったら、**正規化を意識するとスッキリ整理できます！**
AWS-CLF→SAAへの挑戦（合格体験記）

## はじめに
2025年1月28日にAWS認定ソリューションアーキテクト – アソシエイト（SAA-C03）試験に合格しました。私の学習方法や使用した教材について共有します。これから受験する方の参考になれば幸いです。

## 受験までのスケジュール
- **学習期間**：1か月（2024年12月28日～2025年1月27日）
- **前提知識**：AWSクラウドプラクティショナー（CLF）試験に2024年12月28日に合格済み

## 学習に使用したツール
### Udemy
- 【SAA-C03版】これだけでOK！ AWS 認定ソリューションアーキテクト – アソシエイト試験突破講座
- 【SAA-C03版】AWS 認定ソリューションアーキテクト アソシエイト模擬試験問題集（6回分390問）

### AWS認定資格 WEB問題集＆徹底解説
- URL: [AWS認定資格WEB問題集](https://aws-exam.net/saa/index.php)
　SAAの問題はプレミアムプランのみとなっているため、課金しました。
 しかし、Ping-tなど無料でSAA問題集を提供しているサイトもあるため、コストを抑えたい方は無料問題集を活用すると良いと思います。



### 書籍
- **徹底攻略 AWS認定 ソリューションアーキテクト − アソシエイト教科書 第3版**（通称：黒本）

## 学習方法

### ① Udemyの試験突破講座を2倍速で視聴
- 講座の総時間は約47.5時間。
- 2倍速で視聴することで、約20時間の時間短縮が可能。
- ハンズオンは見るだけ。

### ② Udemyの模擬試験問題集を解説モードで解く
- 1問1問解いて、誤った問題をマーク。
- **重要なポイント**
  - **a.** 誤った選択肢が“**なぜ誤っているのか**”を理解する。
  - **b.** 正解の選択肢だけでなく、“**正解以外の選択肢がなぜ誤りなのか**”を理解する。
- これにより、試験本番で「これどっちだっけ？」と悩む場面を減らすことができる。

### ③ 模擬試験問題で正解率70%以上を取れるまで繰り返す
- Udemyの模擬試験は比較的高難易度。
- **7割以上**正解できる理解度があれば、本番試験でも問題ないかと思います。（私自身もこの方法で合格しました）

### ④ AWS認定資格 WEB問題集の確認テストを実施
- ③までしっかり学習できていれば、7～8割以上の正解率を取れるはず。

### ⑤ 黒本（教科書）はほとんど使わなかった
- SAAからAWS資格を初めて受ける人には有用。
- ただし、CLF合格済みの人には重複する部分が多い。
- 本を読むよりも模擬試験を解くことに時間を使うほうが効率的。

## まとめ
1か月間の学習でAWS-SAA試験に合格するためには、
- **動画視聴は効率的に（2倍速視聴）**
- **問題集を重点的に解く**
- **間違えた問題の選択肢を深く理解する**
- **7割以上の正解率を目指す**

この方法で学習を進めれば、短期間でも合格可能です。これから受験する方の参考になれば嬉しいです！
システム開発における基本設計の重要性について

# はじめに
最近、チーム開発で機能の追加提案の一環で基本設計をする機会がありました。
今までは要件や仕様が決まっている中で実装をすることが多かったので、改めて基本設計の重要性を感じました。
そこで今回はその基本設計についてまとめてみました。

# 基本設計とは
基本設計は、**要件定義で明確化されたシステムの目的や機能を、具体的な形にするためのプロセス**です。この段階で、システムの全体像や外観（操作画面の見た目など）、技術的な実現方法などが決定されます。

主に以下のような成果物を作成します。
- 基本設計書
- テーブル定義書
- 画面設計書
- ER図
- 画面遷移図
- API設計書
- エンドポイント設計書

# システム開発の工程と基本設計の位置付け
一般的に、システム開発は以下の工程で進められます。

1. **要件定義**: 顧客の要望や課題を明確にし、システムに求められる機能や性能を定義します
2. **基本設計**: 要件定義で定義された内容に基づき、システムの全体像や主要機能、技術的な実現方法などを具体的に設計します
3. **詳細な設計**: 基本設計で決定された内容をさらに詳細化し、具体的な機能や画面、データベースなどを設計します
4. **開発**: 詳細設計に基づいて、プログラムを作成します
5. **テスト**: 作成されたプログラムが正しく動作するかを検証します
6. **運用・保守**: リリースした後のシステムを運用し、保守を行います

![システム開発の流れ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677000/dcb4832d-4fff-c66e-bdcc-f2343e72f23f.png)

> 引用：[システム開発の工程（流れ・手順）を解説！開発手法ごとの比較やメリットも](https://dx-offshore.mynavi.jp/resources/system-process)

# 基本設計が不十分だと何が起こる？？
もし基本設計が不十分なまま開発工程に進んでしまうと、**手戻りや仕様変更**が頻繁に発生し、**スケジュール遅延やコスト超過**につながる可能性が高まります。

# 基本設計の重要性
## プロジェクトの方向性を定める
基本設計は、開発チーム全体が共通認識を持つための基盤となります。システムの目的や機能、技術的な制約などを明確にすることで、開発チームは迷うことなく作業を進めることができます。

## 手戻りを防ぐ
基本設計をしっかりと行うことで、開発段階での手戻りを大幅に減らすことができます。開発工程が進んでから仕様変更が発生すると、時間もコストもかかってしまいます。

## 品質の確保
基本設計では、システムの品質を確保するための様々な検討が行われます。性能、セキュリティ、保守性などを考慮することで、安定したシステムを開発することができます。

## 関係者間のコミュニケーションを円滑にする
基本設計の成果物である設計書は、開発者だけでなく、顧客や運用担当者など、様々な関係者間のコミュニケーションを円滑にするためのツールとして活用できます。

## テーブル定義の事例から学んだこと
基本設計の中でも特に重要なのが、テーブル定義（データベース設計）。
これを曖昧にして進めてしまうとどのような問題が起こりうるのでしょうか？？

**テーブル定義あるある3選**を独断と偏見でまとめました。
1. **データ構造の不明確さ**
テーブル定義が曖昧だと、どのようなデータがどのテーブルに格納されるのか、各項目の意味は何かが明確になりません。
その結果、開発者はテーブル構造を理解するのに時間がかかり、実装作業が遅延する可能性があります。
2. **データ型の不一致**
テーブル定義でデータ型が明確に定義されていない場合、実装時に適切なデータ型を選択する必要があります。
しかし、データ型が曖昧だと、開発者によって解釈が異なり、データ型が不一致になる可能性があります。
データ型が不一致になると、データの入力や処理でエラーが発生したり、データの整合性が失われたりする可能性があります。
3. **制約の欠如**
テーブル定義で主キーや外部キーなどの制約が明確に定義されていない場合、実装時にデータの整合性を保つための制約を別途実装する必要があります。
しかし、制約が曖昧だと、制約の実装漏れや誤った制約の実装が発生する可能性があります。
制約の欠如は、**データの重複や矛盾、参照整合性エラー**などを引き起こす可能性があります。

## 関係者へのメリット
基本設計以外の担当者が関心を持つことは、様々なメリットをもたらします。

### 実装者
- 設計者の意図を理解しやすくなり、実装作業がスムーズに進められるようになります
- 設計の問題点にいち早く気付き、手戻りなどを減らせるようになります

### テスト担当者
- テストケースの作成やテスト計画の策定がより効果的になります

### 運用・保守担当者
- 設計段階からシステムの構造や動作を理解しておくことで、トラブル発生時に原因を特定しやすくなり、迅速な対応が可能になります
- 設計段階で運用保守に必要な情報を把握し、考慮した設計にすることで、運用保守作業の効率化を図ることができます

### 営業担当者
- 業務知識の理解が深まり、顧客への提案や説明がより的確になります

## 詳細設計との違い
### 基本設計
**目的**: システムの全体像を把握し、主要な機能や構成要素を決定すること
**対象**: ユーザーの要求に基づき、システムが満たすべき要件を明確にする

### 詳細設計
**目的**: 基本設計で決定された内容を具体的に落とし込み、開発者が実際に開発作業を行えるようにすること
**対象**: 基本設計で定義された機能を、具体的なモジュールやプログラムに分割する

|項目  |基本設計  |詳細設計  |
|---|---|---|
|目的	  |システムの全体像の把握  |開発者が作業できるレベルまで具体化  |
|対象  |ユーザーの要求  |基本設計の内容  |
|内容|機能・非機能要件、構成、画面、データベース、API|モジュール、インターフェース、物理設計、プログラム、テスト|
|成果物|外部設計書|内部設計書|

要約すると、
基本設計は、<INS>ユーザーや関係者にシステムの全体像を理解してもらうための設計です。</INS>
詳細設計は、<INS>開発者が実際に開発作業を行うための設計です。</INS>
		
# まとめ
基本設計は、プロジェクトの方向性を決定づける重要な工程です。基本設計がしっかりしていれば、プロジェクトの目標達成がスムーズに進み、成功に近づきます。
WordPressのプラグイン「Flamingo」のレコードを消す

## 8年もののWordPressと40万レコードのwp_postsと820万レコードのwp_postmeta

随分昔に作られたWordPressのサイトの引っ越しをすることになりました。
いつものようにダンプデータをとって、引越し先のデータベースに突っ込んで、wp_cliでURLを変える……と思ってたのですが、なんだか一つひとつのアクションにやけに時間がかかる。
どうなってるの、とレコード数を数えたら、見出しのような数。
内訳を見てみると、そのほとんどが、`flamingo_inbound`という`post_type`の記事。そしてwp_postmetaの800万件を超えるレコードもどうやらその関係。

## プラグインをアンインストールしたら消える？

このレコードの理由になっているプラグインは、「Flamingo」というもの。
依頼主に確認したところ、プラグインは消していいよ、ということだったので、もしかすると、プラグインのアンインストールで消えるかなと思ったのだけど、これは思惑通りにはいかず、レコードは残ったままになりました。

## うかつに消せないっぽい？

調べてみると先行事例がみつかった。

- [Flamingoの大量のスパムを一括で削除する方法](https://stilltalkintv.com/post-3862/)

なるほど。でも、

```MySQL
DELETE FROM wp_posts WHERE post_type = 'flamingo_inbound';
```

しちゃうと、`wp_postmeta`のレコードが残ってしまうそうな。上掲の記事によると、WordPressの関数`wp_delete_post($post->ID, true)`だったら、紐付いている`wp_postmeta`のレコードも消してくれるそうな。

## 一気に消せない

しかしまあ40万件と800万件を一気に消すことは当然できない。というわけでバッチ処理。

```PHP
<?php
set_time_limit(0);
define('WP_USE_THEMES', false);
require(__DIR__ . '/wp-blog-header.php');

$batch_size = 500;
$loop_count = 0;

do {
    $items = $wpdb->get_results("
        SELECT ID FROM {$wpdb->posts}
        WHERE post_type = 'flamingo_inbound'
        LIMIT $batch_size
    ");

    if (empty($items)) {
        echo "No more flamingo_inbound posts to delete.\n";
        break;
    }

    foreach ($items as $v) {
        wp_delete_post($v->ID, true);
    }

    wp_cache_flush();
    $loop_count++;

    echo "Batch $loop_count: Deleted " . count($items) . " posts.\n";
} while (!empty($items));

echo "All flamingo_inbound posts deleted.\n";
```
これを`wp-blog-header.php`と同じディレクトリ（ほとんどの場合、ドキュメントルートかしら）に置いて、
```bash
/path/to/php /path/to/filename.php
```
で、実行すると、500件ずつ削除してくれて、全部なくなります。4時間位かかりましたが、すっきり。
Ollamaについての基礎的な操作メモ

:::note info
著者初投稿記事です。
下手くそだとは思いますが、温かく見守っていただければと思います。
:::

Ollamaを動かす時の基本操作のメモです。
誰かの役に立てば幸いです。

# Ollamaとは？
- Ollamaとは?ローカルでLLMを動かすためのソフトウェア
- 家でLLMを遊びたい人には便利

# Ollamaを動かしてみる
#### 実行環境
- Docker(devcontainer)
→Linux(Ubuntu)環境です

#### インストール
[Ollama公式サイト](https://ollama.com/download/linux)を参考にインストール。
以下コマンドで、ダウンロード+インストールができます。
```bash
curl -fsSL https://ollama.com/install.sh | sh
```
#### Ollamaの起動
ダウンロードが終わったら、以下のコマンドでOllamaのサーバーを起動します。

:::note warn
Ollamaコマンドを実行するためには、Ollamaのサーバーが起動しているしている必要があります。
:::
```shell
ollama serve
```
#### 動かしたいモデルをダウンロード
以下のコマンドで、モデルのダウンロードや実行ができます。
初回はモデルのダウンロードがあるためかなり時間がかかります。(dockerで行うので、ボリュームをマウントすることを忘れずに。ボリュームは`/root/.ollama`をマウントしてください)
今回は`llama3.3`を動かします

```bash
ollama run llama3.3
＃ ollama run 実行したいモデル
```

うまく実行できると、ターミナルで実行LLMを試すことができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780680/98e66946-ac97-7299-b713-1a07dd86409a.png)


# 参考情報
- [Ollama公式ドキュメント](https://ollama.com/)
【Unity】ILogHandlerのドキュメントのサンプルをいじって動かしてみる


# はじめに

UnityのドキュメントのILogHandlerにサンプルコードが記載されてたので試してみる。

https://docs.unity3d.com/ja/2023.2/ScriptReference/ILogHandler.html


# 実装

実装にあたって以下の内容を対応する
1. ログファイルの出力先をLogsフォルダに変更する
1. ファイルストリームを閉じてないので閉じるようにする
1. ILogHandlerが適応されているの分かりやすくするため、Debug.Logからログの出力をする

``` cs:MyFileLogHandler.cs
using System;
using System.IO;
using UnityEngine;

public class MyFileLogHandler : ILogHandler, IDisposable
{
    private FileStream _fileStream;
    private StreamWriter _streamWriter;
    private readonly ILogHandler _defaultLogHandler;

    public MyFileLogHandler(ILogHandler defaultLogHandler)
    {
#if UNITY_EDITOR
        string filePath = Application.dataPath + "/../Logs/MyLogs.txt";
#else
        string filePath = Application.persistentDataPath + "/MyLogs.txt";
#endif
        _fileStream = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
        _streamWriter = new StreamWriter(_fileStream);
        _defaultLogHandler = defaultLogHandler;
    }

    public void Dispose()
    {
        if(_streamWriter != null)
        {
            _streamWriter.Close();
            _streamWriter = null;
        }
        if(_fileStream != null)
        {
            _fileStream.Close();
            _fileStream = null;
        }
    }

    public void LogFormat(LogType logType, UnityEngine.Object context, string format, params object[] args)
    {
        string formatEx = "[MyFileLogHandler]:" + format;
        if(_streamWriter != null)
        {
            //ログをファイルに書き込む
            _streamWriter.WriteLine(String.Format(formatEx, args));
            _streamWriter.Flush();
        }
        _defaultLogHandler.LogFormat(logType, context, formatEx, args);
    }

    public void LogException(Exception exception, UnityEngine.Object context)
    {
        _defaultLogHandler.LogException(exception, context);
    }
}


```

``` cs:MyGameClass.cs
using UnityEngine;

public class MyGameClass : MonoBehaviour
{
    private MyFileLogHandler _fileLogHandler;
    void Start()
    {
        Debug.Log("MyGameClass Start before");
        _fileLogHandler = new MyFileLogHandler(Debug.unityLogger.logHandler);
        Debug.unityLogger.logHandler = _fileLogHandler;
        Debug.Log("MyGameClass Start after");
    }

    void OnDestroy()
    {
        _fileLogHandler.Dispose();
    }
}


```

# 実行結果

![スクリーンショット](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3553099/e2ce6f07-30d8-0d85-728e-16796792f300.png)

![スクリーンショット](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3553099/a93ea112-cfec-23e1-3095-40fa07b4fb93.png)


MyFileLogHandlerを設定した後に、MyFileLogHandlerの内容が反映され、Logsフォルダ内にLogファイルが生成されました。
【Tableau】オープンデータを使って観光マップを作る

# はじめに
札幌市のオープンデータを使い、観光マップを作成しました。
その過程と用いたテクニックを紹介します。

https://public.tableau.com/views/SapporoSightseeingMap/1?:language=ja-JP&:sid=&:redirect=auth&:display_count=n&:origin=viz_share_link
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3522398/ed7e7b5b-5454-1a05-32b7-74a0771ce577.png)


# 使用したデータ
https://data.pf-sapporo.jp/

https://ckan.pf-sapporo.jp/dataset/sapporo_kankou_spot

上記の札幌観光スポットデータをCSV形式でダウンロードし使用しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3522398/c4a4a464-4bb5-fadc-98e5-4ac4a8bb97d2.png)

# データの処理

マップに落とし込むための情報・検索窓に使いたい項目を確認してみます。
- 緯度・経度を使いマップにプロットする
- プロットの色はエリアで分ける
- 「何をするか」で検索はかけられた方が良いので分類項目は使いたい

# シートの作成

### 必要なパラメーター
- 分類検索用パラメーター
今回のデータでは1つのレコードに分類が「;」区切りで複数入っていました。2,3個程度ならカスタム分割でカラムを複数作り検索に活かすのですが、数が多いものもありましたので、パラメーターを用いた部分一致フィルタを採用することにしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3522398/3aca5d27-0a07-84f6-514f-0e10ec752b8b.png)
このパラメーターをダッシュボードに表示させ、パラメーター値によってフィルタをかけています。

### 必要な計算フィールド
- 緯度・経度から座標算出
```
MAKEPOINT([緯度（10進法）],[経度（10進法）])
```
MAKEPOINT(緯度,経度)とし、マークの詳細欄に持っていくとプロットが作成されます。

### 地図のスタイル変更
デフォルトの地図だと道路・地形などが分かりづらく、観光マップとしては不適だと感じたため、地図のスタイルを変更しました。
地図上で右クリックし、「バックグラウンドレイヤー」を選択することで、各種地図の設定が可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3522398/5ef54104-0cb6-643e-e3a1-75445337a346.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3522398/c8cd4dd6-6598-f751-4819-eba70340d515.png)
→ 何を表示させたいかなども詳細に設定が可能です。

https://help.tableau.com/current/pro/desktop/ja-jp/maps_options.htm

### ツールヒントの編集
マップとして最低限必要な情報をツールヒントに加えました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3522398/3986b651-4808-4576-b26d-af12e53b334e.png)

### 店舗詳細情報リスト（明細表）の作成
先ほどのツールヒントの情報に加え説明・URLといった「ツールヒントに加えると長くて見づらいもの」を加え、Vizの下部に配置する明細表を作成しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3522398/98629f48-7cee-8641-4a7a-eed2cd6cb646.png)


# Vizの構築・レイアウト
- マップをフィルターとして利用し、クリックしたプロットがそのまま明細表に表示される仕様に
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3522398/bedb6456-5461-2164-6cc6-b1e9ccb8ca46.png)

- フィルターには「エリア」「分類」を採用
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3522398/967223bb-b8a3-f656-6674-b56b88bee2fe.png)

- 明細のツールヒントにURLリンクを採用し、気になった店の公式サイトに飛べるように設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3522398/c478cece-79dc-3355-a6c1-5f5660896d96.png)

この設定はダッシュボードのアクションからできます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3522398/ee7149f7-8438-9f5d-1967-d4f996dc9e64.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3522398/d978821d-7131-1a36-94c7-c0fd9a31a6f7.png)


# おわりに
- Tableau Prepなど、データプレパレーションツールを用いることができれば「営業時間」「季節」などで絞り込みを行うことが出来るだろうな…と感じました。オープンデータはやはり癖が強いですね…。
- 今回は簡単なVizとなりましたが、DATASaberで学んだテクニック（マップ・シートをフィルターとして利用・URLのアクション・パラメーター）だけでなく、マップのスタイル変更・MAKEPOINT関数といった新たに知識をつけ使うことができ、Ord復習に最適でした。
Rockylinux 8.10にnodejs22が来てる

RHEL8とRocky8にここ数日で使えるようになったと思われる。

```
# dnf module list nodejs
Last metadata expiration check: 0:00:46 ago on Wed Jan 29 14:14:43 2025.
Rocky Linux 8 - AppStream
Name                  Stream               Profiles                                            Summary
nodejs                10 [d]               common [d], development, minimal, s2i               Javascript runtime
nodejs                12                   common [d], development, minimal, s2i               Javascript runtime
nodejs                14                   common [d], development, minimal, s2i               Javascript runtime
nodejs                16                   common [d], development, minimal, s2i               Javascript runtime
nodejs                18                   common [d], development, minimal, s2i               Javascript runtime
nodejs                20                   common [d], development, minimal, s2i               Javascript runtime
nodejs                22                   common, development, minimal, s2i                   Javascript runtime

Hint: [d]efault, [e]nabled, [x]disabled, [i]nstalled
```

リリースノートには掲載があったけど、今まで無かった？
https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/8/html-single/8.10_release_notes/index#new-features-dynamic-programming-languages-web-and-database-servers

でもEOL不明
https://access.redhat.com/support/policy/updates/rhel-app-streams-life-cycle

(2025-04-01追記)
追加された
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502524/5c904f6b-e20e-4396-a120-46c03b74cb19.png)
【Mac】ターミナルでIPアドレスを取得する方法

## ローカルIPアドレス

以下のコマンドでローカルIPアドレスが取得できます。

```terminal
$ ifconfig | grep "inet " | grep -v 127.0.0.1 | awk '{print $2}'
192.168.2.126
192.168.2.109
```

```terminal
$ ipconfig getifaddr en0
192.168.2.126
```

## グローバルIPアドレス

以下のコマンドでグローバルIPアドレスが取得できます。

```terminal
curl ipecho.net/plain; echo
```
Fetch通信でフォームが意図せずリロードされる問題の解決方法

# 発生した事象
HTMLフォームを使った画面で、ボタンクリック時にJavaScriptの fetch によりサーバへ非同期通信を行う実装を行った。

フォーム入力後ボタンをクリックすると、サーバ処理は正常に完了するものの、画面がリロードされfetch の処理が途中で中断し、画面遷移に失敗した。

一方で、なぜかフォーム未入力時はリロードがされずにfetch が正常動作し、画面遷移に成功していた。

# 問題の原因
ボタンが`<button type="submit">`であるため、デフォルトのフォーム送信（submit イベント）が発生し、ページリロードが行われた。

入力がある場合、HTMLフォームは正常な送信条件を満たすため、fetch中でもリロードが優先されfetch処理が中断された。

一方で、ボタンにrequiredを付与していたため、未入力時はバリデーションエラーにより、デフォルトのフォーム送信がブロックされ、リロードが防がれたため fetch が完了していた。

ブラウザ側では処理が途中で途切れるが、すでにサーバにはリクエストが届いているため、サーバ側では処理が正常に完了している。

# 解決方法
方法1: event.preventDefault() でデフォルト送信を無効化

方法2: type="submit" を type="button" に変更することで、デフォルトのフォーム送信を防ぐ。

# 技術的な学び
#### フォームのデフォルト動作に注意
`<button type="submit">`は意図せずページ遷移やリロードを引き起こす可能性がある。
TypeScript型定義からJSONスキーマへの変換方法

TypeScriptを使っていて、型定義をJSONスキーマに変換したいなという場面がありました。この記事では、TypeScriptの型定義からJSONスキーマを生成するための主要な方法について解説します。

## はじめに：TypeScript型からJSONスキーマへの変換が必要になるとき

TypeScriptの型定義は、開発時にコードの型安全性を確保するための強力なツールです。一方、JSONスキーマは、JSONデータの構造を検証するための標準的な仕様です。以下のような場面で、TypeScript型からJSONスキーマへの変換が役立ちます：

- APIのリクエスト/レスポンスの検証
- フォームデータのバリデーション
- データベースのスキーマ定義
- 設定ファイルの検証

## 変換方法の選択肢

TypeScript型からJSONスキーマへの変換には、主に3つの方法があります。それぞれの特徴を見ていきましょう。

### 1. typescript-json-schema：シンプルで軽量な選択肢

typescript-json-schemaは、基本的な機能に特化した軽量なツールです。小規模なプロジェクトや、シンプルな型定義の変換に向いています。

インストールは以下のコマンドで行います：

```bash
npm install typescript-json-schema --save-dev
```

基本的な使用例：

```typescript
// ユーザー情報を定義する型
interface User {
  name: string;        // ユーザー名
  age: number;         // 年齢
  email?: string;      // メールアドレス（省略可能）
}

// コマンドラインでの変換実行
// npx typescript-json-schema ./src/types.ts User --out schema.json
```

生成されるJSONスキーマ：

```json
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "name": {
      "type": "string"
    },
    "age": {
      "type": "number"
    },
    "email": {
      "type": "string"
    }
  },
  "required": ["name", "age"]
}
```

### 2. ts-json-schema-generator：より完全な機能を持つ選択肢

ts-json-schema-generatorは、より多くの機能を備えた本格的なツールです。複雑な型定義や大規模プロジェクトでの使用に適しています。

インストール方法：

```bash
npm install ts-json-schema-generator --save-dev
```

JavaScript/TypeScriptでの使用例：

```typescript
import { createGenerator } from 'ts-json-schema-generator';

// 設定オブジェクトの準備
const config = {
  path: './src/types.ts',  // 型定義ファイルのパス
  type: 'User',            // 変換したい型の名前
  jsDoc: true             // JSDocコメントを含める
};

// スキーマの生成
const generator = createGenerator(config);
const schema = generator.createSchema(config.type);

console.log(JSON.stringify(schema, null, 2));
```

### 3. オンラインツール：手軽に試せる選択肢

ちょっとした変換や、ツールの動作確認には、オンラインの変換ツールも便利です。

Transform.tools（https://transform.tools/typescript-to-json-schema）を使用すると、ブラウザ上で直接変換が可能です。以下のような特徴があります：

- 即座に結果が確認できる
- インストール不要で手軽に使える
- 小規模な変換に最適

## ポイント

TypeScript型からJSONスキーマへの変換を効果的に行うために、以下のポイントに気をつけると良いでしょう：

1. **型の制約を理解する**
   変換ツールでは扱えない複雑な型（例：条件付き型）があります。必要に応じて型定義をシンプルにすることをお勧めします。

2. **生成されたスキーマの確認**
   自動生成されたスキーマは、必要に応じて調整が必要かもしれません。以下の点を確認しましょう：
   - 必須フィールドの設定
   - 型の正確性
   - 追加したいバリデーションルールの有無

3. **パフォーマンスへの配慮**
   大規模なプロジェクトでは、型定義の変換に時間がかかることがあります。ビルドプロセスの一部として組み込むかどうかは、慎重に考慮したほうがよさそうです。

## まとめ

TypeScript型からJSONスキーマへの変換は、選択肢の1つとして覚えておくと開発プロセスを効率化するテクニックになるかもしれません。ただ自動化するとデメリットもあることも判断材料として注意しておきたいですね。

- 小規模プロジェクト → typescript-json-schema
- 大規模/複雑なプロジェクト → ts-json-schema-generator
- 試験的な変換 → オンラインツール

## 参考資料

- [typescript-json-schema NPMページ](https://www.npmjs.com/package/typescript-json-schema)
- [ts-json-schema-generator GitHub](https://github.com/vega/ts-json-schema-generator)
- [JSONスキーマ公式ドキュメント](https://json-schema.org/)
ローカルで動くGPUを利用した簡易的な画像生成Webアプリを作ってみた

# はじめに
今回、以前から興味のあった画像生成Webアプリを作ってみました。

# どのようなものにするか
以下はぼんやりと思い描いた設計イメージ。
・入力フォームにプロンプトとネガティブプロンプトを入力する。
・生成ボタンを押すとその下に生成した画像が表示される。
・huggingface のモデルIDを画面で入力して切り替えられるようにする。
・GPUを利用して生成できるようにする。←最重要ポイント

 
# Webアプリのベース作成
AIに要件を伝えてWebアプリのベースを作成しました。
すると以下のような画面が作成できました。
![スクリーンショット (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3997332/61f79b30-5337-cb46-48d6-9439a8a3440b.png)
ひとまずUIは自分の思い描いたものに！

 
# 肝心なGPUの有効化がうまくいっていなかった件
いざ画像を生成しようとしてみたところやたら時間がかかります...
モニタリングソフトを見てもGPU使用率が全く変わっておらず...



# CUDAツールキットの導入
原因を調べたところNVIDIAが配布しているCUDAツールキットを導入する必要があったみたいです。
![スクリーンショット (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3997332/b8daa920-1651-165c-9548-12de930839a8.png)

　
CUDAツールキットを導入してみたところ無事にGPUを利用した画像生成が有効になり速度が大幅に速くなりました！
以下は実際に作成してみた画面で大体７秒ほどで生成できました
![スクリーンショット (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3997332/7cb7f886-6f13-f7c8-9383-ba401192ee17.png)

 　
# まとめ
ということで無事目的は達成したのですがあくまで簡易的なものになるのでここからカスタマイズして機能追加などしていきたいと思います！
転ドラで2回転職した話

こんにちは、イロハと言います。
この記事では私が転職ドラフトを利用して転職をした話をしたいと思います。

## はじめに

こちらの記事は転職ドラフトスカウト体験談投稿キャンペーンに参加しています
キャンペーンページ: https://job-draft.jp/articles/251
## 前提
私について、自己紹介。
エンジニア歴は今年でちょうど10年になります。
大学時代は情報系どころか理系でもなく、文系でした。カナダへ1年留学して凍えてたりしてました（寒かった記憶しかない）。
エンジニアとしての主戦場はバックエンドですが、今までジョインしたチームは大きいところは少なく、フロントやインフラもちょこちょこ触ってるような感じです。

趣味：最近はポケポケをやっています。元々カードゲームが好きで、今は春リリース予定のシャドバに期待を寄せてます。

## 転職活動
転職活動について。転職活動は2024年の6月頃から始めて、半年程度かけて転職活動をしていました。
転職においてはメインは転職ドラフトを使っていました。

## 2回目の転職ドラフト
なぜ、転職ドラフトかというと、実は数年前に転職したのですがその時も転職ドラフト経由でした。
そしてそのときに大幅な年収アップを実現できたので、かなり転職ドラフトに好感を持っていました。なので、今回は初めから転職ドラフトをメインにしようと思っていました。

私にとって転職ドラフトの良いと思ってるのは、基本的にこちらの年収を開示する義務がないところです。ルールに沿って会社側から確認してくるのはアリなのですが、転職ドラフトで面接に進んだ企業の中で年収を聞いてくるところは少数派でした（いるにはいましたが）。

なぜ年収非開示が良かったかというと、1回目の転職活動時は新卒としてエンジニアになったのは良いものの、正直年収が良いとはとても言えませんでした。一般的な転職サイト経由では、現在の年収を考慮されてしまうので、どうしても年収の天井にぶち当たってしまう状態に陥っていたのです。実際、内定をいただいた会社から提示いただいたのは（当時の年収からすれば妥当ではあるものの）満足行くような提示をいただけなかったです。

一方で、転職ドラフトを利用したことで、年収に縛られないオファーをいただけるので本当にありがたかったです。90%ルールがあり、10%以上スカウト時の提示年収より内定オファー年収が下がることがないのは安心材料でした。もっとも、私は基本的にはスカウト時の提示年収の9割を実質的な提示年収として見てました（期待して下がった時悲しいので）


### 6月 ~ 10月
まずは転職ドラフトでドラフトに参加するため、レジュメの継ぎ足しや書き直しをしました。
とりあえずと出た6月回で、前回よりもさらに高額な提示をもらいました。これは普通に嬉しかったし自信にもなりました。
また、転職ドラフトをメインにするといったものの他の転職サイトも利用しました（主にはGreenやLapras）
ちなみに7月回も一応ドラフトに参加したのですが、直近の6月回に出てるしスカウトなんて来ないだろうと思ったら、すごい来てビビり散らかしてました。

ただ、この頃は非常に仕事が忙しく、面談・面接を月に1度ペースでしかできておらずこの頃にオファーをくれた会社の面談が一通り終わったのは10月半ばくらいでした（4ヶ月くらい面接に時間かけてました）。

### 10月 ~ 12月
7月回で指名を受けたところの最終面接があり、なんか雑談してたら内定をもらえました。ただ、この時に無理を言って内定受諾を待って欲しいとお願いし、転職活動は続けました。その後、転職ドラフト以外のサイトでもらったオファーなどを中心に受けて、内定をもう1社もらいました。


### 1月
結局、内定をもらった2社で迷いに迷った挙句、最初に内定をいただいたところに決めました。それならその時に決めておけよという感じですが、私自身転職活動をやり切ったという感じになれたのでここまでやって良かったと思っています。

決めた理由はいろいろありますが、面白そう、成長しそう、いろいろ体験 & 挑戦できそうって感じられたところですね、

ここでようやく実際のオファーをいただいのですが、転職ドラフトで最初に提示されていたオファー金額よりさらに高くなってたいので、だいぶ驚きました（正直90%程度だろう、みたいな諦観みたいなのがありましたので）。


## 最後に
年収の話ばかりになった気がしますが、個人的には年収や待遇はあれば嬉しいですが、何よりも楽しそうな会社に内定をいただけたのがいちばんの収穫かなと思っています。
個人的な備忘録：FQDN（Fully Qualified Domain Name）について、DNSとの関係から実際の取得方法まで説明してみた

## はじめに
インターネットを利用する中で、私たちは日々「`www.google.com`」や「`yahoo.co.jp`」といったドメイン名を目にしています。

:::note info
**これらのドメイン名の中でも、ホスト名を含んだ完全な形のものを FQDN（Fully Qualified Domain Name、完全修飾ドメイン名） と呼びます。**
:::

FQDNはネットワーク管理やサーバー運用に欠かせない概念であり、特にインフラエンジニアにとっては基本知識の一つです。

本記事は個人的な備忘録としてまとめたものです。***その点をご理解いただければ幸いです。***

## 書こうと思ったきっかけ
実務でDNSを扱う機会が多く、それに伴いFQDNについても深く学んできました。

:::note warn
***私自身、最初は全く理解できませんでしたが、仕組みを知ることで「**なるほど、こういうことだったのか**」と納得できるようになりました。***
:::

今回、学んだことを整理し、自分自身の振り返りの機会とするために、この記事としてアウトプットすることにしました。

## FQDNとは？
FQDN（Fully Qualified Domain Name、完全修飾ドメイン名）は、インターネット上の特定のホスト（コンピュータやサーバー）を一意に識別するための完全なドメイン名のことです。

![Screenshot 2025-01-29 at 22.31.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/fd184efb-ec8a-64e8-fc72-f487f20902d8.png)
引用画像：https://www.kagoya.jp/howto/it-glossary/domain/fqdn/

単に「ドメイン名」と言う場合もありますが、FQDNはより詳細な指定を含んだ形です。

## FQDNの構造
FQDNはドット（`.`）で区切られた複数の部分（ラベル）で構成されます。

**一般的な形式：**

```css
[ホスト名].[ドメイン名].[トップレベルドメイン]
```

**具体例**

`www.example.com`

- **www** → ホスト名（サーバーの名前）
- **example** → ドメイン名
- **com** → トップレベルドメイン（TLD）

### FQDNとその説明

ホスト名だけではネットワーク内の他のホストと区別しにくいですが、FQDNを使うことでグローバルに一意な識別が可能になります。

| FQDN               | 説明                      |
|--------------------|-------------------------|
| www.google.com    | Googleのウェブサイト     |
| mail.yahoo.co.jp  | Yahoo! Japanのメールサーバー |

## 実際に端末のFQDNを取得してみた

システムで自分のFQDNを確認するには、以下のコマンドを使用できます。

### **Linux/macOS**

```bash
hostname -f
```

**実際のコマンド結果**

```bash
➜  ~ hostname -f
MacBook-Pro.local
```

### **Windows（コマンドプロンプト）**

```cmd
echo %COMPUTERNAME%
```

**実際のコマンド結果**

```cmd
C:\Users\user>echo %COMPUTERNAME%
HONDA-WINDOWS11
```

## FQDNとDNSの関係
FQDNはDNS（Domain Name System）を使ってIPアドレスと対応付けられます。たとえば、`www.example.com` はDNSサーバーを介して `93.184.216.34` というIPアドレスに変換されます。

***FQDNはネットワーク管理やサーバー運用において重要な概念なので、理解しておくと役立ちます！***

## まとめ

最後までお読みいただき、ありがとうございました。基本的な内容でしたが、丁寧に振り返ることで、より深く記憶に定着させることができました。

:::note info
***FQDNはDNSと密接に関わる概念であり、私自身も今後、積極的に活用していきたいと考えています。***
:::

今回のまとめが、どなたかの技術の支えとなれば幸いです。
Dockerにおけるポートの考え方

Dockerを使うと、「コンテナ」という仮想的な環境の中でアプリケーションを動かせます。ただし、コンテナの中は**外の世界（PCやインターネット）から直接アクセスできません**。そこで重要になるのが**ポート**の考え方です。

## 1. ポートって何？
「ポート」とは、コンピュータの**入り口・出口**のようなものです。
例えば、

- Webサイト（HTTP）は通常「80番ポート」
- Webサイト（HTTPS）は「443番ポート」
- データベース（MySQL）は「3306番ポート」
というように、それぞれ特定の番号のポートを使って通信します。

## 2. Dockerコンテナのポートとは？
コンテナの中には、アプリケーション（Webサーバーやデータベース）が動いています。でも、このままだと外部（PCやインターネット）からアクセスできません。そこで、**コンテナのポートと、ホスト（PC）のポートをつなぐ**（ポートマッピング）ことで、外部からアクセスできるようになります。

## 3. ポートマッピングとは？
例えば、DockerでWebサーバーを動かすときに、コンテナ内では80番ポートを使っているとします。でも、PC（ホスト側）のポートとつながっていなければ、外部からは見えません。

そこで、次のように「ホストの8080番」と「コンテナの80番」をつなげます。
~~~ruby:sh
docker run -p 8080:80 my-web-app
~~~
すると、

- コンテナの80番ポート（Webサーバー）
- PCの8080番ポート
がつながり、ブラウザで `http://localhost:8080` にアクセスすると、コンテナ内のWebサイトが見られるようになります。

## 4. `-p` の書き方と意味
ポートを指定するには、`-p ホスト側ポート:コンテナ側ポート` の形式を使います。

**よく使う例**
~~~ruby:sh
docker run -p 8080:80 my-web-app
~~~
👉 ホストの8080番 → コンテナの80番へつなぐ

~~~ruby:sh
docker run -p 3306:3306 my-database
~~~
👉 ホストの3306番 → コンテナの3306番（MySQLデータベース）

**ポートを変えたい場合**
~~~ruby:sh
docker run -p 5000:80 my-web-app
~~~
👉 ホストの5000番 → コンテナの80番へつなぐ（`http://localhost:5000` でアクセス）

## 5. Docker Compose でのポート設定
複数のコンテナを管理する `docker-compose.yml` でも、ポートを指定できます。

~~~ruby:yaml
version: '3'
services:
  web:
    image: my-web-app
    ports:
      - "8080:80"
  db:
    image: mysql
    ports:
      - "3306:3306"
~~~
👉 Webアプリは `http://localhost:8080` でアクセス可能
👉 MySQLは `localhost:3306` で接続可能

## 6. まとめ
- **ポートはコンピュータの入り口・出口**
- **Dockerコンテナは外からアクセスできないので、ポートを開ける必要がある**
- `-p ホスト側:コンテナ側` でポートをマッピング
- `docker-compose.yml` でも設定可能
これを理解すると、Dockerのアプリを外部から利用できるようになります！
--spring.output.ansi.enabled=always が実行できないジョブです。

＃　経緯
Eclipseにおいて、Springbootでバッチを実行しようとした際にタイトルのエラーメッセージがコンソールに出力されて、実行できなかったため、解決方法を記載する。

＃ Ver情報
Springboot　2.6.4
Java 17
Eclipse 2024

対応方法
**ANSIコンソール出力のチェックを外すと解消された。**

![image (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3633053/2d885159-6590-8efc-f1c4-6d6d92912ce7.png)


上記画像の状態で実行すると、バッチが正常に実行された。
DDDにおけるエンティティ・値オブジェクト・リポジトリ・サービスの役割と棲み分け

## 1. DDD（ドメイン駆動設計）とは？
DDD（Domain-Driven Design、ドメイン駆動設計）は、複雑なビジネスロジックを扱うシステムを効果的に設計する手法です。特に、開発者とビジネス側が共通の認識を持ち、保守性や拡張性を向上させることを目的としています。

## 2. エンティティと値オブジェクトの違い
### **エンティティ（Entity）**
エンティティは **一意の識別子（ID）を持ち、状態が変化するオブジェクト** です。
#### **特徴**
- **IDを持つ**（同じIDなら同じエンティティとみなす）
- **状態が変化する**（例: 注文の状態が「支払い待ち」→「配送中」→「完了」）
- **等価性の判断はIDで行う**

#### **例（Java）**
```java
public class User {
    private final Long id;
    private String name;
    private String email;

    public User(Long id, String name, String email) {
        this.id = id;
        this.name = name;
        this.email = email;
    }

    public void changeEmail(String newEmail) {
        this.email = newEmail;
    }

    public Long getId() {
        return id;
    }
}
```

### **値オブジェクト（Value Object）**
値オブジェクトは **IDを持たず、不変（Immutable）な値を表すオブジェクト** です。
#### **特徴**
- **IDを持たない**（同じ値なら等しいとみなす）
- **不変（Immutable）**（変更不可、変更する場合は新しいオブジェクトを作成）
- **等価性はすべてのフィールドの値で判断**

#### **例（Java）**
```java
public class Money {
    private final BigDecimal amount;
    private final String currency;

    public Money(BigDecimal amount, String currency) {
        this.amount = amount;
        this.currency = currency;
    }

    public Money add(Money other) {
        if (!this.currency.equals(other.currency)) {
            throw new IllegalArgumentException("通貨が異なるため加算できません");
        }
        return new Money(this.amount.add(other.amount), this.currency);
    }
}
```

## 3. 値オブジェクトとドメインサービスの棲み分け
### **値オブジェクトに入れるべき処理**
- 値そのものの操作（例: `Money.add()`）
- そのオブジェクトの性質に関わる処理
- 不変であるべき処理

### **ドメインサービスに入れるべき処理**
- 複数のエンティティ・値オブジェクトを組み合わせる処理
- 外部データを参照する処理（例: 為替レート取得）
- あるエンティティの責務として持つのが不自然な処理

#### **例: 通貨変換（ドメインサービス）**
```java
public class ExchangeRateService {
    private final ExchangeRateRepository exchangeRateRepository;

    public ExchangeRateService(ExchangeRateRepository exchangeRateRepository) {
        this.exchangeRateRepository = exchangeRateRepository;
    }

    public Money convert(Money from, String targetCurrency) {
        if (from.getCurrency().equals(targetCurrency)) {
            return from;
        }
        BigDecimal rate = exchangeRateRepository.getRate(from.getCurrency(), targetCurrency);
        BigDecimal convertedAmount = from.getAmount().multiply(rate);
        return new Money(convertedAmount, targetCurrency);
    }
}
```

## 4. リポジトリとサービスの棲み分け
### **リポジトリ（Repository）の役割**
- データの永続化（保存・取得）
- データベースアクセスのカプセル化
- CRUD操作のみ（ビジネスロジックは持たない）

### **ドメインサービス（Domain Service）の役割**
- ビジネスロジックを実装
- 複数のエンティティや値オブジェクトを操作

### **アプリケーションサービス（Application Service）の役割**
- ユースケースを管理
- トランザクション管理
- DTO変換（クライアントとのデータ変換）

## **まとめ**
DDDでは、エンティティ、値オブジェクト、リポジトリ、ドメインサービス、アプリケーションサービスがそれぞれ異なる役割を持ちます。適切な責務分離を行うことで、保守性・拡張性の高いシステムを構築できます。

- **エンティティ** はIDを持ち、状態が変化するオブジェクト。
- **値オブジェクト** はIDを持たず、不変な値の概念を表す。
- **リポジトリ** はデータの永続化を担当し、ビジネスロジックを持たない。
- **ドメインサービス** は複数のエンティティをまたぐビジネスロジックを管理する。
- **アプリケーションサービス** はユースケースの流れを管理し、リポジトリやドメインサービスを調整する。

これらの設計原則を意識することで、システムがスケーラブルかつ理解しやすくなり、変更に強い構造を実現できます。
何も考えずにmecab-ipadic-neologdのビルドを高速化する

たぶん、日本人は過半数はmecab-ipadic-neologd のビルドに２０分近くかかることに悩んでいると思うので対応しました。

https://github.com/hisashi-ito/mecab-ipadic-neologd

もし、ビルド時間が遅くて困っている方がいらっしゃご利用してもらってもいいかも。
基本、公式の未マージの 

https://github.com/neologd/mecab-ipadic-neologd/issues/84

に関してフォークして修正しただけです。


参考元：
こちらの記事を参考にさせていただきました。ありがとうございます。

https://qiita.com/padawan_e15/items/6152144c3411941ced08
メールアドレスの企画を見返す用の記事(備忘録)

## 下記はAIの解説
Q、「規格外の長さのメールアドレスを許容すると不都合なこと起きますか？」

1.データベースの制約


- 多くのDBでは VARCHAR(255) でメールアドレスを格納
- 長すぎるメールアドレスはDBの制約に違反
- データ切り捨てやエラーの原因に


2.RFC標準への非準拠


- メールアドレスの標準仕様(RFC 5321)では:

  - ローカル部（@前）: 最大64文字
  - ドメイン部（@後）: 最大255文字


- 標準外のアドレスはメール送信時に問題発生


3.セキュリティリスク


- 異常に長いメールアドレスはバッファオーバーフローの原因に
- SQLインジェクションなどの攻撃ベクトルとして使用される可能性

## 参考記事
https://qiita.com/yoshitake_1201/items/40268332cd23f67c504c
cloudflare workersにデプロイするRemixプロジェクトを作成する

## 概要

Cloudflare Workersにデプロイする、Remixプロジェクトを作成する方法をまとめる。

## 前提

Cloudflareのアカウントを持っていること。
ローカルPCでnpxコマンドが実行できること。
Cloudflare Workersにデプロイするところまでを本記事では記載し、「エンドポイントにリクエストを送る」などの作業は別の記事に記載する。

## 方法

1. 下記を実行してRemixのプロジェクトを作成

    ```sh
    npx create-remix@latest deploy_cloudflare_workers --template remix-run/remix/templates/cloudflare-workers
    ```

1. 作成されたdeploy_cloudflare_workersのディレクトリに移動し下記を実行

    ```sh
    npm run dev
    ```

1. 表示されたURLにアクセスし、問題なく画面が出ることを確認
1. 下記を実行してwrangler.tomlというファイルを作成（Cloudflare Workersのプロジェクト設定ファイル）

    ```sh
    npm run typegen
    ```

1. wrangler.tomlというファイルが作られているはずなので展開し、nameの値を`name = "deploy_cloudflare_workers"`に変更し、再度下記コマンドを実行

    ```sh
    npm run typegen
    ```

1. 下記を実行してデプロイ（おそらく実行するとブラウザが勝手に立ち上がり、Cloudflareへのログインを求められる。ログインしてAllowをクリック）

    ```sh
    npm run deploy
    ```

1. 別のブラウザのタブでCloudflareにログイン
1. 「deploy_cloudflare_workers」というアプリがWorkersにデプロイされていることを確認、デプロイできていることが確認できたので完了

    ![CleanShot 2025-01-29 at 22.23.52@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/833d2522-d745-3283-0f3e-ba90abb85937.png)


## 参考文献

https://remix.run/docs/en/main/guides/deployment

https://remix.run/docs/en/main/other-api/create-remix#create-remix