OmniAICreator/Qiita-1.07M huggingface dataset:
【TypeScript】type-challenges 中級編 8・Readonly 2 解説

## お題
`K`が指定されている場合、オブジェクト型`T`の中の`K`のプロパティのみを読み取り専用にし、`K`が指定されていない場合、通常の`Readonly<T>`と同様に、すべてのプロパティを読み取り専用にする型`MyReadonly2`を実装する。

## やりたいこと
```ts
interface Todo {
  title: string
  description?: string
  completed: boolean
};

type Expected = MyReadonly2<Todo, 'title' | 'description'>;

interface Expected {
  readonly title: string
  readonly description?: string
  completed: boolean
};
```

## 解答
```ts
type MyReadonly2<T, K extends keyof T = keyof T> = {
  readonly [P in K]: T[P]
} & {
  [P in keyof T as P extends K ? never : P]: T[P]
};
```

## 解説
### 処理の流れ
- `<T, K extends keyof T = keyof T>`
  - `K`に入る値を、`T`のプロパティのみに制約
  - **default value**を使用し、`K`が指定されない場合は`keyof T`が割り当てられる
  （`K`が指定されない場合に、すべてのプロパティが読み取り専用になる）
- `{ readonly [P in K]: T[P] }`
Mapped Typesを使用し、`K`のプロパティのみの読み取り専用オブジェクトを作成。
- `{ [P in keyof T as P extends K ? never : P]: T[P] }`
Mapped Typesと`as`を使用し、元の型を保持した`K`以外のプロパティのオブジェクトを作成。
- `{...} & {...}`
インターセクション型（&）を使用し、オブジェクトを合成する。

### default valueとは...
:::note info
**引数が`undefined`のとき、代わりの値を指定できる**
JavaScriptは引数を省略すると、`undefined`が返される。
```ts
// 書き方
function 関数名(引数 = デフォルト値) {}

// 型注釈を入れる場合
function 関数名(引数: 型 = デフォルト値) {}
```
:::

### インターセクション型（&）とは...
**合成したいオブジェクト同士**を`&`で列挙することで、インターセクション型を作る。
```ts
type A = { name: string };
type B = { age: number };

type AB = A & B; // { name: string; age: number; }
```
:::note warn
**プリミティブ型のインターセクション型**
`never`が返される。
```ts
type Never = string & number; // never
```
:::

### keyof演算子とは...
https://qiita.com/yuto99999/items/dcc234f3e25a5393a2ab#keyof%E6%BC%94%E7%AE%97%E5%AD%90%E3%81%A8%E3%81%AF

### Mapped Typesとは...
https://qiita.com/yuto99999/items/dcc234f3e25a5393a2ab#mapped-types%E3%81%A8%E3%81%AF

### Mapped Typesにおける「as」とは...
https://qiita.com/yuto99999/items/8557d13e24cd132f6ef2#mapped-types%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8Bas%E3%81%A8%E3%81%AF

## 参考記事
### default value
- [デフォルト引数 | TypeScript入門『サバイバルTypeScript』](https://typescriptbook.jp/reference/functions/default-parameters)

### インターセクション型
- [インターセクション型 | TypeScript入門『サバイバルTypeScript』](https://typescriptbook.jp/reference/values-types-variables/intersection)

## 今回の問題
https://github.com/type-challenges/type-challenges/blob/main/questions/00008-medium-readonly-2/README.ja.md
コールバック関数について

## はじめに
コールバック関数という言葉はよく耳にするのですが、詳しくは知りませんでした。
そのため、調べた結果をここでアウトプットしたいと思います。

## コールバック関数とは

一言で表すと**引数として渡す関数のこと**です。

　
詳しく説明します。

- 関数とは
    - 何かあげると何かしらを返してくれる処理の塊のこと
- 引数とは
    - 関数にあげるもののこと
- 戻り値とは
    - 関数から返ってくるもののこと



### (例題) Aさんはもらった数字に＋5をします。そんなAさんに数字の3をあげたら、8が返ってきました。

この文だと

引数：3
関数：Aさん
戻り値：8
になります。

Aさん(引数に5を足し、その結果を戻り値として返すという処理)に引数3を渡し、戻り値として8が返ってきたというわけです。
　

### (例題) 自動卵焼き機と卵をシェフにあげると卵焼きが返ってきた

この文だと

引数：
・自動卵焼き機
・卵

関数：シェフ
戻り値：卵焼き
になります。

この**自動卵焼き機**がコールバック関数になります。
普通、引数には数字や文字などが渡されますが、今回は自動卵焼き機と卵が渡されました。
自動卵焼き機には処理があります。そんな処理が書いてあるものをシェフにさらに処理(動かす)してもらいます。


 　
### 最後に
このように何かの処理の中でさらに処理を動かしたいときにはコールバック関数を利用します。
Ubuntu22.04へのTeXのインストール（したこと）

# TeXのインストール（ubuntu22.04）

## はじめに

どうもburidaikonです。12月になって一段と寒くなってきましたね。
今回は、ubuntuにTeXをインストールする際にしたことを備忘録として書きました。
素人が適当なこと言ってるだけなので、あまり気にしないでください。

## やったこと

**➀コマンド**
**➁進捗が止まる**
**➂（止まったら）連打**

➀コマンド
```command
$ sudo apt update
$ sudo apt install texlive-full
```

➁進捗が止まる

おそらくインストール後の展開をしているところで処理が止まる（？）と思います。（私は写真の状態で止まって、丸1日放置しても全然変化がありませんでした。）

![スクリーンショット 2024-12-14 182959.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618170/81c62cf2-60f1-24bb-ef59-5d23f31e6178.png)

➂（止まったら）連打

私と同じように固まったそこのあなた！
エンターキーを連打しましょう

それだけでOKです

ほらね
![スクリーンショット 2024-12-15 004829.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618170/1e8b7ac6-c119-d352-4624-1b88903e9092.png)

とりあえずこれでubuntuへのインストールは完了です。
GitHubでブランチの命名規則を制限する方法

GitHubでチーム開発をしていると、ブランチ名がバラバラで管理が大変になることがありますよね？そんなときに役立つのが、**ブランチの命名規則を制限する機能**です！今回は、この設定方法やメリットについて、具体例を交えながら紹介します。

## ブランチ命名規則を制限するには？

GitHubでは、リポジトリの「ブランチルールセット」を設定することで、特定のパターンに従わないブランチ名の作成を防ぐことができます。

以下の手順で設定を行います：

リポジトリの Settings > Branches を選択し、Add branch protection rule から以下のように設定します。

![スクリーンショット 2024-12-18 23.54.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9872/92e56c58-b8aa-7051-a3de-f79be8f30cf2.png)

Branch targeting criteriaには「**作成させたくないブランチ名を対象**」に指定する必要があるので、上記画像のように「全部のブランチが対象！でもdevelop-*とかfeature/**/*みたいにいつも作ってるブランチ名は制限しないでね！」とする必要があります。

また画像の最後にある「Restrict creations（作成を制限する）」にチェックを入れる事も忘れないでくださいね！

これにより、指定されたルールに違反する名前のブランチは作成できなくなります。

### パターン設定の具体例

**Exclude pattern**や**Branch name pattern**では、以下のようにワイルドカード（`*`や`**`）を使うことができます。

#### 例1: `develop-*`をExclude patternに設定した場合

`develop-`から始まるブランチ名が作成可能ですが`/`を含める事は出来ません。

- 作成可能なブランチ名
  - `develop-test`
  - `develop-123`
- 作成不可なブランチ名
  - `develop-test/hoge`
  - `test-develop-123`



#### 例2: `feature/**/*`をExclude patternに設定した場合

`feature/`から始まるブランチ名が作成可能です。`/`を含める事も可能です。


- 作成可能なブランチ名
  - `feature/new-feature`
  - `feature/subdir/task`
- 作成不可なブランチ名
  - `test-feature/123`
  - `feature-123`

:::note info
ポイント
- `*`: 任意の文字列（スラッシュを含まない）
- `**`: 任意の文字列（スラッシュを含む）
:::

#### 例3: `feature-*/**/*`をExclude patternに設定した場合

`feature-`から始まり、最低１回は`/`を含めたブランチ名が作成可能です。

- 作成可能なブランチ名
  - `feature-123/test`
  - `feature-test/hoge/fuga`
- 作成不可なブランチ名
  - `feature-123`
  - `test-feature-123/123`

これでだいたいの設定ルールは網羅できたんじゃないでしょうか？

## ブランチ名の制限を設けるメリット

では、なぜブランチ名に制限を設けるべきなのか？あくまで私基準で理由を書いておきます。

### 1. 開発フローの統一
バラバラなブランチ名だと、どのタスクがどのブランチに紐付いているか分からなくなります。命名規則を設定することで、統一感が生まれ、プロジェクト全体の見通しが良くなります。

### 2. Four Keysの指標を正確に取得
[Four Keys](https://cloud.google.com/blog/ja/products/gcp/using-the-four-keys-to-measure-your-devops-performance)（デプロイ頻度、リードタイム、変更失敗率、MTTR）を計測する際、規則的なブランチ名が重要です。これにより、CI/CDパイプラインや分析ツールで正確なデータが取れるようになります。

### 3. ミスを防ぐ
意図しないブランチ名の作成を防ぎ、誤ったブランチにコミットしてしまうリスクを低減します。

## まとめ

GitHubのブランチ命名規則を制限することで、チーム開発の効率と品質を向上させることができます。正確な分析結果をもってKPTを回すためにも普段から観測できる状態にしている事はとても重要な事です。
実際の運用で試してみて、より良い開発環境を構築してみてください！
PHP で YouTube チャンネル登録者数カウンターを作る

## QSL4A でのリアルタイム取得に失敗したので
[QPython で GUI プログラミング2（YouTube チャンネル登録者数カウンターを作る：未完）](https://qiita.com/harycurl/items/29c271d7c09d3855116f) が失敗に終わったので、今度は PHP を使って YouTube チャンネル登録者数カウンターを作ることにした。

## Composer のインストール
YouTube API の PHP モジュールを使う場合、 Composer を使う必要があるようだ。
Termux には Composer が無いのでインストールする。 
```
The program composer is not installed. Install it by executing:
 pkg install composer
```
とエラーメッセージが出るけど、どう考えても罠っぽい（composerと名の付くパッケージは別物だろう）ので調べると以下のサイトでインストール方法が解説されていた。

https://itrendbuzz.com/install-php-composer-on-termux/

## YouTube チャンネル登録者数を取得する
あとはこのあたりを参考にすればよさそうである。

https://qiita.com/gentsuki/items/dfd9f4febaec11851c06

そもそも Composer を使わない方法もあった。こちらでもいい？

https://alluka.net/faq/youtube/faq01.html

下の方法だと、 `$response["items"]["0"]["statistics"]["subscriberCount"]` にチャンネル登録者数が入るので、あとは [PHP を雑に書いて Web 情報取得（株価指数を大きな文字で表示）](https://qiita.com/harycurl/items/d9cd0e98bfe4ee8de175) と同じように拡大表示させればよい。

## 完成形
```PHP: youtube_counter.php
<html>
<head>
<meta http-equiv="refresh" content="20">
<style type="text/css">
.header {
font-size: 50px;
text-align: right;
line-height: 2em;
}
.subcount {
font-size: 250px;
font-weight: bold;
text-align: center;
line-height: 1.8em;
}
</style>
</head>
<?php
define('YOUTUBE_API_KEY', '((APIキー))'); 

function json_get($url, $query = array(), $assoc = false) { 
    if ($query) $url .= ('?' . http_build_query($query, '', '&', PHP_QUERY_RFC3986));

    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url); // URL
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);
    $responseString = curl_exec($curl);
    curl_close($curl);
    return ($responseString !== false) ? json_decode($responseString, $assoc) : false;
}

$response = json_get('https://www.googleapis.com/youtube/v3/channels', array(
    'key' => YOUTUBE_API_KEY,
    'id' => '((チャンネルID))', 
    'part' => 'statistics', 
), true);

echo '<div class="header">';
date_default_timezone_set('Asia/Tokyo');
echo date("Y/m/d H:i:s");
echo "<br></div>";
echo '<div class="subcount">';
echo $response["items"]["0"]["statistics"]["subscriberCount"];
echo "<br></div>";
?>
</html>
```
![php_counter_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3943774/80352fd3-d273-4012-27a0-b35db048a8a8.png)

更新間隔は `http-equiv="refresh" content="20"` の数字を秒数で設定すればよい。
ちなみに YouTube Data API v3 は 1日10000回までリクエスト可能（1つのチャンネルの登録者数の取得は1回分消費）のため、1つのチャンネルのカウンターのみとして使用するのであれば、数字上8.64秒に1回までは取得可能である。日界は太平洋標準時。
shutdownシステムアカウントが見事に本番サーバを停止させた

本番環境などでやらかしちゃった人 Advent Calendar 2024
19日目の記事です。

https://qiita.com/advent-calendar/2024/yarakashi-production

# 先に結論
本番サーバで安直に初めてのオペレーションを行ってはいけません。

# はじめに

10年以上前のある日、Linuxサーバの管理をしているとき『**shutdown**』ユーザーにスイッチしたところ、予期せぬ形で本番サーバが停止してしまいました。

## 背景

本番サーバを管理している際、偶然にも『shutdown』という名前のユーザーアカウントが存在していることに気付きました。初めて見た名前だったため、当時の若かりし私は躊躇なく興味本位でそのアカウントにスイッチを試みてしまいました。

## shutdownシステムアカウントとは？

昔は一般ユーザが容易にシャットダウンを行えるために（セキュリティ上その有効性には議論があるものの）『**shutdown**』というパスワード無しでログイン可能なアカウントが存在していました。

最近のディストリビューションにあるかは未確認ですが以下のようなRHELページもあるので、ログイン不可になっているものの存在しているかも？また、管理上あえて作成しているパターンもありそうです。

https://access.redhat.com/solutions/44682

## そして事件は起きた

私はログイン中のアカウントから次のようにして『**shutdown**』アカウントにスイッチしてみました。

```bash
su - shutdown
```

その直後、本番サーバがシャットダウンされ、サービスがすべて停止してしまいました（確か本番のDBサーバだったはず）。原因を調査した結果、『**shutdown**」アカウントはログインするとshutdownコマンドが実行されるように設定されていたためでした。

## 教訓、本番環境での操作は慎重に
本番サーバの操作に関しては、常に慎重でなければなりません。本番環境でのミスは、その影響が大きいため、事前に検証環境で試されている手順を踏むことが求められます。ましてや、興味本位でコマンドをたたくなどはもってのほかです。

# 改めて結論
本番サーバで安直に初めてのオペレーションを行ってはいけません。

# おまけ宣伝
今回、少しセキュリティに関係する話を書きましたが、セキュリティに関わるLT会を2025年1月23日に企画しています。
ご興味があれば是非、遊びに来てください。

https://security-any.connpass.com/event/336993/
Google Geminiを利用したソース解析に失敗した話

# はじめに
この記事では、GoogleGeminiが実際の開発で、
どのような用途でどれぐらい利用できるのか、ざっくり検証したものになります。
環境は、以下のとおりです。

| 環境 | 詳細 | 
| - | - |
| Gemini | Gemini Advanced | 
| 検証アプリケーション | Google Spreadsheet(GAS) | 

# 作業内容
以前技術合宿で作成したWEBアプリ(GAS&Spreadsheet)をGeminiさんに食わして、
ソース解析からスタートです。

## ソースの解析
### プロンプト
```
spreadsheetとGASのアプリを以前作成しました。
社内コンペで発表したいのですが、簡単に概要をまとめてもらえますか？
URLは以下です。
https://docs.google.com/spreadsheets/d/1Ye...
```
### 回答
```
このスプレッドシートとGASのアプリは、社内コンペの応募作品を管理し、審査プロセスを効率化するためのツールです。

主な機能
応募作品の一元管理: スプレッドシートに作品情報（作品名、応募者、カテゴリなど）をまとめて登録できます。
審査の自動化: GASを使って、審査員へのメール送信、採点結果の集計、点数に基づいたランキング作成などを自動化できます。
進捗状況の可視化: 現在の審査状況をスプレッドシート上で確認できます。

メリット
時間短縮: 審査プロセスを自動化することで、担当者の作業時間を大幅に削減できます。
…以下略
```
### 検証
おぉい、全然中身違うよ！何見て回答しているんだよ。
読み込ませたのは、
特定の地点を飛行中の航空機の位置情報などをAPIで取得して、
それの航空機の情報を画面に表示するWEBアプリケーションだよ。
絶対、URL先の中身見ていないだろ…

### プロンプト
```
え、URLの先をちゃんとみましたか？
```
### 回答
```
申し訳ありません。URLの先をきちんと確認せずに、一般的なスプレッドシートとGASのアプリの説明をしてしまいました。

改めてURLを確認したところ、これは「社内LT大会」の応募者と発表順を管理するためのスプレッドシートとGASのアプリですね。

主な機能

応募者の一元管理: スプレッドシートに応募者情報（氏名、所属、発表タイトルなど）をまとめて登録できます。
…以下略
```

### 検証
えぇぇ、ちゃんと中身見てないの、認めちゃったよこの人。
GAIなのにサボるってどういうことなの？
そして、改めてURLを確認したとか言いながら、
全然実際のソースとは異なる内容を回答を返してきましたよ。
だめじゃん。

### プロンプト
```
では、GASの中身について、処理をまとめてください
```
### 回答
```
分析が正常に完了しませんでした

Gemini に問題が発生しました
リクエストを処理できませんでした。プロンプトを書き変えて、もう一度お試しください。
```

### 検証
うん、プロンプトが悪いのかな。
念のため、再チャレンジ。

### プロンプト
```
もういっかい
```
### 回答
```
GAS（Google Apps Script）の中身について、処理をまとめますね。

このスプレッドシートでは、GASを使って以下の処理を行っています。

応募者の登録: スプレッドシートに入力された応募者情報を読み込みます。
発表順の抽選: shuffleArray()という関数で応募者のリストをシャッフルし、ランダムな発表順を生成します。
発表順のリスト出力: シャッフルされた応募者リストを別のシートに書き出します。
発表順の表示: 抽選結果をスプレッドシートの指定セルに表示します。
GASのコード例
```

### 検証
スタートから認識に齟齬がありそうですね。
私としては、「社内で説明するため」に「既存アプリの解析」を依頼したつもりが、
「社内説明をするため」に「GASでアプリを作る」話として、捉えられているようです。

# おわり
この作業で何も生まれなかったのですが、
やはりプロンプトが良くなかったのかなーという感触です。
ソースの渡し方も不親切だったのかな。
明日は、ソース直貼りした結果を検証してまいります。
年間5,000人の勉強会📚「パートさんDX」of AEON

本記事は、[AEON Advent Calendar 2024](https://qiita.com/advent-calendar/2024/aeon)の20日目記事です🎄🎅

https://qiita.com/advent-calendar/2024/aeon

こんにちは！AEONの中で細々とDXを推進する[おきなか](https://twitter.com/okinakamasayos1)です！
日本の小売業の就業者数はなんと735万人。9人に1人は小売業従事者で、我が巨大企業には**56万人が在籍**します。

https://dcri.jp/column/cl_no_4/#:~:text=%E5%B0%8F%E5%A3%B2%E6%A5%AD%E3%81%AE735%E4%B8%87,%E8%80%85%E3%81%A8%E3%82%82%E8%A1%A8%E7%8F%BE%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%80%82

この超BIG組織の中でDXを推進するにあたり、ものすごく大事だと思っていることがあります。それは…

## 主役は店舗のパートさん

ということです。
 
56万人のうち、**従業員の多くは「店舗スタッフ」**。レジ打ちから食品、衣料品の管理まで、店舗の業務は多岐にわたります。新入社員の多くも、まずは店舗に配属されます。
 そして店舗スタッフのほとんどは、いわゆるパートさん、アルバイトさん。1店舗の従業員が100名で、**正社員10名、90名がパートさんアルバイトさん**、というケースも決して珍しくありません。

## で、パートさんはDXに関わるべき…？

<br><br>

   <font color="Red">**です。**</font>

<br><br>


## 人が減り、好みは増える、そんな時代。

 一昔前、本部や社員が出した指示を現場のパートさんが実行することで、どんどん売上が伸びる時代がありました。「本部指示を正確に遂行」が売上向上の鍵で、人口が増加し続ける地域では、出店＝業績UPがまかり通っていました。

 しかし**人口が減り、情報が増え、好みが多様化**する中、**消費者に最も近い存在であるパートさんが果たす役割はめちゃくちゃ大きい**です。現場の中で日々の業務を通じ、直接お客さまと接し、声を聞き、時には自身がお客さまの一人として発言し、**改善のヒントは常にパートさんの中にある**といっても過言ではありません。

 DXにパートさんが関わるべき理由は、まさにここにあります。

 ## 超優秀テクノロジーも「使いません」だと効果ゼロ

 一方で、どれだけ素晴らしい技術やツールを本部が導入しても、現場で使われなければ全く意味がない。**パートさんが「とりあえずやってみよかなぁ～」と考え**、とにかく使い始めてもらうことが**最も重要**です。
変化の激しい時代だからこそ、マーチャンダイジングや業務効率化のPDCAなど、色々な実験検証をこれまで以上のスピードで回すべきで、過去は「正解」とされていた **「指示されたこと 慣れてることをやり続けます」をいかに打破するか** 、それこそが私の挑戦でもあります。

 ## 「これなら私もできるかも」先生も生徒も「従業員」

  2年前にDXを推進する部署に来た私は、**従業員自身が講師となり、自ら学んだスキルや、実際の業務改善や成功体験を共有する「社内勉強会」をスタート**させました。例えば、「Excelのこの機能を集計業務に使ったら、こんなに時間が短縮できた！」「総務部ならこのショートカットキーは覚えておこう！」というような超具体的な事例ばかりで構成しています。

 参加者は、同じAEONで働く仲間が講師を務めるからこそ、「自分もできるかも」「業務にも活かせるかも」という実感を持ちやすく、アンケートからは、**外部の専門家やネットの情報では得られない社内メンバーの発する言葉に、絶大な信頼感**があることも分かりました。結果、現場のリアルな実例を共有したこの勉強会は、**想像以上の反響**を呼び、毎月の実施ごとに参加者からの好評の声は増え続け、今では毎回約400名以上が参加を希望し、**年間5,000名**を超える規模となっています。

 もちろん勉強会には社長からパートさんまで誰でも参加できますが「デジタルに苦手意識のあるパートさんにも分かりやすく」に徹底的してこだわり、今では**参加者全体のなんと20%がパートさん**で構成されるようになりました。

## 成果は出てきた からこそMore＆More

 2年間地道に勉強会を続ける中で「Excelのマクロを覚えた従業員が、1時間かかっていた業務を5分に短縮」といった具体的な成果はもちろん、勉強会で学んだ従業員同士が学び合うコミュニティを自発的に作ったりと、「自分たちでやろうぜ」という文化作りや、マインドを醸成にもつながっていることを少しずつ感じています。

  だからこそ、**今後はもっと大きなムーブメントにつなげていきたい。**

 AEONの中で今次々と生まれている <font color="Red">**新たなテクノロジーを、まるでExcelのショートカットキーを一つ覚えるくらいの感覚で「まず私がお店で使ってみます！」と言ってくれる**</font>パートさんがどんどん増えてくれば、AEONが、そして小売業がこれまで以上のスピードで、 <font color="Red">**お客さまの新たな喜びを創り出していける**</font>と信じています。

 これからもAEONの新たなトライと、これまで以上のお買い物体験にぜひご期待ください！

明日は[H1karu SA1T0](https://qiita.com/hikkie)さん！お楽しみに！**AEONわいわい☺**

https://qiita.com/advent-calendar/2024/aeon

AEONの色々なトライはぜひこちらから

https://engineer-recuruiting.aeon.info/aeon-tech-hub
19日目: Z Algorithmを実装する

[競プロ用ライブラリを作る Advent Calendar 2024](https://qiita.com/advent-calendar/2024/yukkku-ribitol)の19日目です.

https://qiita.com/advent-calendar/2024/yukkku-ribitol

# Z Algorithmって?

何らかの配列`s`が与えられたときに, こういう配列を作ります
- `z[i]`は「`s`と`s[i..]`の先頭のいくつの要素が一致しているか」を表す

愚直に書くなら以下のようになります
```rs
fn naive_z(slice: &[u8]) -> Vec<usize> {
    let mut z = vec![];
    // slice自身とslice[0..]は完全に一致するので, 長さを入れておく
    z.push(slice.len());
    for i in 1..slice.len() {
        // 先頭を比較する配列
        let sub = &slice[i..];
        let mut j = 0;
        loop {
            // 違う箇所を見つける or 文字列の最後まで見たら, その場所を結果の配列に入れる
            if slice.get(j) != sub.get(j) {
                z.push(j);
                break;
            }
            // そういう箇所が見つかるまで調べ続ける
            j += 1;
        }
    }
    z
}
```
この愚直は最悪$O\left(N^2\right)$になりますが, このアルゴリズムを使えば$O(N)$でできます.

# 仕組み

愚直な方法で時間がかかるときは`atatatata...`みたいな大規模に先頭が一致して調べるのに時間がかかるケースです.

例として`atatata_and_atatata`という列を計算したときの結果を見てみます
```
 a  t  a  t  a  t  a  _  a  n  d  _  a  t  a  t  a  t  a
---------------------------------------------------------
19  0  5  0  3  0  1  0  1  0  0  0  7  0  5  0  3  0  1
    ^^^^^^^^^^^^^^^^                    ^^^^^^^^^^^^^^^^
```
`^^^`の範囲が一致していますね. 13文字目に「7文字一致している」という情報があるから, そこから6文字は先頭の情報が使いまわせてしまうわけです.

注意すべきが, `tentekotenten`みたいなケースで,
```
 t  e  n  t  e  k  o  t  e  n  t  e  n
---------------------------------------
13  0  0  2  0  0  0  5  0  0  3  0  0
    ^^^^^^^^^^           ^^^^^^^^^^
```
この通り, 一致しません. 11文字目の「先頭3文字」は一致している範囲からはみ出しているのでそのままでは使いまわせず, どれだけはみ出すか調べる必要があります.

原理はこういう感じなので, これを実装するだけです. が, かなりややこしいので注意して実装しましょう.

```rs
pub fn z(slice: &[u8]) -> Vec<usize> {
    let n = slice.len();
    // 結果を入れる配列
    let mut z = Vec::with_capacity(n);
    // 先頭の要素は全部一致してるので, 配列の長さを入れる
    z.push(n);
    // 利用する「一致している範囲」の左端と右端
    // 最初は仮に両方1を入れていて, 区間の大きさが0なので「最初」
    let mut l = 1;
    let mut r = 1;
    // ループの各回で1つずつzに要素を追加していく
    for i in 1..n {
        // 完全に一致している範囲に収まっていたら, そのまま追加して終了
        if l < i && z[i - l] + i < r {
            z.push(z[i - l]);
            continue;
        }
        // この後を実行するのは
        // - はみ出した
        // - 一致している範囲を使い切ってまだ情報が無いところに突入した
        // のどちらかです
        // どちらにしても, 今計算したい地点から新たな「一致している範囲」を作り直します

        // rはここで不一致(一致している区間の終わり)を探す用の変数になります
        // - はみ出した場合は, 一致している区間の中では完全に一致していた, ということなので,
        //   探索はr以降を見ればいいです
        // - 範囲を使い切った場合は情報がないのではじめ(つまりi)から調べればよいです
        //   このケースではこの時点でr <= iになってるので, r < iのときにr = iに設定してやります
        if r < i {
            r = i;
        }
        // 前述の通り, 新しい一致している区間の左端はiです
        l = i;
        // 一致していない場所を探します
        while slice.get(r) == slice.get(r - i) {
            r += 1;
        }
        z.push(r - l);
    }
    z
}
```

# 実装

- [`z.rs`](https://github.com/Yukkku/ribitol/blob/main/src/z.rs)

上のサンプルコードと殆ど何も変わりません.

# まとめ

いかがでしたか?

明日は引き続き天才線形時間アルゴリズムを実装します.
Spresense HDRカメラのズームフォーカスレンズ用のフォルダを作る

Spresense HDR カメラに接続できるかなと思い、ズームフォーカスレンズを入手しました。巷では、アイリス制御レンズをズームレンズと称して売っているところもありますが、騙されないようにしましょう。アイリス制御レンズはモーターが一つ、ズームフォーカスレンズは、モーターが２つです。

**アイリス制御レンズ（モーター一つ：ズームフォーカスは手動）**
![IrisLens.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598183/655c634c-6c03-02a9-e49d-58b611c4d402.jpeg)

**ズームフォーカスレンズ（モーター２つ：ズームフォーカスは電動）**
![zoomfocus.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598183/f37ef986-c7de-0308-29a1-ff45617d9509.jpeg)

ズームフォーカスレンズはM14と標準のM12よりちょっと大きめ。よいフォルダが見つからないため、作ってみました。完成品がこちら。

![DSC_0830s.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598183/c225220f-5e25-beeb-2cb8-134b929457cb.jpeg)

フォルダは「Free CAD」で作成しました。パーツはフォルダの底と筒の２つの構成です。この２つを瞬間接着剤などで剥がれないよう強力に接着します。普通のセメダインなどではネジ穴を貫通させるときに剥がれてしまうので注意してください。（そのうちGithubにあげます）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598183/69934338-371d-9c2e-8292-151360827845.png)

フォルダは、HDRカメラオリジナルのレンズバレルをつなげていたネジを使って、裏からネジ止めします。

![DSC_0831.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598183/cd74d461-3941-4925-cde6-b352c55842be.jpeg)


注意点が一点。3Dプリンタのフィラメントには黒を使ってください。白や色付きのフィラメントだと光がイメージセンサに入り込んでしまい、全体が明るくなったり色がついたりします。

次はズームフォーカスのモーター制御について解説したいと思います。

関連記事
[Spresense HDRカメラ用のズームフォーカスレンズのモーターの仕様を確認する](https://qiita.com/TaroYoshino/items/7f2b4e3c9ce0c7de4176)
[Spresense HDRカメラ用のズームフォーカスレンズのモーターを制御する](https://qiita.com/TaroYoshino/items/342d6180e4ca6aa3b439)
[Spresense ズームレンズ対応HDRカメラを動作させてみた](https://qiita.com/TaroYoshino/items/98f5ab07975a0fb59ebc)
git のコミット時に記載するメアドを表示と設定する

標準じゃと、unix アカウント名がそのまま記載されちゃるけん、具合悪い(ワシだけかも)
変更しおる方法の忘備録
```shell:設定	/usr/local/etc/gitconfig
git config --system user.name JE3KMZ
git config --system user.email JE3KMZ@example.app
```
```shell:確認	~/.gitconfig
git config --global user.name
git config --global user.email
```
```shell:削除	リポジトリのディレクトリ/.git/config
git config unset user.name
git config unset user.email
```
24日目にLINEミニアプリが完成する初心者 ―― Day19. LIFFアプリを初期化する


# はじめに

前回は「24 日目に LINE ミニアプリが完成する初心者 ―― Day18. リッチメニューの修正」と題して、一旦当初予定していた LIFF アプリの機能開発を終えました。

https://qiita.com/non_watanabe/items/fd4244de3f70b998853b

<br/>
今回からは LIFF でまだ紹介していない機能を学習しつつ機能修正・開発を行って行きたいと思います。

# liff.init()

紹介する機能の 1 つ目としては LIFF アプリを初期化です。

これは LIFF スターターアプリにあらかじめ組み込まれているため、詳しく学習を行いませんでした。

そのためあらためてこの機能について詳しく学習して行きたいと思います。

LIFF アプリの初期化には LIFF SDK の`liff.init()`を使います。

LIFF アプリはページを開くたびに必ず初期化する必要があり、これは同じ LIFF アプリ内での遷移であっても同様のため、LIFF アプリ開発をするのであれば避けては通れないものです。

:::note info
**LIFF アプリを初期化する前でも実行できるメソッド**

初期化前にも以下のメソッドは利用することができます。

- `liff.ready`
- `liff.getOS()`
- `liff.getAppLanguage()`
- `liff.getLanguage()`（非推奨）
- `liff.getVersion()`
- `liff.getLineVersion()`
- `liff.isInClient()`
- `liff.closeWindow()`（LIFF SDK バージョンが 2.4.0 以上）
- `liff.use()`
- `liff.i18n.setLang()`

:::

## 実装方法

コードの記述はシンプルで以下のように記載を行います。

`then`の中には、LIFF アプリの初期化後に実行する処理を記述します。

```js
liff
  .init({ liffId: process.env.LIFF_ID })
  .then(() => {
    // Start to use liff's api
  })
  .catch((error) => {
    console.log(error);
  });
```

私は Next.js で実装しているため`\_app.tsx`ファイルで`useEffect`を使って記述しています。

```tsx:src/nextjs/pages/_app.tsx
  useEffect(() => {
    liff
      .init({ liffId: process.env.LIFF_ID })
      .then(() => {
        liff.getProfile().then((profile) => {
          trigger({ userId: profile.userId, name: profile.displayName });
        });
      })
      .catch((error) => {
        console.log(`liff.init() failed: ${error}`);
      });
  }, []);
```

# LIFF アプリ初期化時の注意事項

いくつか注意事項があったためそれぞれ確認しておきます。

## `liff.init()`をエンドポイント URL 以下の階層で実行する

`liff.init()`メソッドはエンドポイント URL と完全に一致、もしくはエンドポイント URL よりも下の階層においてのみ動作します。

私の場合だとエンドポイント URL として以下の 3 つを登録しています。

- https://mahaloliving.netlify.app/
- https://mahaloliving.netlify.app/catalog
- https://mahaloliving.netlify.app/showroom

これらはそれぞれエンドポイント URL と完全一致しているため、どれも問題ありません。

もし`https://mahaloliving.netlify.app/`をエンドポイント URL として登録していなかった際は、登録されているエンドポイント URL より上の階層になってしまうため`liff.init()`が動作しません。

## `liff.init()`を 1 次リダイレクト先 URL と 2 次リダイレクト先 URL で 1 回ずつ実行する

`liff.init()`メソッドは URL に付与される`liff.state`や`access_token=xxx`などの情報を元に初期化処理を行っています。

そのためエンドポイント URL にクエリパラメータやパスが含まれている場合は、正しく LIFF アプリを初期化するために、2 度 liff.init()メソッドを実行する必要があります。

1 回目は 1 次リダイレクト先 URL とされる、エンドポイント URL での初期化。
2 回目は 2 次リダイレクト先 URL とされる、エンドポイント URL にクエリパラメータやパスを含んだ URL での初期化です。

ただ、今回私が実装した中ではクエリパラメータやパスが含まれている URL はまだ使っていないため対応は不要です。

## URL を操作する処理は`liff.init()`が完了してから実行する

`liff.init()`メソッドが返す`Promise`オブジェクトが resolve する前に、サーバーやフロントエンド側の処理などで URL を変更すると LIFF アプリを開くことができないようです。

リダイレクトなどを行う場合は以下のように`liff.init()`完了後に実行するようにしましょう。

```js
liff
  .init({
    liffId: "1234567890-AbcdEfgh", // Use own liffId
  })
  .then(() => {
    // Redirect to another page after the returned Promise object has been resolved
    window.location.replace(location.href + "/entry/");
  });
```

## 1 次リダイレクト先 URL の取り扱いに注意する

1 次リダイレクト先 URL には自動的に`access_token=xxx`といったユーザのアクセストークンが付与されます。

アクセストークンは機密情報ですので、このアクセストークンは付与された 1 次リダイレクト先は外部に公開しないよう注意しましょう。

# まとめ

ここまでで LIFF アプリの初期化について学習し、実装に問題がないか振り返ってきました。

次回は、二次元コードリーダーについて学習し、機能としての活かし方を考えて行きたいと思います。

残りは 5 日！
気になる方は是非フォローやカレンダー購読をお願いします:star:
AZ-900 合格体験記

## はじめに

AZ-900、無事合格してきました。
いつも思いますが、試験終了を確定する瞬間ってやっぱり緊張します。
まだ余韻に浸ってる今のうちに試験に向けてやってきたことなどを書いていこうと思います。

## 私のスペック

業務系エンジニアしてます。最近はマネージャというポジションで日々を過ごしています。
情報処理系で持ってる資格は以下のとおり。

- 基本情報技術者
- AWS CLF
- AWS SAA

業務では AWS のみ。Azure は全くのノータッチ。

## 受験のきっかけ

仕事で、とある案件参画の必須条件に「AZ-900を取得済であること」がありました。
AWS認定資格は持っているものの、代替にはならないとのことで取得に向けて動くこととなりました。

## 試験準備

通常業務をこなしつつ、期限までに取得が必要という状況でした。
参考書を買って読み込む時間もあまりないと感じ、スキマ時間でもできる方法を探りました。

- YouTube
    - [【Azure】Microsoft認定Azure Fundamentals（AZ-900）対策講座【Microsoft】](https://www.youtube.com/watch?v=HAcXTBF_qAM)
Azureの各サービスに関する解説動画です。
    - [Azure資格 対策講座](https://www.youtube.com/@Azure_cource/featured)
上記と同じく解説動画ですが、今回はこの動画に一番助けられた感じがします。
- 練習問題
    - [AZ-900 公式ページ](https://learn.microsoft.com/ja-jp/credentials/certifications/azure-fundamentals/?practice-assessment-type=certification)
Microsoft が用意している練習問題に挑戦できます。私は最終的な仕上げに利用しました。
ただし、ここで高得点を叩き出せてもやはり練習問題という割り切りが必要です。
本番はもう一歩踏み込んだ問題を出してきます。
    - [IT Concepts JAPAN](https://it-concepts-japan.com/)
無料で 90 問提供してくれてます。でも試験レベルではないです。
    - [練習問題（問題集）（ Azure Fundamentals（Azure基礎）AZ-900）](https://studyand.work/list-question-azure-az-900)
本番の問題レベルに一番近いかも。

## 試験当日

会社の近くにあるテストセンターで受験しました。
手続きを終え、PCの前に案内されて試験スタート。

問題数は 35 問だったかな？15 分程度で１周できます。
残った時間であと２周ぐらい見直しをしましたが、わからん問題は何回見てもわからんままでした。

試験終了のボタンを押し、最終確認を促すダイアログで「はい」を押すと終了です。
合否は即時表示されます。AWS CLF のときも即時表示だったのでドキドキしながらボタンを押しました。

## 試験結果

もちろん合格です。
842 / 1000 というスコア。700 が合格ラインであることを考えると、少し余裕を持った点数でした。

## 感想

「AWS 知ってるし、何とかなるっしょ」というノリで受けると失敗する可能性が高いような気がしました。
たしかに、責任共有モデルだったりリージョンだったり AZ だったりと同じ考え方するところもあります。
やはり Azure のサービス名や特徴を把握しないと厳しいと思いました。

## 最後に

この手の体験談は所詮は「私の場合はこうだった」であって、銀の弾丸にはなりえません。
それでも、今から AZ-900 の受験をしようと考えている方々にとって背中を押すきっかけになれれば嬉しいです。
Splunk Cloudでrestコマンドを使用してリソース一覧を抽出する方法

## はじめに
Splunk Cloudでとあるリソースの一覧を抽出したいとなった際に、数が多いとUIからではページネーションで一気に表示できません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222808/54d45b96-789a-5c7b-fa2e-0c08f8eb9b1a.png)

サーチでrestコマンドを使用すればリソースの一覧をエクスポートすることが可能です。

## restコマンドとは
SplunkのREST APIエンドポイントにクエリを実行するための検索コマンドです。

https://docs.splunk.com/Documentation/Splunk/9.3.2/SearchReference/Rest

## サーチ例

### View（ダッシュボード）一覧

```
| rest splunk_server=local /services/data/ui/views
| search NOT eai:acl.owner IN (nobody admin)
```

### Savedsearch 一覧

```
| rest splunk_server=local /services/saved/searches
| search NOT eai:acl.owner IN (nobody admin)
```

## プライベートなリソースも含める
上記のサーチ例ではプライベートなリソースは含まれません。もしプライベートも含めたい場合は以下のようになります。

### View（ダッシュボード）の例

```
| rest splunk_server=local /servicesNS/-/-/data/ui/views
| search NOT eai:acl.owner IN (nobody admin)
```

## サーチ結果のフィールド選択
上記のサーチ例ではフィールドの情報が多いため必要なものだけを抽出します。

以下では`ダッシュボード名`と`所有者`、`App`を抽出しています。

```
| rest splunk_server=local /servicesNS/-/-/data/ui/views
| search NOT eai:acl.owner IN (nobody admin)
| fields  title eai:acl.owner eai:acl.app
```

## リソースの一覧をCSVで出力
サーチを実行して結果が出たらあとはエクスポートするだけです。これでリソースの一覧を抽出することができます。


![貼り付けた画像_2024_12_18_23_37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222808/004e6d93-57b3-0122-e709-c7c66e471ae0.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222808/a780191c-2892-a5e2-8560-6c59bb35aec7.png)
ExpressRouteの概要


# はじめに

ふと私の中でExpressRouteの中身がブラックボックスだなと思ったので、勉強しました。ExpressRouteにはMicrosoft PeeringとPrivate Peeringがありますが、今回はPrivate Peeringについてです。

# よく見る図

こんな感じのをよく見かけます。
ExpressRouteのマークとゲートウェイがあってオンプレと通信できますってことを表しています。しかし、このExpressRouteマークに込められた意味が色々と省略されています。

![ExpressRoute（簡略）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248327/972c02ad-1b66-6b7e-d720-08793dd631da.png)

# 少し具体的に

実際はこんな感じです。

![ExpressRoute（詳細）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248327/0240e34f-a6e6-f730-4a49-6cc46f745ba5.png)

丸いオブジェクト（？）はNW機器（ルータ）を表現したものです。
裏ではこんな感じになっています。
MSはMicrosoftの略です。

1. MS Edge 　　：Microsoftの設備で管理されているルータ
1. Provider Edge：プロバイダがMS Edge間を結ぶために設置しているルータ
1. Custmer Edge：顧客が用意するルータ（BGP設定が必要）

※本来回線ベンダの施設はこんなものじゃないくらい複雑なはずですが、今回は触れません。

# 回線

ルータが分かれている部分で回線は２種類あるようなイメージになります。

![ExpressRoute（回線１２）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248327/6daa6c5f-af61-aa81-d8b7-67d625ddbd00.png)

・回線１：オンプレとプロバイダとの間を繋げる回線
・回線２：プロバイダと契約してMSへアクセスする回線

# アクセス回線

回線１のことをアクセス回線と言ったりします。
※手元に回線を生やして、クラウドにアクセスするための回線的なニュアンス

実際手元に回線が生えてきたらこんな感じになるはずです。

![ExpressRoute（終端装置）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248327/d6414611-0c74-fc23-5d0e-b98bdd0aed88.png)

回線終端装置：有名なのはONUと呼ばれるものです。壁から線だけ伸びててもネットワークは使えないのでこの装置があります。この装置にLANケーブル接続して、逆側をルータに接続して、使用するイメージです。

図では２本書いているので、回線１（アクセス回線）は回線が２本あることになります。
ExpressRouteで冗長化されていてもアクセス回線が２本ないとアクセス回線に何かあるとクラウドへのアクセスが途絶えてしまいますので、冗長化する際は２本用意しないといけません。

# 最後に

回線１，２をまとめて提供してくれるベンダもいます。
回線１、２それぞれで契約するってケースもあると思います。
よく分からないという方は回線ベンダさん（プロバイダさん）に話を聞いてみるのが早いかと思います。
更に詳しいことが知りたい方は参考文献をご覧ください。

# 参考文献

公式

https://learn.microsoft.com/ja-jp/azure/expressroute/expressroute-introduction

https://learn.microsoft.com/ja-jp/azure/expressroute/expressroute-connect-azure-to-public-cloud

https://learn.microsoft.com/ja-jp/azure/architecture/reference-architectures/hybrid-networking/expressroute-vpn-failover

ブログ

https://jpaztech.github.io/blog/archive/expressroute-deep-dive-part4/

https://www.cloudou.net/expressroute/exr001/
QAが考える「設計者に必要なスキル」

## はじめに
私の業務は QA (Quality Assurance:品質保証）です。
組織によって QA の業務内容は異なりますが、私の組織では以下の3つ業務を担当します。
1. ドキュメントレビュー(仕様書や設計書の内容を確認)
1. プロセスチェック（社内・業務規定に従って作業していることを確認）
1. 製品テスト（製品が仕様・設計通りに動作することを確認）

ドキュメントレビュー中に「__どうしてチームや人によって、設計書の完成度に差が出るんだろう？__」とふと疑問に思ったので、自分なりに整理してみました。


## そもそも、なんで「設計書の完成度」を気にするの？
端的に言うと、設計書の完成度が低いと __無駄なコストが発生する__ からです。
以下に、開発中・保守運用中それぞれのフェーズに発生する問題を列挙します。

#### 開発中：要求定義～受入テスト
- __他の設計者__「設計根拠や前提条件が記載されていないので、設計の妥当性を判断できない。そのため、設計内容に矛盾や不足があっても発見されないまま実装され、納品時に顧客の要件に適合しないことが発覚する。」
- __QA__「設計書に必要な情報が不足しているので、顧客の要件やシステムの仕様に沿ったテストを作成できない。その結果、バグを見逃してしまい、顧客に納品した後トラブルとなる。」

#### 運用開始後：保守～改修～廃棄
- __後任の設計者__「コンポーネントや外部システムとどのように連携しているのかが設計書に記載されていない。そのため、ある部分を改修した際に与える影響範囲を特定できず、思わぬところに不具合が発生する。」 
- __不具合対応の関係者__「エラー処理や例外処理の内容が記載されておらず、内部の挙動がわからない。そのため、不具合の原因の特定や対策に時間がかかる。」

完成度が低い設計書は、 __関係者全員の時間と労力を無駄__　にします。
だからこそ、関係者全員がスムーズに作業を進められる __完成度の高い設計書が必要__ なのです。


## 「完成度が高い設計書」が生まれる過程を考える
設計書が生まれる過程から、「どんなスキルが必要かな？」と考えました。
考えた結果は下の表の通りです。

| プロセス | 作業内容 | 必要なスキル |
|:-----------|:------------|:------------|
| 論点・サブ論点  | 設計書の目的と章節構成*1を考える | 論理的思考力 |
| タスク | 仕事を実行可能な単位に分割する*2 | 仕事の段取り力、コミュ力 |
| スケジュール | タスクの優先順位と所要時間を考えて時間を確保する | 自分の作業スピードを見積もる力 |
| 作業 | 集めた情報と決定事項を文章にする | テクニカルライティングのスキル＋セルフチェック（音読、校閲機能） |
| アウトプット | 設計チームやQAのレビューを受ける | レビュースキル |

*1)例えばセキュリティ設計書の場合、
まず前提条件となる設計書の対象範囲やシステム構成、顧客のセキュリティ要件や法規制等を記載します。そのあとに、セキュリティリスク分析を実施した結果を記載して、「どのようなリスクがあるのか。また、そのリスクにはどう対応していくのか。対応策を導入すると受け入れ可能なレベルまでリスクが低減されるのか。」という流れで、どんどん具体化していきます。この流れから外れると、ゴールが不明確になったり、論理性が失われます。

*2)タスクの中には、技術書からの情報収集であったり、ほかの機能を担当する設計者に質問したり、ネゴったり...いろいろ泥臭いこともあると思います。「設計者は一人でコツコツ作業することが好き」というイメージがありました。しかし、チームで働く以上、相手に依頼することであったり、進捗報告＋遅延の報告であったり、という風にコミュニケーションスキルは避けては通れないなと思いました。

## :coffee:コーヒーブレイク:coffee:「コミュニケーションって難しい」
とある部署での開発プロジェクトは、以下の特徴があったのでプロジェクトが混乱することはほとんどありませんでした。
- チーム全員が確立された開発プロセスに従っていたので、作業漏れが少なかった
- 開発チームの人数が少なく、情報共有がスムーズに行えていた
- 製品について熟知したメンバーが開発を担当していたため、仕様の理解不足や誤解が発生しづらかった

しかし、現在参画している開発プロジェクトでは:fire:様々な問題:fire:が起こっています。まとめると、上で述べたプロジェクトは正反対の特徴があります。
- 新しい開発プロセスに従っているため、チーム全員にとって不慣れなため、作業漏れが発生する
- 開発チームの人数が多く、必要な人に情報が回ってこないことがある
- 製品や製品が使用されるビジネスを理解しているメンバが少なく、仕様の理解不足や誤解が発生する

 同じ会社であっても、部署やグループによって仕事の進め方や開発経験が異なります。そのため、関係者間で認識のズレが起こらないように、 __ゴールや作業ルール、作業の担当範囲等__　について、密なコミュニケーションが大事だなと思いました。


## 最後に
私の実体験に基づく偏った意見です。
実際に経験したことやアドバイス等ありましたら、コメント欄でご意見を頂けると幸いです！

## 参考文献
適宜、追加していく予定。
#### テクニカルライティング
- 技術者のためのテクニカルライティング入門講座

#### レビュー
- なぜ重大な問題を見逃すのか？ 間違いだらけの設計レビュー第3版

#### ソフトウェアエンジニアリング


## 変更履歴
2024/12/18: 新規作成
python-fire: 引数の型は型ヒントでなく引数の値で決まる

# 環境
* Python 3.12.4
* [python-fire](https://github.com/google/python-fire) 0.7.0

# 概要
`python-fire`によって呼び出される関数において、引数の型は型ヒントでなく引数の値で決まります。


```python:sample1.py
import fire

def hello(name: str):
    print(f"{name=}")
    print(f"{type(name)=}")

if __name__ == '__main__':
  fire.Fire(hello)
```

```
$ python sample1.py aaa
name='aaa'
type(name)=<class 'str'>

$ python sample1.py 001
name=1
type(name)=<class 'int'>
```

上記の例では、引数`001`はint型の`1`に変換されました。



なお、公式ドキュメントには以下の通り記載されています。

>The types of the arguments are determined by their values, rather than by the function signature where they're used. You can pass any Python literal from the command line: numbers, strings, tuples, lists, dictionaries, (sets are only supported in some versions of Python). You can also nest the collections arbitrarily as long as they only contain literals. [^1]

[^1]: https://github.com/google/python-fire/blob/master/docs/guide.md#argument-parsing

# string型の値`001`を渡す方法
string型の値を渡すには、コマンドラインの呼び出し側で引用符を用いて対処する必要があります。

```python:example.py
import fire
fire.Fire(lambda obj: type(obj).__name__)
```

```
$ python example.py 10
int
$ python example.py "10"
int
$ python example.py '"10"'
str
$ python example.py "'10'"
str
$ python example.py \"10\"
str
```

https://github.com/google/python-fire/blob/master/docs/guide.md#argument-parsing 引用


# 変換処理
python-fireは、以下の関数でコマンドラインから渡された引数を適切な型に変換しています。

https://github.com/google/python-fire/blob/6cf45c663075c96b20dd0dfa733c2374545a4ad6/fire/parser.py#L79C5-L116

標準モジュールである`ast`を利用していました。


# jsonargparse との比較
python-fireにインスパイアされた[jsonargparse](https://jsonargparse.readthedocs.io/en/stable/)では、型ヒントに従って値の型が決まります。

>Second, the arguments are expected to have type hints, and the given values will be validated according to these. [^2]

[^2]: https://jsonargparse.readthedocs.io/en/stable/#comparison-to-fire 引用

```python:sample2.py
def hello(name: str):
    print(f"{name=}")
    print(f"{type(name)=}")


if __name__ == "__main__":
    import jsonargparse

    jsonargparse.CLI()
```    


```
$ python sample2.py 001
name='001'
type(name)=<class 'str'>
```

```python:sample3.py
def hello(name: int):
    print(f"{name=}")
    print(f"{type(name)=}")


if __name__ == "__main__":
    import jsonargparse

    jsonargparse.CLI()
```    

```
$ python sample3.py 001
name=1
type(name)=<class 'int'>
```
続・ UnrealEngine を使って注文住宅を建てたお話 ～ 最終報告編 ～

※ この記事は[Unreal Engine (UE) Advent Calendar 2024](https://qiita.com/advent-calendar/2024/ue
 "「Unreal Engine (UE) Advent Calendar 2024」")の19日目の記事になります。
# はじめに
昨年度、「Unreal Engine を使って注文住宅を建てたお話」という記事を執筆し、
多くの方にご覧いただくことができました。特に普段はUnreal Engineを使用していない方々からもコメントをいただき、違う分野の意見を見ることができてとても参考になりました。

さて、今回の記事は昨年度の記事をお読みいただいていることを前提にしていますので、
まずは軽く目を通してからご覧いただけると幸いです。

https://qiita.com/TOKUNAGA_02_ZZ/items/91792c667531c1612cfb

# Unreal Engine上の家と実際の家の比較
我が家では、自分達が考えた間取りからハウスメーカーさんが図面を作成し、
モデラーの方に家の3Dモデルを制作してもらいました。
今回は、実際に完成した家、Unreal Engineで作成したモデルを比較してみたいと思います。
<img width="80%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/980013/7ec1a1e0-985c-786f-18de-515618edfe1b.png">

# 外構について
完成した家を実際に見て、正直驚きました。Unreal Engineで作成したモデルが、思っていた以上にそのまま再現されていると感じました。
一部、途中で窓の配置や仕様が変更された部分は反映できていませんが、それ以外はほぼ完璧に再現されていると思います。

### ◆ 正面玄関

<img width="80%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/980013/773fc52b-1161-4a67-999a-4bf23ab77502.png">

### ◆ 庭

<img width="80%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/980013/8a784369-c991-7f41-5331-740177ef73a8.png">

### ◆ 側面
<img width="80%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/980013/72385a2c-a1eb-908c-7f6d-90f846b86047.png">

# 内装について
内装のスケール感も忠実に再現されており家具の買い替えの参考になりました。
Unreal Engine上ではグレイマンを配置して、部屋のサイズ感を確認しながら家具を選んでいったのですが、実際に家が完成してみると、思っていたよりも全体的に広く感じました

<img width="80%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/980013/90bbb7f3-19b0-0e33-7857-563711a8ed25.png">

### ◆ 玄関
<img width="80%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/980013/38331980-746e-c5ec-41d9-7206932c44cf.png">

### ◆ 水回り
<img width="80%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/980013/618e0279-d7be-a2b7-9a30-aa1423764cf2.png">

### ◆ リビング
<img width="80%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/980013/9fc0ba07-c297-ab88-8da3-fd608a32d741.png">

### ◆ ダイニング
<img width="80%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/980013/305c8450-0423-4abd-cb85-d75f1fec8430.png">

### ◆ 寝室
<img width="80%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/980013/c503ae1e-3e79-5d20-ebf5-7eb6c9bc659c.png">

# ふりかえり
1年半ほどUnreal Engineを使用して家づくりをしてきましたが、建築との相性は抜群だなと感じました。
私や妻自身にも聞いてみて良かった点を簡単にまとめたいと思います

### ◆ 壁紙のコーディネート
思い切った色の壁紙を選定できるほか、一般的に確認できるメーカーから配布されているカタログだと小さな切れ端でしか確認できないため、壁全面に張った姿をシミュレーションできるのは凄くよかった。
→ これがないと白一色になっていたと思いますｗ
<img width="80%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/980013/d417673c-f159-3da4-d63b-55f720c69f8c.png">

### ◆ ライティング
図面のみだと窓の位置や大きさが想像しずらく、我が家では決定するまでに時間がかかる項目でした。
Unreal Engine上で窓の位置をシミュレーションする事で差し込む光や外からの見え方が想像でき、最終決定にかなり貢献しました。
<img width="80%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/980013/d138d7c2-5872-1f1c-45a1-59bb6efed280.png">

# おわりに
間取りをUnreal Engine上で視覚化し、その後実際に家を建てるという経験は、おそらく一生に一度の貴重な体験だと感じました。
このプロジェクトを進めるにあたり、多くの方々にご協力いただき本当に感謝の気持ちでいっぱいです！本当にありがとうございました！

これから注文住宅を建てようとお考えの方や、興味があってお話を聞いてみたい方がいらっしゃれば、ぜひお気軽にお問い合わせください。
テスト自動化あるある

# はじめに

テスト自動化において、あるあるなエピソードを紹介します。

# カバレッジは高いがassertが抜けている

テストスクリプトを書いているときに、カバレッジが高いことに安心してしまい、十分なassert文を書けていないことがあります。

ソフトウェア内の経路を解析してテストカバレッジを測定するツールは、テストスクリプトが実際に期待通りにソフトウェアの妥当性を確認しているかどうかを保証するものではありません。

高いテストカバレッジは、テストスクリプトがソフトウェアの多くの部分をカバーしていることを示すだけであり、十分なテストを行っていることを保証するものではありません。

過不足なく assert 文を使って適切に妥当性を検証することで、はじめて自動テストが意味を持ちます。

# テストデータが読みにくい

テストデータを直接記述しているテストスクリプトをしばしば見かけます。

スクリプト内にデータが含まれるとデータ構造とスクリプトの制御シーケンスが混在してスクリプトが読みにくくなります。

データはスクリプトから分離して外部ファイルに記述することで、データの読みやすさを維持しつつ、スクリプトの保守性を高めることができます。

# テストスクリプトが長い

1000行を超えるテストスクリプトとか・・・。

1つのテストメソッドの中で複数のテストシナリオを実行していると、テストスクリプトが長くなりがちです。

また、テスト対象とするソースコードの複雑度が高いと、テストスクリプトも複雑で長くなりがちです。

本来は、、ソフトウェアをリファクタリングしたり、1つのテストメソッドでテストするシナリオを1つに絞るなどして、テストスクリプトを短く保つことが望ましいです。
よく使うGitHubのコメント略語まとめ

GitHubでのコードレビューやIssue管理でよく目にする略語について, 実際の使用シーンと共に解説する.

## 主要な略語一覧

### 作業状況を示す略語

- **WIP** (Work In Progress)
  - 作業中であり, まだ完了していない状態を示す.
  - PRのタイトルに付けることで, レビュー待ちではないことを明示できる.

- **TBD** (To Be Determined)
  - 未定の項目や, 後で決定する予定の箇所を示す.
  - 仕様書や設計書でよく使用される.

### タスク管理用の略語

- **FIXME**
  - 修正が必要な箇所を示す.
  - 緊急度が高い技術的な負債によく使用される.

- **TODO**
  - 実装予定の機能や追加タスクを示す.
  - コード中にコメントとして記載されることが多い.

### レビュー関連の略語

- **RFC** (Request For Comments)
  - レビューやコメントを求める際に使用する.
  - 設計段階での意見募集によく使われる.

- **LGTM** (Looks Good To Me)
  - コードレビューでの承認を示す.
  - レビュアーが問題ないと判断した際に使用する.

### その他のコミュニケーション用略語

- **IMO** (In My Opinion)
  - 個人的な意見であることを示す.
  - 主観的な提案をする際によく使用される.

- **AFAIK** (As Far As I Know)
  - 発言者の知る限りでの情報であることを示す.
  - 不確実な情報を共有する際に使用する.

- **NIT**
  - 些細な指摘や軽微な修正点を示す.
  - コードスタイルなどの微調整時に使用する.

- **FYI** (For Your Information)
  - 参考情報として共有する際に使用する.
  - チーム内での情報共有でよく見られる.


これらの略語を適切に使用することで, コミュニケーションを効率化できる. 特にWIPやLGTMは, GitHubでの開発フローにおいて重要な役割を果たしている.

それではQiitaアドカレ.24企画の今日のクリスマスツリーです．

> 詳しくは[こちら](https://qiita.com/JavaLangRuntimeException/items/1f4a6febf957f522ba45)の記事から

![Wondershare Uniconverter 15_000013.GIF](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3757442/09dcf42c-e858-ce0c-5255-4aabace9e7e2.gif)
分散共分散行列が正定値となる必要十分条件

**ざっくりサマリ**

$\mathrm{データの次元}+ 1\leq\mathrm{データ数}$であれば（変に分布していない限り）分散共分散行列は正定値となる（ので逆行列が計算可能）。逆も成立。

# 背景

多変量正規分布の推定やマハラノビス距離の計算では分散共分散行列の逆行列を求めるため半正定値ではなく更に強い条件である正定値性が必要となりますが、「分散共分散行列は半正定値である」という文献は割と見つかるものの「正定値であるための必要十分条件」は探してもなかなか出てきません（筆者の検索力不足）。ですが分散共分散行列が正定値となる必要十分条件は初等的な線形代数の知識$+\alpha$で証明できるので自力で示しましょう。

# 示したい命題

$d,n\in\mathbb{N}$とする。$\mathbb{R}^d$上のベクトルの組$(x_i)_{i=1}^n$に対して次の三条件は同値。

$\mathrm{(I)}$ $(x_i)_{i=1}^n$の中から選んで$\mathbb{R}^d$上の基底を取れる

$\mathrm{(II)}$ $X\triangleq\sum_{i=1}^nx_ix_i^\top$ は正定値行列

$\mathrm{(III)}$ $X=\sum_{i=1}^nx_ix_i^\top$ は正則（逆行列が存在）

## 正定値性と二次形式

正定値性は二次形式を用いて表現することが出来ます（詳細・証明は[こちら](https://manabitimes.jp/math/1089#:~:text=45%E5%BA%A6%E5%9B%9E%E8%BB%A2%EF%BC%89-,%E5%8D%8A%E6%AD%A3%E5%AE%9A%E5%80%A4%E8%A1%8C%E5%88%97%E3%81%A8%E4%BA%8C%E6%AC%A1%E5%BD%A2%E5%BC%8F,-%E4%BB%A5%E4%B8%8B%EF%BC%8C)）。

- 実対称行列$X\in\mathbb{R}^{d\times d}$が正定値$\Longleftrightarrow$任意の$y\in\mathbb{R}^d(y\neq0)$に対して$y^{\top}Xy>0$
- 実対称行列$X\in\mathbb{R}^{d\times d}$が半正定値$\Longleftrightarrow$任意の$y\in\mathbb{R}^d$に対して$y^{\top}Xy\geq0$

この事実を利用すると「正定値行列$X$と半正定値行列$Y$の和$X+Y$は正定値行列」ということが自明に言えます（証明でも利用します）

## 証明

$\mathrm{(I)}\Longrightarrow\mathrm{(II)}$

基底をとれるため$d\leq n$であり$\<x_1,\ldots,x_d\>$を基底としても一般性を失わない。

はじめに$n=d$の場合を示す。基底を並べた行列を$Z=\left[x_1,\ldots,x_d\right]\in\mathbb{R}^{d\times d}$とおく。このとき$\mathrm{(II)}$$X=ZZ^\top$と表せるためこれが正定値であることを示す。

$y\in\mathbb{R}^d$を任意として

$$y^{\top}ZZ^{\top}y=\|\|Z^{\top}y\|\|_2^2\geq0$$

である。等号成立は$Z$が基底を並べた行列であることから正則であるため$y=0$のみである。従って$X=ZZ^\top$は正定値であることが示される。

続いて$n>d$の場合を示す。基底でない余ったベクトルを並べた行列を$Z'=\left[x_{d+1},\ldots, x_n\right]\in\mathbb{R}^{d\times(n-d)}$とおく。このとき上記の$Z\in\mathbb{R}^{d\times d}$を用いて

$$y^{\top}Xy=y^{\top}(ZZ^{\top}+Z'Z'^{\top})y=y^{\top}ZZ^{\top}y+y^{\top}Z'Z'^{\top}y$$

となるが、これは正定値$+$半正定値であるので$X$は正定値であることが示される。

$\mathrm{(II)}\Longrightarrow\mathrm{(III)}$

一般に正定値行列の性質から導かれる。$0$でないベクトル$y\in\mathbb{R}^d$に対して$y^\top Xy>0$であるから$Xy\neq0$である（$Xy=0$なら$y^{\top}Xy=0$であるため正定値性が破綻する）。したがって$X$は正則である。

$\mathrm{(III)}\Longrightarrow\mathrm{(I)}$

（対偶証明）基底を選択できないならば線形独立な$d$個のベクトルの組を用意できないということであるため、$Z=[x_1,\ldots,x_n]\in\mathrm{R}^{d\times n}$の行列のランクは$\mathrm{rank}(Z)<d$である。従ってランクの性質より

$$\mathrm{rank}(X)=\mathrm{rank}(ZZ^\top)\leq\min(\mathrm{rank}(Z), \mathrm{rank}(Z^\top))=\mathrm{rank}(Z)<d$$

これは$X$が正則でないことを示す。$\square$

# 分散共分散行列が正定値とならないケース

ベクトルの組$X=(x_i)^n_{i=1}$の分散共分散行列は平均ベクトルを$\bar{x}=\frac{1}{n}\sum_{i=1}^nx_i$として$\mathrm{Cov}(X)=\frac{1}{n}\sum_{i=1}^n(x_i-\bar{x})(x_i-\bar{x})^\top$で表せる。

上記より分散共分散行列が正定値となるにはベクトルの組$(x_i-\bar{x})_{i=1}^n$から基底を選択できることが必要十分である。

すなわち、この中から線形独立な次元と同じ数だけのベクトルの組み合わせを選択できれば良い。

これが意味することは、まずデータの次元$d$がデータ数$n$より多いとき分散共分散行列は正定値になり得ないということである。

また$n=d$の場合についても$a_1,\ldots,a_d\in\mathbb{R}$として線形結合

$$a_1(x_1-\bar{x})+a_2(x_2-\bar{x})+\cdots+a_d(x_d-\bar{x})=0$$

を考えると$a_1=a_2=\cdots=a_d=1$で成立するから正定値ではない。

従って分散共分散行列が正定値であるためには$n\geq d+1$であることが必要条件である。

$n\geq d+1$の条件下で正定値になるかどうかは場合によるが、上記の考察から次のようなことは言える。

- （恐らく）一般的な設定としてデータの連続的な観測ノイズが全ての次元に広がるような場合では（例えば多変量正規分布）、ほぼ$n\geq d+1$であれば分散共分散行列の正定値性は期待出来る

- 一方で特に多重共線形な変数が過剰に含まれる場合や離散変量が多い場合には$n\geq d+1$であっても正定値になるとは限らない
SwiftでのJSONデータの取り扱い

## JSONデータとは
JSONとは"JavaScript Object Notation"の略で、JavaScriptというプログラミング言語におけるオブジェクトの書き方を参考に作られたデータフォーマット(データの記述形式)のこと。

他の代表的なデータフォーマットとして、CSVやXMLがある。
JSONの特徴は比較的、「読み書きしやすい」、「処理が重くなりづらい」などがある。

### 記載例
```
{
  {“Number” : 1, “Prefecture” : “Kanagawa”, “Capital” : “Yokohama”}, 

  {“Number” : 2, “Prefecture” : “Aichi”, “Capital” : “Nagoya”},

{“Number” : 3, “Prefecture” : “Hyogo”, “Capital” : “Kobe”},
}
```


## アプリ内に保管されたJSONデータの探索
アプリ内に保管されたJSONデータを読み込むためには、まずは場所を探す必要がある。Bundle.main.urlを使って探索する。
### コード
```
url = Bundle.main.url(forResource: "data", withExtension: "json")
```
### 意味
- `Bundle`: アプリケーションやリソースをまとめたディレクトリ
- `main`：アプリケーション全体を示す
- `url(forResource:withExtension:)`: 指定したリソースファイルのURLを取得するメソッド

## データの取得
```
let data = try Data(contentsOf: url)
```
`Data(contentsOf:)`: ファイルの内容をバイトデータとして読み込みます。urlが指し示すファイルを取得し、データ形式（Data）に変換しています。
`try`: このメソッドはエラーをスローする可能性があるため、tryキーワードが必要です。エラーが発生した場合、エラー処理が行われる（呼び出し元にエラーがスローされる）か、do-catchブロックでキャッチされます。

## JSONデータのswiftオブジェクトへの変換
JSONデータをSwiftのオブジェクトに変換するためのデコーダーを作成します。
```
let decoder = JSONDecoder()
```
`JSONDecoder()`: JSON形式のデータをSwiftの型（構造体やクラスなど）に変換するためのクラスです。このデコーダーは、Codableプロトコルに準拠した型を使ってJSONデータをデコード（解析）します。

## デコード
```
let prefectures = try decoder.decode([prefectures].self, from: data)
```
`decoder.decode(_:from:)`: decodeメソッドは、指定された型（ここでは[prefectures].self）にJSONデータを変換します。
`from`: dataで指定されたdata（JSONデータ）を解析し、指定した型のオブジェクトに変換します。

## エラーハンドリング
下記のようなケースでエラーが発生する可能性があり、エラーが発生した場合はCatch内のコードで処理を実施する。

- 指定されたurlが無効でファイルが存在しない。
- ファイルの中身がJSONフォーマットに準拠していない。
- JSONデータの構造がPlayActivityの構造に合わない。

## コード全体
```
    if let url = Bundle.main.url(forResource: "play_activities", withExtension: "json") {
        do {
            let data = try Data(contentsOf: url)
            let decoder = JSONDecoder()
            let prefectures = try decoder.decode([prefectures].self, from: data)
            return prefectures
        } catch {
            print("JSONデータの読み込みエラー: \(error)")
        }
```


##
Python滅ぼす協会

最近、ある奇妙な組織の存在を耳にしました。
それが「**Python滅ぼす協会**」。
思わず目を疑いました。Pythonを愛している多くのプログラマーにとって、「Python滅ぼす協会」は敵対組織でしかないのですから。
Pythonの~~カスさ~~便利さと~~ゴミのようなインデント~~美しさに魅了されている私にとって、そのような団体こそ滅ぶべきと思いましたがね。

## 1. 「Python滅ぼす協会」の真の目的とは？

まず最初に、正直に言うと、「Python滅ぼす協会」と聞くと、どうしてもその名が示す通り、Pythonを嫌い、Pythonの使用を禁止しようとしている団体だと思われがちです。しかし本当にそうでしょうか。
この協会の本当の目的は、「Pythonを使わなくても良い世界を作ろう」とするものではないでしょうか。
つまり、Pythonという素晴らしいプログラミング言語に依存しすぎないようにすることが目的であり、Pythonを完全に排除することではないのです。

現代のプログラミング環境では、Pythonが広く使われていることから、他の言語や技術を学ぶ機会が減少していることが懸念されています。
そのため、協会はPython以外の言語や技術への再注目を促し、プログラマーが他の選択肢を考慮することを促進しようとしています。

## 2. その主張と背景

Pythonはそのシンプルさと~~読みにくいインデント~~可読性、~~C++頼りの~~強力なライブラリ群によって、初学者からプロフェッショナルまで多くの人々に愛されています。
確かに、Pythonはデータサイエンス、機械学習、Web開発など多岐にわたる分野で非常に便利ですが、その一方で「Pythonばかり使っていると、他のプログラミング言語や技術に対する理解が薄れてしまう」と考える人々も増えてきました。

例えば、CやC++のような低レベル言語では、コンピュータの内部構造やメモリ管理に関する知識が深まるでしょう。
また、JavaやGoなど、Pythonとは異なる哲学を持った言語を学ぶことで、より広範なプログラミングスキルを身につけることができるでしょう。
Pythonを使い続けることで他の言語に対する理解が浅くなるよりも、むしろ多様な技術に精通することがプログラマーとしての成長に繋がるという考え方です。

## 3. Python滅ぼす協会に入会する理由

さて、私がなぜ「Python滅ぼす協会」に入会しようかと思ったのか。
それは~~Pythonが滅べばいいと思っているから~~ Pythonのみではなくてもっと多くの技術の知識を取り入れるためです。
Pythonに依存しすぎることで、「Pythonの得意分野以外ではどうしても手を出せない」という状況になってしまうこともあります。
たとえば、組み込みシステムやリアルタイムシステムの開発では、CやC++が主流であり、Pythonでは実現できないことも多いのです。
こうした技術に触れることで、自分のスキルを広げ、さらに多様な領域に挑戦できるようになるのではないかと思うのです。


## 4. 結論: バランスが大切

「Python滅ぼす協会」の入会を検討することは、あくまでバランスを取るための第一歩です。Pythonを全く使わない世界を目指すのではなく、Pythonという優れたツールを活用しつつ、他のプログラミング言語や技術にも触れてみることが大切だということです。プログラミングは常に進化している分野であり、どの言語にも一長一短があります。Pythonだけに頼らず、多様な技術を身につけることで、より柔軟で広い視野を持ったエンジニアになることができるのです。

最終的に、どの言語を使うかは自由です。そして、最も大切なのは「問題を解決するための適切なツールを選ぶ力」を養うことです。Pythonが最適な選択である場面もあれば、他の言語が適している場面もあります。そのため、「Python滅ぼす協会」に入会することは、単なる反抗ではなく、より良いエンジニアとして成長するための一歩なのです。

## 注釈

筆者はPythonアンチをしていますが、後学のためにたまーに書いてます。
バランスよくPythonも学びましょうね皆さん。
JekyllをMacにインストールする手順

HTMLコーディングを効率化できる静的WebサイトビルダーのJekyllをインストールする方法をまとめました。

ここではMacでHomebrewを使ったインストール方法を紹介します。

## 1:Homebrewのインストール
もしHomebrewがまだインストールされていない場合は、以下のコマンドをターミナルに貼り付けて実行します。ターミナルは、Finderの「アプリケーション」フォルダ内の「ユーティリティ」フォルダにあります。

```
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```

このコマンドを実行すると、Homebrewのインストールが開始されます。途中でパスワードの入力を求められる場合があります。

## 2:Rubyのインストール
JekyllはRubyで動作するため、Rubyをインストールする必要があります。Homebrewを使って簡単にインストールできます。ターミナルで以下のコマンドを実行します。

```
brew install ruby
```

## 3:Rubyのパスを通す
rubyコマンドを使えるようにするため、Rubyのパスを環境変数に設定します。ターミナルで以下のコマンドを実行します。

```
echo 'export PATH="/opt/homebrew/opt/ruby/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
```

もし.zshrcファイルが存在しない場合は、代わりに.bash_profileまたは.bashrcを使用してください。いずれかのファイルに上記のコマンドを追記し、sourceコマンドでファイルを読み込み直してください。

## 4:Bundlerのインストール
BundlerはRubyの依存関係を管理するツールのこと。Jekyllのインストールと管理に必要なので、以下のコマンドでインストールしておきます。

```
gem install bundler
```

## 5:Jekyllのインストール
次にJekyllをインストールします。ターミナルで以下のコマンドを実行します。

```
gem install jekyll bundler
```

## 6:Jekyllのバージョン確認
インストールができたか確認するために、以下のコマンドを実行します。

```
jekyll -v
```

## 7:サイトを作って動作確認
Jekyllのインストール後、簡単なサイトを立ち上げて動作確認することができます。ターミナルで以下のコマンドを実行しプロジェクトフォルダを作ります。

```
mkdir jekyll-project
cd jekyll-project
```

次に新しいサイトを作成します。プロジェクト名をmy-jekyll-siteとすると、以下のコマンドを実行します。

```
jekyll new my-jekyll-site
cd my-jekyll-site
```

以下のコマンドを実行してJekyllサーバーを起動します。

```
bundle exec jekyll serve
```

実行してしばらくすると`Server address: http://127.0.0.1:4000/`のようなテキストが表示されます。これがサーバーのURLです。ブラウザで`http://127.0.0.1:4000/`にアクセスしてトップページが表示されれば完了です。

この状態でHTMLファイルを編集して保存した後、ブラウザを更新すると変更が適用されているはずです。

サーバーを停止するときはターミナルで`Ctrl + C`キーを押します。
[Spring Framework] クラス名から分かるクラスごとの各役割


# 本記事について
業務でSpringBootのクラスの各役割について学んだ。

# クラスごとの役割の種類
Controller
Service
Configuration
Interface
Entity
Repository
Utility
Exception
Advice
Interceptor


# 各役割
## Controller
Controllerとは、主にクライアントからのリクエストを受け取って、最終的にレスポンスを返す役割。

ロジックについてはController内では行わず、Serviceのメソッドを実行する。

処理を大まかにcontrol(操作)しているイメージ。

## Service
Serviceとは、Controllerでもあげた通りロジックを持たせる部分。

Serviceクラスにロジックを集中させることにより、可読性があがる。

ただ、1部のロジックについてはService内では持たせずに他のクラス(Utilityなど)に持たせた方が良い場合がある。



## Configuration
Beanのデータを格納しているクラス。
そのため、主にプロパティのデータを格納していた。

getterやsetterも必要


## Interface
データを呼び出す処理を、Interfaceのクラスで定義しているイメージ。

調べてみたところ、RESTクライアントをを使用する場合はInterfaceとするのが良いとのこと。
現場によってルールが違いそうなので注意したい


## Entity
Entityは、データベースのテーブル構造を表している。
テーブルの内容をオブジェクトに格納する。

## Repository
Repositoryは、APIやデータベースにアクセスする際に使用される。
Repositoryパッケージの中にEntityがあるイメージ。

## Utility
Utilityは複数のクラスで使用しそうな処理をstatic領域において、簡単に呼び出せるようにするクラス。
StringからIntに型を変換するような処理や、共通で使用できそうな汎用的な処理を置いておくイメージ。


## Exception
Exceptionクラスは、名前の通りエラーエクセプションの情報を保持するクラス。

基本的に〇〇Exceptionクラスを継承して使用する。
RuntimeExceptionクラスを継承して独自のExeptionを作ることが多い。

## Advice
Adviceクラスは、throwされたExceptionの処理を共通化するクラス。

Adviceクラスで`@CotrollerAdvice`と指定すれば、`@Cotroller`のついたコントローラークラスでExceptionがthrowされた際に、Adviceクラスの処理に移行する。


## Interceptor
Interceptorは、コントローラーの前や、特定のクラスを実行する前に実行したい処理がある場合に、使用するクラス。

事前に実行したい共通処理がある場合に重宝する。

例えば、APIを実行するための認証情報を取得する処理など入れたりする。


# おわりに
Spring関係なく、Javaのコードでも使用するものも多かったが、Springでさらに役割が分別されており、可読性が高いと感じた。

他のフレームワークだとどのようなクラスの構成になるのかなどが気になった。