OmniAICreator/Qiita-1.07M huggingface dataset:
【おまけ】JDBCについて

## JDBCとは
JDBCとはJavaからリレーショナル・データベースに接続するための標準インタフェース（API）のことを言う。JavaからDBに接続をする・SQL文を実行する・トランザクションを実行するといったことができる。

## JDBCのイメージ
JDBCはJava API、JDBCドライバマネージャー、JDBC DriverAPI、JDBCドライバーが構成要素。

### JDBC API
Javaアプリケーションとデータベースのやり取りを行うための標準的なインターフェースで、SQLクエリの実行や、結果セットの取得などを行う。JDBC APIを使用することで、アプリケーション開発者はデータベースの種類に依存しないコードを書くことができる。

### JDBCドライバマネージャー
JDBC APIと各データベースのドライバの仲介役。JavaアプリケーションがどのJDBCドライバを使用するかを管理し、適切なドライバに接続を振り分ける。

### JDBCドライバ
特定のデータベースに接続する。各データベースベンダーが提供しており、データベース固有の通信プロトコルを使用して接続を確立・管理する。

### 動作イメージ
Javaアプリケーションがデータベースにアクセスする際、以下の順序で各構成要素が関与する。

1. JavaアプリケーションがJDBC APIを通じてデータベース接続やクエリ実行を要求する
2. JDBC APIは、この要求をDriverManagerに渡す
3. JDBCドライバマネージャーは、ロードされた適切なJDBCドライバを選択する
4. 選択されたJDBCドライバが、実際のデータベースとの通信を行う

## メソッド紹介

### getConnection()
DB接続用のメソッド。

```
con = DriverManager.getConnection(url,user,parrword)
```

:::note info
**URLの例**
jdbc:mysql://localhost:3306/flmとは何か
:::
### createStatement()
ステートメント作成用のメソッド。ステートメントとはJavaアプリケーションからデータベースにSQLクエリを送信し、その結果を取得するためのJDBC APIの一部。

```
stmt = con.createStatement()
```

### executeQuery()
クエリを実行してデータを取得するメソッド。

```
res = stmt.executeQuery(sql)
```


### executeUpdate()
クエリを実行してデータを更新するメソッド。

```
int deleteCount = stmt.executeUpdate(sql)
```

### ResultSetインタフェース
データベースの結果セットを表すデータの表で、通常、データベースに照会する文を実行することによって生成される。

イメージとしては以下。nextメソッドで参照するデータの列を次に移動させることができる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2521217/618c94b3-7a75-ea3a-19ef-2140e13e714d.png)

### getxxx()
ResultSetから値を取り出すことができる。取り出し方は以下の2通り。
XXXにはデータ型(IntやStringなど)が入る。

列番号で取り出し
```
getXXX(index)
```


列名で取り出し
```
getXXX(colName)
```

列番号が可変になる場合もあるので、列名で取り出す方がおすすめ。

### close()
接続をクローズするメソッド。
```
con.close()
```

### preparedStatement()
プリペアードステートメント作成用のメソッド。SQL文中にパラメータプレースホルダー（?）を使用して動的な値を指定することができる。


```
stmt = con.preparedStatement("SELECT NAME from EMPLOYEE WHERE ID = ?")
```

ステートメントとプリペアードステートメントの違いは以下。

| 特長 | Statement | PreparedStatement |
| ----| ---- | ---- |
|SQLクエリの実行方法| 毎回SQL文を解析・コンパイル | 最初に1回だけ解析・コンパイル |
| パラメータの使用| 直接文字列に埋め込む | ? を使用して動的パラメータを設定 |
| SQLインジェクション対策| リスクが高い | 安全 |
| パフォーマンス| 毎回コンパイルするため効率が悪い | 一度コンパイルされるため効率が良い |

### setXXX
プレースホルダーに値をセットする。XXXにはデータ型(IntやStringなど)が入る。
第一引数に何番目のプレースホルダーか，第二引数にプレースホルダーに入れる値をセットする。

```
stmt.setInt(1,922104)
```

## トランザクション
トランザクションとは、データベースにおける一連の操作をひとまとめにして、すべて成功するか、またはすべて失敗するかを保証する仕組み。トランザクションに関するメソッドは以下。

### 自動コミットモードの解除
```
con.setAutoCommit(false)
```

### トランザクションの確定
```
con.commit()
```

### トランザクション取り消し
```
cno.rollback()
```
BlenderのモデルをBambu Stduioで3Dプリントしてみたよ

Black Fridayで安くなっていた高性能と噂のBambu Lab A1 miniを購入したので、Blenderで作成したモデルを3Dプリントしてみました。私みたいな初心者の人もいるかと思うので、簡単な流れをまとめてみました。

https://x.com/machidyo/status/1865308790775841243

# 前提
- Blender 3.4.1
- Bambu Studio 1.10.1.50

# 流れ
## 1. BlenderからSTLでエクスポート
1. Blenderで3Dプリントしたいモデルを開きます
2. 私は念のためカメラなど印刷しないオブジェクトは削除しました。対応不要かもしれませんが未調査です
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506075/ddefcf59-5930-49d8-4152-e40301694823.png)
3. stlでエクスポートします。特にエクスポート時の設定は変更しませんでした    
    ![image (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506075/13a9cdf0-90a5-b93d-ec77-015444aef2f2.png)

## 2. Bambu Studio
### 2.1 Bambu Studioの設定
1. Bambu Studioを起動します
2. ホームからログインします。しなくても問題ないですが、3Dプリンターの設定をしたときに自身のアカウントとプリンターを紐づけているかと思います。その情報を引っ張ってきてくれるので、楽です。（良くできてる！）
3. 自身のプリンターの設定をします。私の場合の設定を参考においておきます
    ![2024-12-09_15h39_14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506075/39fdde74-a99c-7b16-6208-e058297e7d5a.png)    

### 2.2 STLファイルの3Dプリント
1. BlenderからエクスポートしたSTLファイルをインポートします    
    ![2024-12-09_15h35_53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506075/5554359d-20a4-ab04-dfb8-c0bbb3965067.png)    
2. 警告が出た場合、はいを選択します。
    ![2024-12-09_15h36_58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506075/61bc00dd-54fd-77c4-c3aa-09fbee6064d3.png)    
3. 画面上部にある自動向き調整を押します。ちょっと下にあったりすると自動でプレートまで移動させてくれます
    ![2024-12-09_15h45_21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506075/6dcb5e60-870f-caad-2ad5-ffe91c909d79.png)    
4. スライスボタンを押してスライスします    
    ![2024-12-09_15h46_50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506075/25e2414d-9931-14f4-6c78-6eb1dfb66b00.png)

    :::note info
    スライスとは、3Dプリンタがモデルを印刷していく順番を、層として分割するようなイメージです
    
5. 警告が出ていないか確認します。警告が出ていなければ準備完了です！以下警告が出ている場合、6の手順を試してみてください
    ![2024-12-09_15h47_30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506075/bf4fce50-106c-27af-1490-5e3f1351ff50.png)    
    ```
    It seems object xxx.stl has floating cantilever. Please re-orinet the object or enable support generation.
    ```    
6. 警告が出ている場合、プレビュー（①） → サポート（②） → 有効化（③）にチェックを入れて、再度スライスしてください。
    ![2024-12-09_15h53_38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506075/1d5ee3d7-a7f9-c7db-f115-3a603bf7c814.png)  

    :::note info
    Bambu Lab A1 miniは冷却に時間を必要とするため、空中にプリントすることができません。そのため浮いているところは何かしらの補強みたいなもので仮支えして出力する必要があります。それがサポートです。
    この図では①の箇所が浮いているので、②のサポートで支えて印刷します。サポートは印刷後に簡単に取ることができます。
    ![2024-12-09_15h58_56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506075/40ff3ce3-5120-cdbf-799b-52ab23253b02.png)
7. 造形開始ボタンを押して造形を開始します。後はできあがるまで待つだけです
アイディアを技術に落とし込む方法

# ご挨拶

初めまして！

未経験からエンジニアを目指しRUNTEQでプログラミング学習中のあいと申します。
11月末には卒業制作のアプリのMVPを取得し、無事に卒業認定をいただきました。
現在は本リリースに向けてアプリ開発を続けています。

今回は、アプリ開発を始める際に誰もが悩むであろう、「やりたいこと」と「機能」をどのように「技術」に落とし込んでいくのか、その手順についてお話しします。これからアプリ開発に取り組もうとしている方の参考になれば幸いです。


# 前提

- 筆者のバックグラウンドは芸大でデザインやクリエイティブなことを専攻してました。アートやデザインの世界では、アイディアを生み出す際にリサーチをたくさんすることは当たり前です。そのため本記事はその考え方が元になっております。
- あくまで筆者の1つの考え方であるため、全ての方に当てはまるとは限りません。
- 初学者がアプリ開発を通して学んだことをまとめておりますので、温かい目で見守ってくださると幸いです。
- もし別の方法でうまくいっている方がいらっしゃれば、教えていただけますと幸いです。


---

# たくさんアプリを触ってリサーチしよう！

RUNTEQ生の場合、ソーシャルポートフォリオなどを通じて先輩方のアプリにアクセスできます。実際にアプリにログインして、以下のポイントを意識しながら隅々まで触ってみてください。

- **RUNTEQ生の場合のおすすめのリサーチ先**
    - ソーシャルポートフォリオ
    - RUNTEQのアプリイベント用の特設サイト
    - - [Letters Tubu](https://letters-tube.vercel.app/)
    - インターネットやYouTubeなどでプログラミング学習中の個人開発アプリを探す
- **どんな機能がどの技術で実装されているのか？**
    - RUNTEQ内の学習記録（times）やQiitaやZennの記事、開発者ブログなどの開発者のアウトプットから探します。
    - どんなAPIを使っているのか、ロジック、機能名などが書かれているかもしれません。
- **その機能はコードのどこで実装されているのか？**
    - まず、該当アプリのGitHubにコードを見に行きます。
    - コントローラー、モデルのタイトル名やコミットメッセージからここかもしれないと思う単語を見つけます。
    - 該当ファイルを開き、ここかもしれないと思うコードを自分で読み解いたり、AIに解説を依頼したり、どうしてもわからない場合は、聞けるなら開発者に質問してみてもいいかもしれません。

また、実際に触ってみて感じたことも重要です。

- アプリ開発者がどのような目的でその機能と技術をそのアプリに使っているのか。
- 機能、技術、アプリ、サービスそれぞれが、あなた自身にどのような効果を与えてくれるか？



# 手札を増やし、アイディアに技術を当てはめる

### 1. **リサーチで手札を増やす**

アプリや技術を調べることで、たくさんの実装例や技術の組み合わせが手札として手に入ります。

「〇〇機能には△△技術が使われている」といった情報が蓄積されると、次にどの技術を使えば良いか自然とわかるようになります。

### 2. **自分のアイディアに置き換えて考える**

増えた手札を元に、作りたい機能を技術に変換してみましょう。

例:

- 「〇〇機能を実装したい」 → 「△△技術を応用すればできるかも！」



# 人に相談することを選択肢に入れよう

初めて挑戦することは、一人で考えてもなかなか解決できないことが多いと思います。

例えば、

- どの技術で機能を実装しているのか？
- コードのどこに目的の処理が書かれているのか？
- 手札は増えたが作りたい機能を技術に変換する感覚がつかめない

こうした壁にぶつかったら、**人に相談する** ことも一つの方法です。

RUNTEQでは、エンジニアの方との技術面談で相談できます。そしてコミュニティ内の仲間に相談することもできます。他の視点を得ることで新しい考え方やアプローチに気づけることも多いです。私自身、人に相談して壁を乗り越える経験をしてきました。

ただ、相談するときは**相手にリスペクトを持つこと**が大切です。自分なりに調べたり考えたりした上で質問し、感謝の気持ちを伝えることで、より良いコミュニケーションや学びにつながります。

一人で考える力も大切ですが、相談することで学びが加速することをぜひ覚えておいてください。相談を通じて得た知識や視点は、必ず自分の成長につながります。

---

# まとめ

やりたいことを技術に変換するには、まずは**リサーチ**を繰り返しそれでも難しければ**相談する**ことが大切です。技術の使い方や組み合わせを学び、少しずつ自分のアイディアに落とし込んでみてください。

私自身、最初は何をどうやったらいいのか途方に暮れたこともありますが、この方法で少しずつ**アイディアを技術に落とし込み**、最終的にアプリを作り始めることができました。この記事が少しでもお役に立てたら嬉しいです！




# 参考サイト
- [Letters Tubu](https://letters-tube.vercel.app/)
今いる仮想端末がtmuxの中にいるか判定するワンライナー

# 今いる仮想端末がtmuxの中にいるか判定するワンライナー

```
[[ $(tty) == $(tmux list-panes -F '#{pane_tty}') ]] && echo true || echo false
```

## 概要

* `tmux display-message -p '#S'` でセッション名を表示できる。
* ただ、tmuxの外にいても、別の仮想端末でtmuxが起動していたらセッション名が表示できてしまう。
* そのため、今いる仮想端末がtmuxの中にいるか判定する目的には利用できなかった。
* そこで、`tty`と`tmux list-panes -F '#{pane_tty}'`の出力の一致を判定する。

## 解説

* `tty` で現在の端末デバイス名を表示する
* `tmux list-panes -F '#{pane_tty}'` で今のペインの端末デバイス名を表示する
* 一致すれば true 
* 不一致なら false

## `$(tty)`

* ttyコマンド
* 現在の端末デバイスを表示する

```
$ tty
/dev/ttys001
```

## `$(tmux list-panes -F '#{pane_tty}')`

* tmux list-panesコマンド
* -F でフォーマットを指定して、ペインの端末デバイスを表示する
* wiki: https://github.com/tmux/tmux/wiki/Formats
* code: https://github.com/tmux/tmux/blob/c311202b73e861a4b41e64bd411286675570043f/tmux.1#L6000

```
$ tmux list-panes -F '#{pane_tty}'
/dev/ttys004
```
UserFormテンプレ.csv

フォーム名,,コントロール名
BackColor,,Accelerator
BorderColor,,Alignment
BorderStyle,,AllowColumnReorder
Caption,,Appearance
Cycle,,Arrenge
DrawBuffer,,AutoSize
Enabled,,AutoTab
Font,,AutoWordSelect
ForeColor,,BackColor
Height,,BackStyle
HelpConTextID,,BorderColor
KeepScrollbarsVisible,,BorderStyle
Left,,BoundColumn
MouseIcon,,Cancel
MousePointe,,Caption
Picture,,Checkboxes
pictureAlignment,,ColumnCount
PictureSizeMode,,ColumnHeads
PictureTiling,,ColumnWidths
RightToLeft,,ControlSource
ScrollBars,,ControlTipText
ScrollHeight,,Cycle
ScrollLeft,,Default
ScrollTop,,Delay
ScrollWidth,,DragBehavior
ShowModal,,DrawBuffer
SpecialEffect,,DropButtonStyle
StartUpPosition,,Enabled
Tag,,EnterFieldBehavior
WhatThisButton,,EnterKeyBehavior
WhatThisHelp,,FlatScrollBar
Width,,Font
Zoom,,FontSize
Font.Name,,FontBold
Font.Size,,FontItalic
Font.Bold,,FontStrikethrough
Font.Italic,,FontUnderline
Font.Strikethrough,,ForeColor
Font.Underline,,FullRowSlect
,,GridLines
,,GroupName
,,Height
,,HelpConTextID
,,HideColumnHeaders
,,HideSelection
,,HotTracking
,,HoverSelection
,,IMEMode
,,IntegralHeight
,,KeepScrollbarsVisible
,,LabelEdit
,,LabelWrap
,,LargeChange
,,Left
,,ListRows
,,ListStyle
,,ListWidth
,,Locked
,,MatchEntry
,,MatchRequired
,,Max
,,MaxLength
,,Min
,,MouseIcon
,,MousePointer
,,MultiLine
,,MultiRow
,,MultiSelect
,,OLEDragMode
,,OLEDropMode
,,Orientation
,,PasswordChar
,,Picture
,,pictureAlignment
,,PicturePosition
,,PictureSizeMode
,,PictureTiling
,,ProportionalThumb
,,RightToLeft
,,RowSource
,,ScrollBars
,,ScrollHeight
,,Scrolling
,,ScrollLeft
,,ScrollTop
,,ScrollWidth
,,SelectionMargin
,,SelLength
,,SelStart
,,SelText
,,ShowDropButtonWhen
,,ShowModal
,,SmallChange
,,Sorted
,,SortKey
,,SortOder
,,SpecialEffect
,,StartUpPosition
,,Style
,,TabFixedHeight
,,TabFixedWidth
,,TabIndex
,,TabKeyBehavior
,,TabOrientationTop
,,TabStop
,,Tag
,,TakeFocusOnClick
,,Text
,,TextAlign
,,TextBackground
,,TextColumn
,,Top
,,TopIndex
,,TriPleState
,,Value
,,View
,,Visible
,,WhatThisButton
,,WhatThisHelp
,,Width
,,WordWrap
,,Zoom
PyTorch→ONNX→TensorRTの変換

研究室でTensorRTのモデルをC++で動かして推論をしているのですが、毎回変換の細かい手順を忘れるので書き残しておきます。
特にONNX→TensorRTの変換に癖があって、私の経験上だと入力テンソルの大きさが可変だとだいたいうまくいきません。

# PyTorch→ONNX
```py:convert.py
import torch
import torch.onnx

model = MyModel()
model.load_state_dict(torch.load('hoge.pth'))

torch.onnx.export(model, torch.randn((1,3,720,1280)), 'hoge.onnx')
```

# ONNX→TensorRT
`trtexec`を使います
```bash
trtexec --onnx=hoge.onnx --saveEngine=hoge.trt
```
GraphQLを1から勉強しなおしてみた ~ スキーマと型 Part2 ~

# はじめに
先日に引き続きGraphQLを一から勉強し直していきます。

前回はこちら。

https://qiita.com/mattsu_mocha/items/7e375eb71fe24a5eda33

# 型
インターフェースから続きを書いていく。

https://graphql.org/learn/schema/#interface-types

## インターフェース型
複数の型間で共通のフィールドを定義するための抽象型。

```graphql
# 抽象型
interface Character {
  id: ID!
  name: String!
  friends: [Character]
  appearsIn: [Episode]!
}


type Human implements Character {
  id: ID!
  name: String!
  friends: [Character]
  appearsIn: [Episode]!
  starships: [Starship]
  totalCredits: Int
}
 
type Droid implements Character {
  id: ID!
  name: String!
  friends: [Character]
  appearsIn: [Episode]!
  primaryFunction: String
}
```

また、インターフェースをimplementして新たなインターフェースを定義することもできる。

```graphql
interface Node {
  id: ID!
}
 
interface Character implements Node {
  id: ID!
  name: String!
  friends: [Character]
  appearsIn: [Episode]!
}
```

## ユニオン型
複数の型のいずれかを返すことができる型。共通のフィールドを持たない異なる型をまとめる時に使う。

ユニオン型に使えるのは具体的なオブジェクト型のみで、インターフェース型や他のユニオン型を使うことはできない。

```graphql:ユニオン型
union SearchResult = Human | Droid | Starship

type Human {
  name
  height
}

type Droid {
  name
  primaryFunction
}

type Starship {
  name
  length
}
```

```graphql:例
{
  search(text: "an") {
    __typename
    ... on Human {
      name
      height
    }
    ... on Droid {
      name
      primaryFunction
    }
    ... on Starship {
      name
      length
    }
  }
}
```

またインターフェース型で記載したように、`Human`と`Droid`は`Character`インターフェースをimplementしているため、以下のように書くこともできる。

```graphql
{
  search(text: "an") {
    __typename
    ... on Character {
      name
    }
    ... on Human {
      height
    }
    ... on Droid {
      primaryFunction
    }
    ... on Starship {
      name
      length
    }
  }
}
```

## input
引数で入力値を指定するときに`input`を使って型を指定することもできる。
```graphql
input ReviewInput {
  stars: Int!
  commentary: String
}
 
type Mutation {
  createReview(episode: Episode, review: ReviewInput!): Review
}
```

## ディレクティブ
クエリやスキーマの特定の部分に対して、追加の動作や条件を指定するためのもの。

以下は標準ディレクティブだが、独自のカスタムディレクティブを定義することもできる。

### deprecated
非推奨であることを示す。

```graphql
type User {
  fullName: String
  name: String @deprecated(reason: "Use fullName.")
}
```

### include
指定された条件が`true`の場合に含める。

```graphql
query getUser($withEmail: Boolean!) {
   user(id: "1") {
     id
     name
     email @include(if: $withEmail)
   }
}
```

### skip
指定された条件が`true`の場合にスキップする。

```graphql
query getUser($withoutEmail: Boolean!) {
   user(id: "1") {
     id
     name
     email @skip(if: $withoutEmail)
   }
}
```
転職した1年後に転職者の面接をする立場になって気づいたこと

## 転職したときのことを思い出してみた

元々、私はSIerとして働いていた。
そのとき、転職先として選んだのは同業他社ではななかった。

なによりも、「受託開発」という立場から逃げたかったのだ。

## 転職をするときに気を付けていたこと

### 自分が得意な分野

自分が得意なものはなにか？を書いた。

この部分については、長年某フリーランス向けサイトで営業活動をしてきた賜物だと思っている。
自分をある程度客観的に見て、相手に刺さるであろうポイントを列挙した。

特に、その企業の使っているスタックに近いものをピックアップした。

SIにありがちな業務経歴書をそのまま出しても長いだけなので、
読んでほしいものだけをピックアップした。

たとえば、Javaを利用しているのであればJavaのプロジェクトをピックアップしたし、
Reactを使っている企業であればそれをピックアップ・・・という感じ。

~~結果として、まともに使ってないGoがメインになっているとは大声では言えない~~

### その業界を目指す理由

とにかく、SI/SESからは離れたかった。

自社サービスを展開している企業を狙った。

そのためにも、「その業界を狙っているんだ」という意思を明確に出すことを意識した。
（その企業というよりも業界、というレベル。）

実際、SIからの転職ということもあり、志望動機についてはどの企業でも聞いてきた、と記憶している。

## 転職から約1年後・・・

なぜか求人をチェックし、面接する側の人間になっていた。

人生とは不思議なものである。

## エンジニア転職で自分がさらにチェックするようになったこと

### 自分は「何を考えて何ができるか」

端的に言うと得意分野は何か？というところである。

特にSI/SES出身者にありがちなのが、「参画していたプロジェクトの情報」のみを記載していること。

これも転職時に勘違いしていたポイントであったが、「前職でのプロジェクト経験そのもの」はあまり判断されない。
「そのプロジェクトで何を考えて何をやったか」を重視する。

実際、自分がいろいろと面接を受けた際もこの手の質問はあった。

自分が面接する側にまわった瞬間、これは非常に重要だと気づいた。
だって書類からは分からないんだもん。実際にその人のスキル（プログラミングとかではなく、人としてのスキル）がどの程度なのかをしっかりと見極める必要があると気づいた次第。

#### ウォーターフォールの悪魔

余談になるが、仮に「要件定義から試験まで経験しました」という人がいたとする。
さて、この人は実際に要件定義で何を実施したのだろうか。

実際には前面に立って調整をしていたかもしれないし、実は書類を作っていただけかもしれない。
それでも、完成品を知っているだけで全然違うので経験したという事実は重要である。

その上で、どこまでこの人が「デキる人」なのかをしっかりと見極める必要があるのだなぁ・・・と感じた。

### 業界への理解・志望動機

これは、SI/SESから自社サービス系の企業へ転職する際に見落としがちなポイントである。

特に業界チェンジをする場合、「なぜその業界を選んだのか」ということが書かれていないことが多い。

自分はとてもそこを気にして書いたので、書いていない人が多いことに驚いた。
本当に要員面談のつもりか？というような職務経歴書のひともいっぱいいた。

特にハイスキルのひとの場合、大量に内定をもらうことになると思うので、どこまで自分ところに本気なのかが分からない。
逆に、志望動機があればスキルアンマッチでも育成枠として推すことも辞さない。
そうなると、希望年収とスキルが少しでも嚙み合ってないとお祈り・・・となる可能性がある。

### 業務外でがんばっていること

エンジニアとして大成するためには、自分で学習する意欲が必須であると考えている。

もちろん、業務時間内だけでキャッチアップできるならそれでも良いが、やっぱりキャッチアップできるための下地が必要である。
結局、そうなると情報収集のクセをつけているとか、遊び半分で新技術を触ってみたりしている人に来てほしいなぁ、と思っているところである。

副業している人とか最高だと思うんだよね。

## 逆に、あまり気にしないところ

### 退職理由

割とどうでもよかった。
理由そのものを気にするのは、「明らかに転職スパンが短いとき」である。

流石に、短いスパンで転職を繰り返すジョブホッパーみたいな人は日本では好まれない傾向がある。
ジョブ型ではなくメンバー型採用をしている以上、すぐに辞められるリスクは看過できない。

逆に言えばそれくらいのもので、エンジニアの転職なんざ人間関係か待遇面がほとんどでしょう。
（もちろん、その待遇にはキャリア形成も含まれるのでそこは考えたいところ）

### 人柄

やべーものはもちろん弾くが、正直会話してみないとわからない。
エージェントが言う「コミュニケーション能力が高く物腰が柔らかく～」という表現は、不動産の「日当たり良好」と同程度、と考えても差し支えない気がしている。（言い過ぎ？）
しょっちゅう見る単語である。というか、そもそもエージェントが扱う人材でコミュ力なかったら、まともに企業を紹介してもらえないのでは？という疑惑もある。

### ポートフォリオ

出してくる人の方がレア・・・というのもあるが、
成果物がある人はそれ以前に「強い」ことが多いので、そこにたどり着く前の時点で魅力的な場合が多い。

そうなると、結果としてポートフォリオは補足事項になってしまう。

個人的にはそういうのが好きなのでむっちゃ見るけど、結果としてポートフォリオの有無そのものが評価に響いたことははかった。

## さいごに

長々と書いてしまったが、一番大事なのは「一緒に働きたいと思わせること」であるとあらためて気づいた。
どんなに優秀な人でも、チームに合わなかったら挙げられる成果も上げられなくなる。

SIやSESであれば現場を変えればチームも変わるのでそこはなんとでもなるが、
だいたいダメな人はどこに行ってもダメだったりするので弾かれるのかもしれない。

というわけで、

**変に取り繕うことをせず、素の自分を出して率直に答えていくこと**

が一番大事だと思います。
JSON-java(org.json)で項目値のnullを空文字して、空要素を<タグ />から<タグ></タグ>に加工する方法

試したコードの一部

Java 17

```java
// JSON文字列
String jsonString = """
{
    "b": "value_b",
    "a": "value_a",
    "c": null
}
""";

JSONObject jsonObject = new JSONObject(jsonString);

// nullを空文字に置き換え
for (String key : jsonObject.keySet()) {
    if (jsonObject.isNull(key)) {
        jsonObject.put(key, ""); // 空文字に置き換え
    }
}
 
// XMLに変換
String xml = XML.toString(jsonObject);

// 空要素形式 (<タグ/>) を置換して (<タグ></タグ>) に変更
xml = xml.replaceAll("<(\\w+)/>", "<$1></$1>");

// 結果を表示
System.out.println(xml);
```

結果
```sh
<a>value_a</a><b>value_b</b><c></c>
```
---
## JSON を XML に変換する際に、値が null または空の場合にタグを削除

```java
// JSON文字列
String jsonString = """
{
    "name": "John",
    "age": null,
    "address": "",
    "city": "Tokyo"
}
""";

JSONObject jsonObject = new JSONObject(jsonString);

// 値がnullまたは空のキーを削除
removeEmptyValues(jsonObject);
 
// XMLに変換
String xml = XML.toString(jsonObject);

// 結果を表示
System.out.println(xml);
```
```java
private static void removeEmptyValues(JSONObject jsonObject) {
    // JSONのキーを反復処理するためのIteratorを取得
    Iterator<String> keys = jsonObject.keys();

    // Iteratorを使って安全にキーを削除
    while (keys.hasNext()) {
        String key = keys.next();
        Object value = jsonObject.get(key);

        // nullまたは空文字列の場合にキーを削除
        if (value == JSONObject.NULL || (value instanceof String && ((String) value).isEmpty())) {
            keys.remove(); // Iterator経由で削除
        }
    }
}
```

結果
```sh
<city>Tokyo</city><name>John</name>
```
なぜ技術書を書いたのか?

# この記事は何?
過去に技術書を5冊書きました。
この記事ではなぜ技術書を書いたのか?、書いた結果、どのようなことがあったか?について書きます。

# 書いた技術書について
技術書典オンラインマーケットで5回技術書を頒布しました。オンラインマーケットの参加のみでオフラインイベントの参加は経験がありません。

書いた技術書はつぎのとおりです。

https://techbookfest.org/organization/5706998658105344

1. [EVカートで始めるモデルベース開発](https://techbookfest.org/product/6581675934875648?productVariantID=5815321967460352)
2. [GCC開発環境構築入門(EVカート編)](https://techbookfest.org/product/4581772882870272?productVariantID=5309574368198656)
3. [CからRustにモータ制御ロジックを移植する](https://techbookfest.org/product/5841041691246592?productVariantID=5858970117865472)
4. [Spresenseデジタルカメラ開発](https://techbookfest.org/product/6145133823131648?productVariantID=6677722182975488)
5. [Spresenseでオリジナルゲームをつくる](https://techbookfest.org/product/1TUdP91Knfjxd7DBLpZvKh?productVariantID=6hn3WTAWnkNpVGed9uvZfR)

# なぜ技術書を書いたか?
なぜ技術書を書こうと思ったか振り返ってみました。

## 自分の知見を整理できると思ったから
本を書くことで自分の知識を整理できると思いました。
矛盾があることや不明な点は調べて本を書くので本のテーマについてより深く学ぶ機会となり、自分の成長につながります。

## 技術書執筆ツールRe:VIEWを使ってみたいと思ったから
技術書執筆ツールRe:VIEWを使ってみたいと思いました。

:::note info
以前、Re:VIEWについて簡単にですがまとめて社内勉強会を実施しました。
よければ見てみてください。

技術書を技術書執筆ツール(ReVIEW)で書いてみよう
https://www.docswell.com/s/juraruming/5D4WVK-2022-07-25-172543
:::

Re:VIEWを環境構築すればテキストベースで本を書けます。
テキストベースであれば、GitHubに書籍のリポジトリを作成し、変更管理していくことも可能です。
ソフトウェア開発のように本も執筆できることを知り、俄然、興味を持ちました。
執筆環境の構築、執筆、変更管理の一連の作業を経験したいと思いました。
私は1人で本を書きましたが、チームで書くのも良いですね。

# 書いた結果、何が良かったか?
本を書いた結果、良かったことです。

## 本をダウンロードしてくれた方のリアクションが嬉しかった
本をダウンロードしてくれた方がXで感想をポストしているのを確認すると嬉しかったです。
執筆作業は苦しい時間帯もありますが、ダウンロード、感想を見るとやってよかったと報われた気持ちになりました。

## 電子書籍の執筆ノウハウが身についた
Re:VIEWの使い方も身につきましたが、執筆作業のノウハウも身についた気がします。
本の全体構成をイメージし、章立てを考え、章の名前を考えることをしっかりすれば、後は執筆に集中できます。
これは技術記事を書くときにも使えるスキルと考えており、本の執筆作業でスキルアップできたと考えています。


# 書いた結果、何が改善点だと思ったか?
本を書いた結果、改善点も見えてきました。

## 表紙
本の中身に集中し、表紙作成に注力できませんでした。
5冊中4冊が真っ白な表紙で味気ないです。
本の中身が良くても目に留まり、ダウンロードしてもらえなければ読んでもらえないため、届けるための努力が必要だと考えています。
今はAIで表紙つくりの敷居も下がったと思うので次回、技術書を書くことがあれば表紙作成にも注力したいと思います。

## 告知
執筆が終わった後は本の告知をして、本の存在を知ってもらうことも必要だと思いました。
苦しんで生み出した技術書なので読んでもらいたい、という気持ちがあります。
表紙と同様、届ける努力が必要だと考えています。

Xで朝、昼、夜に告知はしていましたが例えば次のような告知をしている方もいるので真似したいと思いました。

* 自身のブログで本の紹介をする。ブログのエントリを何回かに分けて各章の説明を書き、購買欲を刺激するような告知に見えた。
* 仲間に本を渡し、自分ではなく第三者に感想を発信してもらう。商業の技術書でも良く見かける手法だと思った。

## スケジューリング
仕事と執筆活動のバランスに苦労しました。極力、仕事に影響ないように動きましたが締切が近くなると夜遅くまで、出社時・昼休みに執筆することもありました。
余裕を持った計画を立てて執筆することが健康面でも重要だと思いました。
【ESLint】flat config で対象ファイルを指定する方法

## `--ext`は使えない

flat configを使用する場合は`--ext`は使えません。

https://eslint.org/docs/latest/use/command-line-interface#--ext

flat configを使用しているのにも関わらず、`--ext`を使用すると以下のようなエラーメッセージが出力されます。

```terminal
Invalid option '--ext' - perhaps you meant '-c'?
You're using eslint.config.js, some command line flags are no longer available. Please see https://eslint.org/docs/latest/use/command-line-interface for details.
```

## 対象ファイルを指定する方法

flat configで対象ファイルを指定するには`eslint.config.js `で`files`を記述します。
`--ext .ts,.tsx`と指定していた場合には以下のようになります。

```js:eslint.config.js

export default [
    {
        files: ["**/*.ts", "**/*.tsx"],
        
        // ...
    }
]

```

https://eslint.org/docs/latest/use/configure/migration-guide#--ext
[Elixir] パイプラインの流れでそのまま変数を定義したい

本記事は、[Elixir Advent Calendar 2024 シリーズ7](https://qiita.com/advent-calendar/2024/elixir)の19日目です。

---

# 変数束縛とパイプライン

Elixirのパイプラインは書いていて楽しいものですが、たまーに変数をおいておかないといけないこともありますよね？

```elixir

data1 = 
  big_data
  |> something_process()

data2 = 
  big_data
  |> another_process()

Enum.zip(data1, data2)
|> hoge_process

...
```

このように変数の列とデータ処理の列がずれます。
これはこれで変数が強調されるので見やすいという意見は当然あり得ます。

が、なんとなく揃えたいなーというのが本記事の動機です。

# 完成系

下記のように追加した構文`bind`が動くことを目指します。

```elixir
[1, 2, 3]
|> Enum.map(& &1 * 2)
|> bind(:a)

IO.inspect(a)
#=> [2, 4, 6]
```

# 説明

最終的には下記２つの要件を満たす必要があります。

1. 変数の用意: 「変数を用意する」という関数の呼び出し
2. 式を追加: 元の計算式に加えて「変数を用意する」という式を追加

## 変数の用意

結論を書くと、`Macro.var/2`を使えば可能です。
引数1は変数名、引数2は`context`と記載されてますが、変数をどのモジュールや関数で定義するか、という情報だと理解すればOK。

livebookやiexだと実行はできますが、効果は発揮できません。
戻り値はElixirにおける内部のコード表現であるASTになっています。

```
iex> Macro.var(:foo, __MODULE__)
#=> {:foo, [], nil}
```

## 式を追加

元の式を書き換える機能といえば、Elixirマクロの出番です。
前項で出てきた変数の内部表現を使ってElixirの式を改変して返します。

# 実装

下記が最終系です。

~~~markdown:livemd
# Bind Macro for Qiita

## Section

```elixir
defmodule Util do
  defmacro bind(ast, var) do
    # 変数の内部表現
    var = Macro.var(var, __CALLER__.module)

    # デバッグ用
    ast
    |> Macro.to_string()
    |> IO.puts()
    |> dbg()

    # 作った変数 = 元のASTという形にして返す
    quote do
      unquote(var) = unquote(ast)
    end
  end
end
```

```elixir
require Util
import Util

[1, 2, 3]
|> Enum.map(& &1 * 2)
|> bind(:a)
```
~~~

## 解説
- CALLERはマクロの呼び出し元の情報を取得します（livebookだと`__CALLER__.module`はnilです）
- quoteで元の式を返します
- unquoteでAST表現されているコードをElixirコードにします
- （メタプロ基本は[ElixirSchool](https://elixirschool.com/ja/lessons/advanced/metaprogramming)を読むのがおすすめ）

---

パイプラインから続けて変数束縛できるようにしました。
Rust Lang) adt_easy_20241217_1 - A, B  

# Source code

```rust
use std::io::{stdin, BufRead};

fn solution_a(){
    let std= stdin();
    let mut buf= std.lock().lines();
    let n= buf.next().unwrap().unwrap()
    .parse::<u32>().unwrap();
let c= char::from_u32(n).unwrap();

println!("{}", c.to_string());    
}

// https://atcoder.jp/contests/adt_easy_20241217_1/tasks/abc304_a
pub fn solution_b(){
    let mut result_v: Vec<String>= Vec::new();
    let mut s_v: Vec<Vec<String>>= Vec::new();

    let std= stdin();
    let mut buf= std.lock().lines();
    let n= buf.next().unwrap().unwrap()
    .parse::<u32>().unwrap();

    for _ in 0..n {
        let person: Vec<String>= buf.next().unwrap().unwrap().clone()
            .split_whitespace()
            .map(|f| f.to_string())
            .collect();
        s_v.push(person);
    }
    
    let mut ages: Vec<i32>= Vec::new();

    for v in s_v.clone() {
        ages.push(v[1].parse::<i32>().unwrap());
    }

    let min= ages.iter().min().unwrap();

    let mut idx= 0;
    for (i, v) in s_v.clone().iter().enumerate(){
        let v= v[1].parse::<i32>().unwrap();
        if *min == v{
            idx= i;
        }
    }

    for i in idx..(n as usize){
        result_v.push(s_v[i][0].clone());
    }

    for i in 0..idx{
        result_v.push(s_v[i][0].clone());
    }
    
    for v in result_v {
        println!("{}", v);
    }
}

fn main(){
    // https://atcoder.jp/contests/adt_easy_20241217_1/tasks/abc252_a
    // solution_a();

    // https://atcoder.jp/contests/adt_easy_20241217_1/tasks/abc304_a
    solution_b();
}

```
【学生エンジニア向け】インターンシップの分類と成長戦略

## はじめに

こんにちは、技術食いつき虫noll:v:です。
学生エンジニアとして複数の企業でインターンシップやアルバイト、業務委託として活動しています。
また、アンバサダー活動やコミュニティ活動にも積極的に参加し、
最新の技術トレンドを追うことを趣味としています。

SNSリンク集: [Rei Suzukiのリンク集](https://linktr.ee/Rei_suzuki)


## なぜこの記事を書くのか

「インターンシップ」という言葉は人によって捉え方が異なり、
会話の中でミスマッチが生じることが多々あります。
そこで、インターンシップの分類を整理し、
エンジニアを目指す学生にとって有益な情報を提供したいと考え、
この記事を書きました。


## インターンシップの分類

学生エンジニアの間では、インターンシップは期間の長さによって以下のように分類されることが多いです

- **短期インターン**: 数日から2～3週間程度。主な目的は、企業の雰囲気や働き方を体験することです。

- **長期インターン**: 数ヶ月から年単位。実務経験を積み、給与を得ることが主な目的です。

しかし、技術的な成長に焦点を当てると、単に期間の長さだけでインターンシップを評価するのは適切じゃないです。
重要なのは、インターンシップでの具体的な業務内容や得られる経験だから。

例えば、同じ企業で同じポジションやチームに長期間所属し続けることには注意してください。
その理由は、別の記事で書きます。

多様な経験を積むためには、異なる環境や役割に挑戦したほうがいいと思います。

なぜなら、
自分に合ったポジションや業界、働き方、待遇を見つけるために、情報収集と選択肢を増やすことを目的に動いたほうがいいからです。
そのポジションが自分にあっているかどうかは、やってみないと分からないですからね。

また、数年の業務経験を持つソフトウェアエンジニアの知識や技能、考え方などを取り入れることを目指しましょう。

## 成長のためのインターン戦略

以下では、卒業までの期間と現在の技術レベルの2軸に基づいて、インターンシップの戦略を提案します。

### 卒業まで3年以上ある場合

#### 未経験（実務経験なし）

- エンジニアの社員と一緒に働ける環境を目指して、積極的に応募しましょう。私自身、約40社に応募した経験があります。
- 最低限、自走できる能力（調べながらコードを理解し、応用できる力）を身につけましょう。応募と学習を並行して進めることが重要です。
- おすすめの教材として、TechtrainやProgate Path、Udemyなどがあります。

#### 実務経験あり（メンターのサポートのもと業務を遂行できる）

- 現在の企業で努力しつつ、幅広い経験（フルスタック）を積むよう心掛けましょう。
  - 例: フロントエンドの経験者がバックエンドのタスクに挑戦するなど。
- 希望するポジションが現在の企業にない場合は、他の企業への応募も検討しましょう。

#### 高度な実務経験あり（一人でタスクを処理できる）

- リソースが許す限り、社内での昇進を目指すか、副業や他社でのインターンを検討しましょう。
- 特に他の分野でも専門で仕事ができるぐらい身に着けておくとベスト。
  - 複数インターンの掛け持ちで、それぞれ違うポジションで働く。
- 海外での経験にも目を向けてみましょう。

### 卒業まで約2年（就活開始時期）

#### 未経験（実務経験なし）

- 長期インターンを重視しつつ、短期インターンにも積極的に応募しましょう。
- 自走力を身につけるための学習を継続し、応募と並行して進めましょう。
- TechtrainやProgate Path、Udemyなどの教材を活用しましょう。

#### 実務経験あり（メンターのサポートのもと業務を遂行できる）

- 通常時は前述の戦略と同様ですが、夏から冬にかけて興味のある企業のインターンに参加しましょう。
- プログラムの内容を事前に確認し、参加の価値を自分で判断しましょう。

#### 高度な実務経験あり（一人でタスクを処理できる）

- 自身の判断でキャリアを選択しましょう。目指すキャリアを持つ複数の人に話を聞くのも有益です。
- 海外での経験も視野に入れましょう。


## 最後に

企業によっては、インターン経験者を優先的に採用する場合もあります。そんなチャンスを逃さないよう、積極的に動きましょう。

もしインターンに落ちたとしても、そんなにへこまないでください。インターンには、いろいろ事情があって、予算であったり、期間であったり、提供できるプログラムに短期間で引っかからずに走り切れる人かであったり、正社員採用の時だったら採用する人でも落ちることがあります。

体感として、今のエンジニア学生の傾向として、全体的に実務経験を持つ人の人数が増え、さらに高度な実務経験を持つ人は、社会人エンジニアの想像を超えるぐらいより高い経験を身に着けるようになったように思えます。

この傾向は、うれしく思う反面、彼らの姿を見て、焦りを感じたり、不安に感じたりする人も少なくないはず。焦らず、自分のペースで挑戦し続ければ、彼らと同じ土俵に立てます。


**Good Luck!**
Microsoft Sentinel の監査をしよう！

# Microsoft Sentinel の監査
Microsoft Sentinel の運用をされている皆さん、Sentinel の利用状況をきちんと監査できる状態になっていますか？

誰がいつどんなクエリを実行したかや、Sentinel の分析ルールやデータ コネクタが正常に動作しているかなどの情報をログとして記録しておくことで、問題に早く気づいたり、後から調査に役立てたりすることができます。

今回のブログでは、Microsoft Sentinel の監査に利用できる 4 つのテーブルを紹介します。

# Microsoft Sentinel の監査に利用できるテーブル（ログ）
こちらで紹介する 4 つのテーブルは既定では有効化されていませんので、必要に応じて有効化して業務にご活用ください。

* LAQueryLogs テーブル
* SentinelHealth テーブル
* SentinelAudit テーブル
* AzureActivity テーブル

### LAQueryLogs テーブル
最初に紹介するのは LAQueryLogs テーブルです。LA は Log Analytics の略で、Log Analytics にどのようなクエリが実行されたかを記録するテーブルです。

問題発生時用だけでなく、クエリ実行者の KQL の成熟度を判定したりといったこともできそうだなーと思います。

下記のような情報を取得できます。

* クエリを実行した時間
* クエリを実行したユーザーのユーザー ID とメールアドレス
* クエリを実行したアプリの種類（Azure ポータル、データコネクタ、Power BI など）
* 実行されたクエリと実行時間
* 結果として返されたレコード数

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563573/dc5c7d03-a74f-c2d0-b97c-0e4b48be7232.png)

Log Analytics ワークスペースの診断設定（Diagnostic setting）から audit カテゴリを選択することでログを取得できるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563573/d2ed11ad-59de-b0ac-5b37-f445e2a29ebd.png)

設定方法やテーブルのフィールドの説明、注意事項などは下記の Learn をご確認ください。

https://learn.microsoft.com/ja-jp/azure/azure-monitor/logs/query-audit

### SentinelHealth テーブル
LAQueryLogs テーブルは Sentinel というよりも Log Analytics のログでしたが、SentinelHealth テーブルはその名の通り Sentinel が正常に機能しているかを確認できる専用のテーブルです。

分析ルールって、意外と失敗していることが多いので、失敗したときに気づけるようにしておくのは大事ですね。

下記のような情報を取得できます。

* ジョブが実行された時間
* ジョブの種類（分析ルール、データコネクタ、プレイブックなど）
* ジョブを実行したリソースの種類と名前（分析ルール、データコネクタ、プレイブック）
* ジョブの実行結果とその理由

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563573/91dd000b-a3f6-0116-18e7-419a1ae9fdb2.png)

Sentinel の設定から「監査と正常性の監視」を有効にすることでログを取得できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563573/913e5995-d0e9-a92f-ccda-5161d3246c1d.png)

設定方法やテーブルを使った監視方法、注意事項などは下記の Learn をご確認ください。

https://learn.microsoft.com/ja-jp/azure/sentinel/health-audit

### SentinelAudit テーブル
SentinelHealth テーブルと同じ設定で取得できるようになるテーブルで、分析ルールの作成や更新などの Sentinel の設定変更の情報を取得できます。

下記のような情報を取得できます。

* 操作が行われた時間
* 操作の種類
* 操作を行ったリソース名（分析ルールなど）
* 操作の結果とその理由

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563573/173f1230-73ec-6cac-85eb-9a6eb26f20da.png)

有効化方法やドキュメントは SentinelHealth テーブルと共通です。

### AzureActivity テーブル
分析ルールの編集などの Sentinel で実行される全ての操作ログを取得できるテーブルです。このテーブルは Sentinel 固有ではなく Azure サブスクリプション全体で共通して使用されます。 

下記のような情報を取得できます。

* 操作が行われた時間
* 操作の種類
* 操作を行ったリソースとその種類
* 呼び出し元の IP アドレス

AzureActivity テーブルは任意の Azure リソースの「アクティビティ ログ（Activity Log）」の「診断設定（Export Activity Logs）」から設定できます。Sentinel だけではなく Azure サブスクリプション全体で機能が有効になりますのでご注意ください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563573/b53693f4-4ac1-1530-8b51-538ec16973ac.png)

AzureActivity テーブルを使用した具体的な監査方法については下記の URL を参照してください。

https://learn.microsoft.com/ja-jp/azure/sentinel/audit-sentinel-data#auditing-with-azure-activity-logs

# まとめ
Sentinel 運用で検討すべき 4 つのテーブルを紹介しました。

ログの量が増えるとコストに跳ね返りますので、どのようなログが必要かを考えて、必要に応じて有効化することをお勧めします。

問題が起きてからでは遅いので、最初の設計段階で（もしくは未設定に気づいたときに・・）忘れずに必要なログ取得を有効化するようにしましょう！
リリース前にも使おう！新規プロダクトの開発中にNew Relicを入れてよかったところ

## はじめに

新規プロダクトの開発期間中にNew Relicを導入してみたところ、リリース前でも良い効果がありました。

- デグレードの検知と原因特定
- N+1問題の特定と改善
- インフラリソースの利用状況の分析
- 運用を意識したログ設計&チューニング

### プロダクトの構成

- クライアント、コンシューマー、社内システムとユーザー層が複数に分かれている
- 既存プロダクトとの連携もあるが、なるべくマイクロサービスに寄せる

このような構成で、複数チームで開発が進められていました。

## 開発中にNew Relicを入れてよかったところ

### デグレードの検知と原因特定

疎結合な設計や網羅性の高いテストを用意していても、システム同士の結合などでデグレードが発生することがあります。

今回は早期にエラーログの監視・アラート設定を行い、「**エラーログが1件でも上がったらアラートを発砲する（Slackチャンネルへ投稿する）**」という仕組みを整えました。
通常の運用では厳しい基準ですが、開発中は不具合の早期発見につながりました。Slackチャンネルを通じて関係者がすぐ認識できて、複数チームにまたがる開発でも情報共有が迅速に行えました。

また、分散トレーシングによって、**一連のトランザクションの中でどのサービスにエラーが起きているかがすぐ分かる**ようになり、原因の特定も容易でした。

### N+1問題の特定と改善

APIのアーキテクチャにGraphQLを採用しているサービスにおいて、GraphQLライブラリの習熟度が低くN+1問題を起こしてしまいました。
「レスポンスがなんとなく遅い」という感覚から始まりましたが、APMを使ったデータベースの分析で原因を特定して解消しました。

今回は処理速度が早いクエリがn+1回発行されていたため、原因の特定に少し苦労しました。
最初はスロークエリを探していましたが特段遅いものはなく、対象処理のループ回数が多くなってようやく顕在化しました。

原因の特定に役立ったのがAPMによるデータベースの分析結果のソート順でした。`most time consuming`（頻繁に発行されるクエリ）と`slowest query time`（遅いクエリ）を見比べて、「処理は速いが発行数が多いクエリ」を発見できたのが解決の糸口になりました。

![処理は速いが頻繁に発行されている.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/371897/86235ee3-a382-ace9-c12c-14f0c06cc9a7.png)

### インフラリソースの利用状況の分析

負荷試験結果の分析のため、インフラリソースの利用状況をまとめたダッシュボードを作成しました。オートスケールの設定に大いに参考になり、複数回の試験結果を見比べながらチューニングを進めました。

死活監視やリソースの利用状況、アプリケーションのエラーレートに応じたアラートも設定できるため、統合的な監視ができる点が気に入っています。

### 運用を意識したログ設計&チューニング

ログにカスタム属性を追加することで、ログ解析を豊かにすることができます。

今回は**開発段階から運用で使うツールを利用することで、実運用の目線を持てた**ことが大きかったです。
不具合の修正時に「この項目があると障害調査が楽そう」「この情報もあるとユーザー行動が分析しやすい」といった声が上がり、実運用を意識したログ設計にチューンアップしていきました。
同意のもとで提供され匿名化したユーザー識別IDや、リクエストパラメータをカスタム属性に含めることで、運用時の調査がスムーズに進められるようになりました。

特にユーザー識別IDを含めるのはおすすめです。
問題が発生したユーザーをログから割り出して、分散トレーシングと組み合わせることで、ユーザーの行動が一通り推測できるようになります。
不具合の再現手順を発見したり、計測ツールのデータからユーザーの属性を解析したりと、幅広い使い方で運用の助けになりました。

## さいごに

New Relicはオブザーバビリティに主軸を置いたツールですが、**観測したいデータを深掘りしていく**ことで、開発中にもいろいろな活用方法がありました。
開発体験のベースにあることで、プロダクトと同様にNew Relicの活用も進化していくのだと思います。
また、リリース後の運用を意識した使い方を学んでいくことができるので、学習期間として触れていくのもおすすめです。

打って変わって、昨年は数十年と続くレガシーシステムにNew Relicを入れて試行錯誤しておりました。
気になる方は、昨年はアドベントカレンダーの記事もぜひご覧ください↓

https://qiita.com/ramiyon_chan/items/20b476577fc8aaed76fd

それでは、みなさま素敵なNew Relicライフを！
初心者でもわかる！Github Actionsの入門

Github Actionsは、GitHubリポジトリにおけるワークフローの自動化を実現する強力なツールです。本記事では、入門者向けにGithub Actionsの基本的な使い方について解説します。

## Github Actionsとは？

Github Actionsは、リポジトリ内の特定のイベント（例：push、pull request）をトリガーにして、事前に定義されたワークフローを実行する仕組みです。このワークフローを利用すれば、CI/CD（継続的インテグレーション/デリバリー）を簡単に設定できます。

## 基本のセットアップ

まずは簡単なワークフローを作成してみましょう。

1. `.github/workflows/` フォルダを作成します。
2. その中に `example.yml` ファイルを作成します。

以下は、最もシンプルな構成の例です。

```
name: Example Workflow

on:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Run a script
        run: echo "Hello, Github Actions!"
```

## ワークフローの構成

### トリガー
ワークフローをいつ実行するかを指定するセクションです。上記の例では `on.push` を利用しており、`main` ブランチにコードをプッシュすると実行されます。

### ジョブ
`jobs` セクションでは、具体的な処理内容を定義します。

- `runs-on`：どの環境で実行するか指定します。例：`ubuntu-latest`。
- `steps`：各ジョブ内で行う処理を定義します。

### ステップ
個々のジョブの中で実行される具体的な処理です。例えば、コードのチェックアウトやテスト実行などがあります。

```
steps:
  - name: Checkout repository
    uses: actions/checkout@v3

  - name: Run tests
    run: pytest
```

## Github Actionsの活用例

### デプロイの自動化
テストが成功した場合に、アプリケーションを自動デプロイする例です。

```
name: Deploy Application

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Deploy to server
        run: ./deploy.sh
```

### GitHub Pagesの自動デプロイ
GitHub Pagesを利用して、リポジトリの`gh-pages`ブランチに自動で静的サイトをデプロイする設定です。

```
name: Deploy to GitHub Pages

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Set up Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '16'

      - name: Install dependencies
        run: npm install

      - name: Build static site
        run: npm run build

      - name: Deploy to GitHub Pages
        uses: peaceiris/actions-gh-pages@v3
        with:
          deploy_branch: gh-pages
          folder: build
```

## まとめ

この記事では、Github Actionsの基本的な使い方を紹介しました。Github Actionsを活用することで、開発効率を大幅に向上させることが可能です。次は、より複雑なワークフローに挑戦してみましょう！
TTSのプロンプトエンジニアリングで合成音声を人間らしい話し方にした

## はじめに
[リンクアンドモチベーションのアドベントカレンダー](https://qiita.com/advent-calendar/2024/lmi)です。
最近TTSをとても触る機会が多かったので記事にしてみました。

## Text-to-Speechとは

Text-to-Speech（TTS）は、文字を音声に変える技術です。たとえば、スマホやカーナビで文章を読み上げるときに使われます。

TTSは次のような仕組みで音声を作ります：

1. **文章の理解**：テキストを分けて、文法や意味を調べる
2. **音に変える**：文章を音に変えるための情報にする
3. **声を作る**：情報を使って音声を作る

この辺はGPTに出してもらいました。へーそうなんだあ。

## 代表的なTTSのサービス

TTSを使えるサービスには、たくさんの種類があります。たとえば：

- **Amazon Polly**：いろいろな言葉に対応していて、感情を込めた声も作れる
- **Google Cloud Text-to-Speech**：高品質な音声を作れる
- **Microsoft Azure Cognitive Services**：自分だけのオリジナルの声を作る機能がある
- **OpenAI Whisper**：音声を作るだけでなく、音声を聞き取ることもできる

この辺もGPTに出してもらいました。へーそうなんだあ。
私はAmazon Pollyを使っていたので、ここからはAmazon Pollyの音声調整の方法を具体的に話していきます。

## TTSの調整方法（Amazon Pollyを例に）

TTSでより自然な声を作るには、ただ文字を入れるだけではなく、いくつかの工夫が必要です。
### 1. 話す速さや声の高さを変える

Amazon Pollyでは、音声の速さや高さを調整するタグを使うことができます。

例：

```ssml
<speak>
  <prosody rate="slow">ゆっくり話します。</prosody>
  <prosody rate="fast">はやく話します。</prosody>
</speak>
```

### 2. 発音を細かく調整する

Amazon Pollyでは、SSML（音声合成マークアップ言語）を使って発音をコントロールできます。発音記号やカスタム発音を指定することで、正確な発音を実現できます。

例：
```ssml
<speak>
<phoneme alphabet="x-amazon-pron-kana" ph="アリ'ガトウ">ありがとう</phoneme>
</speak>
```

発音をコントロールできるということは関西弁を話させることもできます。
例：
```ssml
<speak>
<phoneme alphabet="x-amazon-pron-kana" ph="アリガ'ト'ウ">ありがとう</phoneme>
</speak>
```

#### ふりがなを振る

日本語では、漢字にふりがなを振ることで正確な発音を指定できます。
たとえば、文脈によって読み仮名が変わるような「行った」という言葉は以下のように指定することができます。
```ssml
<speak>
<phoneme alphabet="x-amazon-yomigana" ph="いった">行った</phoneme>
<phoneme alphabet="x-amazon-yomigana" ph="おこなった">行った</phoneme>
</speak>
```

#### TTSで読み取ってくれないがちな日本語

日本語は難しいらしく、調整が必要な言葉がたくさん出てきます。
たとえば以下のような言葉は発音や読み仮名を調整する必要がある場合が多いです。

- **漢字が続く言葉の発音**：たとえば、「三寒四温」や「三杯酢」など、漢字が連続する言葉は、自然な発音にするのが難しいことがあります。
```ssml
<speak>
<phoneme alphabet="x-amazon-pron-kana" ph="サ'ン'カ'ン'シ'オン">三寒四温</phoneme>
</speak>
```
```ssml
<speak>
<phoneme alphabet="x-amazon-pron-kana" ph="サン'バ'イズ">三杯酢</phoneme>
</speak>
```

### 3. 間や区切りを追加する

音声に自然な間を作ることで、聞き取りやすくなります。
特に説明文やリストを読み上げる場合に効果的です。
これがマジで大事で、人間っぽい聞き取りやすい話し方は間があるかどうかにもよるなと思いました。

例：

```ssml
<speak>
  待って... それは何ですか？
  <break time="1s"/>
  今わかりました。
</speak>
```

## 終わりに

TTSの調整をすることで人間の喋りが上手になるかなと思ってたら
音声を聴きすぎてこっちの喋り方が機械に寄りました。
`when_first_matching_example_defined`フック

#### `when_first_matching_example_defined`フックを使う
>### Using when_first_matching_example_defined hook
#### Rspecを使った大きなプロジェクトにおいて、ある種のスペックがロードした時だけ必要された高価なセットアップロジックを持つことが一般的だ。その種のスペックがロードされていなかったならば、セットアップのするコストを避けたいものだ。
>In large projects that use RSpec, it’s common to have some expensive setup logic that is only needed when certain kinds of specs have been loaded. If that kind of spec has not been loaded, you’d prefer to avoid the cost of doing the setup.

#### 最初のexampleがメタデータのマッチで定義された時`when_first_matching_example_defined`フックは条件的にロジックが果たされることを簡単に必要な時にだけ実行される必要なセットアップを確実にさせる
>The when_first_matching_example_defined hook makes it easy to conditionally perform some logic when the first example is defined with matching metadata, allowing you to ensure the necessary setup is performed only when needed.

>### Background
```spec_helper.rb
RSpec.configure do |config|
  config.when_first_matching_example_defined(:db) do
    require "support_db.rb"
  end
end
```
```support_db.rb
RSpec.configure do |config|
  config.before(:suite) do
    puts "Bootstrapped the DB."
  end

  config.around(:example, :db) do |example|
    puts "Starting a DB transaction."
    example.run
    puts "Rolling back a DB transaction."
  end
end
```
And a file named “.rspec” with:
```
--require spec_helper
```
```rb
RSpec.describe "A unit spec" do
  it "does not require a database" do
    puts "in unit example"
  end
end
```
```
Bootstrapped the DB.
in unit example
1 example, 0 failures, 1 passed
```
```rb
RSpec.describe "An integration spec", :db do
  it "requires a database" do
    puts "in integration example"
  end
end
```
```
Run options: include {:full_description=>/An\ integration\ spec/}
Bootstrapped the DB.
Starting a DB transaction.
in integration example
Rolling back a DB transaction.
1 example, 0 failures, 1 passed
```
#### 全体のスイートを実行するとDBがセットアップする
>### Running the entire suite loads the DB setup

>When I run rspec
>
>Then it should pass with:
```
Bootstrapped the DB.

Starting a DB transaction.
in integration example
Rolling back a DB transaction.
.in unit example
.
```
```
Bootstrapped the DB.
in unit example
.Starting a DB transaction.
in integration example
Rolling back a DB transaction.
.

Finished in 0.02682 seconds (files took 1.19 seconds to load)
2 examples, 0 failures

```
* コンソールで`rspec`と入力すると全体のスイートが実行されるようだ

#### specユニットだけを実行させてもDBのセットアップをロードできない
>### Running just the unit spec does not load the DB setup
When I run rspec spec/unit_spec.rb

```
Then the examples should all pass

And the output should not contain “DB”.
```
https://rspec.info/features/3-13/rspec-core/hooks/when-first-matching-example-defined/#:~:text=Using%20when_first_matching_example_defined%20hook,not%20contain%20%E2%80%9CDB%E2%80%9D
ChatGPTに日本語乳児絵本を翻訳させてみた

最近生成AIの調教をやってました。
ざっくり書くとプロンプトを書いて、コンサル仕事やデータ分析など知的労働をやってもらおうみたいな試みです。

生成AIのポンコツぶりにびっくりしました。
いえ、正確にかくと、プロンプトの工夫を頑張れば精度は上がっていくのですが、かなり心的負担が大きいです。
まずやって欲しいことをやってくれない。昨日できていたことが今日はできない。プロンプトを頑張って工夫すれば精度は上がるものの決して100%にはならない。プロンプトを長く細かく書きすぎると汎用性がなくなったり保守性に課題が生まれる。etc

AIがポンコツなのはまあ良いのですが、プロンプトを工夫すれば精度が上がっていくのもあり、「生成AIが目標を達成できないのは、プロンプトを書く私の指示が悪いから」という論理になり、新人教育なんてやったことはないですが、「新人の成績が悪いのはマネージャーのお前の責任」と言われる気持ちを味わうことができました。

思うにIQ110レベルの、ちょっと難しい仕事をやらせようとするからフラストレーションがたまるのだと仮定します。AIの間違えはなくならないし、答えがあってるか専門人材のチェック工数はかかります。
個人的にはIQ80-100レベルの、誰にでもできる作業を無限にやってもらえることに価値があるのだと思っています。
そこで、語学に注目してみました。極論を言えば、アメリカで育てばIQ関係なくほぼ100%英語ができるようになります。語学翻訳と生成AIは相性が良いのではないか？と仮説を立ててみました。

以前趣味で英文をAIが朗読したものを音源化するサイトを作ってました。

https://qiita.com/logsupport_mark/items/69d6b17724f7119ce63c

それに今回改修を加えます。日本語の乳児絵本の日本語を打ち込むと、chatGPTのAPIを呼び出し、英文に翻訳してもらうようにしました。

さて、どういうレベルなのか、見るべきポイントを書いてみます。
1、文法的な正しさ
2、幼児語という専門(？)用語の翻訳
3、比喩など文学表現や主語など含めた、文脈の正しさ
4、擬音語、擬態語
5、リズム感、音読のやりやすさ

本来であれば実験して数量的・客観的に見るべきですが、そこまでやる気はなかったので、完全に私個人の感覚で判断してみました。

個人的には1、2、3、4の観点では80点くらいの満足度でした。例えば「あおむしくん」を「Blue caterpillar」と訳してしまう、みたいな凡ミスはありますが、全体的に満足できるものでした。ちなみに生成AI以前のAIだと2、3、4の観点がめちゃくちゃだったので、すごい進化です。
5のリズム感や音読のやりやすさに関しては、うまく言語化できないのですが、本物の英語絵本の文章とは違う、違和感みたいなものがありました。あえて例えると英文をそっくりそのまま翻訳した日本語の文章を読むような違和感(というのもなんとなく違う気がしますが)。英語力を高めるほどこの違和感は上がるんじゃないかと思ってます。
私が専門？のデータ分析部門で生成AIに不満を持つように、翻訳の専門家にとっては生成AIの翻訳に不満を持つんだろうなーという感想を持ちました。そういう意味で、語学がIQ80-100のレベルの分野という仮説は大分間違っていると言えそうです。

でも翻訳の素人としては、今回の出来に満足してます。
生成した英文はそのままAIに朗読してもらい、音源を作成した後は、カメレオンリーダーというおもちゃと連携させてます。
カメレオンシールにそれぞれの音声を連携させて、カメレオンペンでシールをタッチすると、対応する音源が流れ出す仕組みです。乳児絵本の表紙にシールを貼り付けて、子供が自分で英文を聞けるようにしました。わりと楽しく遊んでいるようです。

作ったサイトも置いておきます。
ユーザー登録の際には「747487」という招待コードを入力してください。
本の著作権などグレーな部分もあるので、研究・教育以外の用途に使わないでくださいね。

https://sharelingoapp.com
数字ベースで聞きたい面接での質問内容

# 概要

近年、リモートでの面接やカジュアル面談が普及し、転職活動のハードルが下がった印象があります。それでも、転職活動は精神的にも体力的に消耗が激しいです。

そんな中、入社した企業がブラック企業だったり、自分に合わない会社だった場合には、目も当てられません。

こうしたリスクを回避するために、面接では数字を基にした質問を行うことで、企業の実態をより具体的に把握できると感じています。そこで今回は、数字を活用した質問を整理し、転職活動に役立つだろう内容をまとめてみました。

:::note warn
注意
踏み込んだ質問も含まれますので、面接時の空気やご自身の状況に応じてご判断ください。
:::


# 前提

企業側も自社をよく見せるために都合の悪いことは言わない場合があります。下記2点は注意して見極めましょう。


## 1. 平均という言葉に注意する

「シンプソンのパラドックス」のように、平均値は対象や範囲を巧妙に調整することで都合よく見せられる場合があります。そのため、**平均の算出方法や対象範囲**を確認したり、**具体的な数字**を聞いて分析しましょう。

https://ja.wikipedia.org/wiki/%E3%82%B7%E3%83%B3%E3%83%97%E3%82%BD%E3%83%B3%E3%81%AE%E3%83%91%E3%83%A9%E3%83%89%E3%83%83%E3%82%AF%E3%82%B9

## 2. 実績1でも実績になる

実績が「0か1」で語られる場合、それが本当に価値あるものか、何を意味しているのかを見極める必要があります。

例：「AWSの資格をすべて取得したエンジニアが在籍しています。」
→ 会社の環境が優れているのではなく、個人の能力が高いだけかもしれません。それが自分のメリットになるかどうかを確認しましょう。

# 確認したい内容

## 会社の規模感

### 1. 「従業員数は何名くらいですか？」

会社の規模感を把握し、安定性や成長性を予測するための質問です。会社HPに記載がある場合も多いので事前に確認しておきましょう。

### 2. 「ここ数年の増減について教えていただけますか？」

入社人数（新卒・中途）を確認することで、会社の成長性や採用の安定性を判断するための質問です。増減が大きい場合、その背景（リストラや急成長による対応など）を掘り下げて確認しましょう。

### 3. 「離職率はどれくらいですか」

社員が長く働ける環境かを知り、ブラック企業を見極めるための質問です。離職率が高い場合に、その分析をしているかを聞きたいところです。


### 4. 「社員の年代ごとの割合はどのくらいですか？」

社員構成を把握し、自分が働きやすい環境かどうかを判断するための質問です。
- **若手が多い場合**: 仕事のレベルが低い可能性があります
- **中堅が少ない場合**: 離職者が多かったり、教育を担える人材が不足している可能性があります
- **40代以上のベテランが多い場合**: 昇給や昇進がしづらかったり、意見を提案しにくい職場の可能性があります

あくまで上記は、私の感覚ですが、自身にとって適切な環境かを見極める材料としましょう。

### 5. 「エンジニアの人数はどれくらいですか？」

働く環境の規模感や過ごしやすさを確認するための質問です。全体の従業員数に対してエンジニアが少なすぎる場合、話を理解してもらえなかったり技術者の負担が大きくなる可能性があります。

### 6. 「部署の数はどれくらいありますか？」

上司やプロジェクト内容が合わなかった場合に異動の可能性やキャリアパスを考える上で、選択肢の多さを確認するための質問です。 事前説明で説明される場合があると思いますが、詳細が不明な場合は具体的に質問したほうが良いです。

### 7. 「営業担当は何名くらい在籍していますか？」

SESや受託開発では、営業の質がプロジェクトの質に大きく影響するため聞いておきたい内容です。営業担当が少ない場合に変えてもらうこともできない可能性があります。また、ITスキルや経験があるかを確認するのもありです。

## 働き方

### 8. 「平均的な月間残業時間はどのくらいですか？」

残業が当たり前になっていないか、無理なく続けられる環境かを判断するための質問です。平均値だけでは分からない長時間労働者がいないかも確認したいところです。

### 9. 「繁忙期の残業時間は最大でどの程度になりますか？」

長時間労働者がいるのかの探りを入れる質問です。深堀し忙しい時期の働き方や長時間労働の際の対処についても確認したいです。

### 10. 「有給取得率はどの程度になりますか？」

有給を取りやすい職場環境かどうかを判断するための質問です。取得率だけでなく、実際に取得しやすい雰囲気かどうかも聞くことが重要です。

### 11.「育児休暇や産休の取得の実績はどれくらいありますか？」

女性限定にはなりますが、育児休暇や産休に対する理解があり、実際に取得できる環境が整っているかを確認するための質問です。実際に取得しやすい雰囲気かどうかも聞くことが重要です。

### 12.「育休後の復職率はどの程度ですか？」

こちらも女性限定にはなりますが、産休後に復職しやすい環境かどうかを見極めるための質問です。復職率が低い場合、キャリアパスに影響があるのかもしれません。

# 質問に対する回答について

ここまで質問をまとめてみましたが、いざ実践してみると、予想外の回答が返ってくることがあります。そんなときは注意が必要です。

例として私が経験した面接の1コマです。

**例：社員の年代ごとの割合について**

```
私：「社員の年代ごとの割合はどのくらいですか？」

会社：「若いメンバーが多いですね。」← （具体的な割合ではなく、曖昧な回答）

私：「若いメンバーが多い理由は何ですか？」
（若い人が多いことで○○が良くなる、または教育制度が充実しているなどの回答を予想）

会社：「会社の方針というか...そういう会社なんですよね...etc...」←（3分ほど説明が続くがもはや意味不明...）
```

このように、具体的な数値やデータを求めているにもかかわらず、曖昧な答えが返ってきた場合、その裏にあるのでは？と感じました。そして「なぜ明確な数値で答えてもらえないのか」という点に注目し、質問を掘り下げていくことで、相手の本音や企業の実態が見えて来るかもしれません。

# 終わりに

これから10年、20年と勤める会社ですので、ミスマッチが無いようにしたいですね。少しでも考え方の参考となればと思います。

上記のほかに、これは質問したほうがいいよ！というのがありましたら教えてください。

ここまで読んでいただきありがとうございました。
初めて技術選定を行った時に注意したこと

# はじめに
2年目の時に初めて技術選定を行ったので、その時に気をつけていたことをまとめました。
バーコード写真から値を読み取るライブラリの選定だったと思います。

# まず要件整理
必要な __要件の整理__ と、__どのくらいの時間__ をかけて調査を行うかを決めました。これがずれているとせっかく技術選定を行っても、時間が無駄になってしまいます。
どんな機能を満たせば良いか、調査にかける人数と時間、テストコードを作成する時間を軽く見積もって期日を決めます。ちゃんと合意を得て、調査に時間をかけることを承認してもらいます。

# 調査
GoogleやGitHub、stackoverflowなどを利用して、要件を満たすにはどんな技術があるか、調べられるだけ調べます。この時、GitHubのスター数やフォーク数を見て最近のコミュニティの活発度合いも調べます。できれば、安定して長いこと動く見込みのあるメンテナンスされそうな技術を使いたいですしね。
そして、 __ライセンス__ や __セキュリティ__ 、必要なライブラリに関しても確認します。
あとは開発者が信用できそうかどうかとか。

# テストコード作成
調査でまとめた技術を使って、同じ要件でテストコードを作成します。実際にコードを書くと、意外と実装できなかったり、要件に合わないことが分かったりします。候補が少なかったら諦めきられませんが、簡単に実装できない技術があった場合は、その技術を実装することをひとまず諦めたりもしました。
最後にパフォーマンスなど調査結果をまとめます。

# 決定
調査結果とテストコードを持って、他の人にコードを動かしてもらいます。そして使ってもらった意見を聞いて、それぞれの技術の利点と問題点を並べ、最終決定します。

# 感想
新しい技術を短い期間にどんどん試せるのが楽しかったです。ライブラリごとに異なるコーディングスタイルや性能を比較できたのもおもしろかったです。
また、ライセンスやレビューなどを普段より真剣に読みますし、他の人とのやりとりも通じて色々なことがかなり勉強になりました。
[Rust]ファイル操作の基礎

## パスを扱う

ファイルパスを扱うには、`Path`や`PathBuf`を使います。前者はイミュータブルであり、後者は前者への参照にあたります（`&str`と`String`のような関係です）。

:::note
以降、`std::path::Path`を単に`Path`と表現します。
:::

### 文字列からパスを取得する

`Path::new(パス文字列）`で対応するパスを取得します。存在しないディレクトリを含んでいるとエラーになります。
また、`Path`には`join`という便利なメソッドがあり、チェーンすることでパスを繋げていくことができます。ただし、途中で絶対パス（`/foo/bar`のようなもの）を渡すと、そこでパスが上書きされるので注意しましょう。

```rust
use std::path::Path;

fn main() {
    let path = Path::new("/home/user/documents");
    println!("Path: {:?}", path);

    let joined_path = path.join("subdir").join("file.txt");
    println!("Joined Path: {:?}", joined_path);

    let overwritten_path = path.join("/new/absolute/path");
    println!("Overwritten Path: {:?}", overwritten_path);
}
```

:::note
`PathBuf`には`push`というメソッドもあり、`join`と似たような挙動をします。`join`は新たな`PathBuf`を返すのに対し、`push`は`PathBuf`に変更を加えるという違いがあります。

```rust
use std::path::PathBuf;

fn main() {
    let mut path_buf = PathBuf::from("/home/user");
    path_buf.push("documents");
    path_buf.push("file.txt");
    println!("PathBuf with push: {:?}", path_buf);
}
```

:::

### カレントディレクトリを取得する

`std::env::current_dir`と使うと、実行時のカレントディレクトリを取得できます。

```rust
use std::env;

fn main() {
    match env::current_dir() {
        Ok(current_dir) => println!("Current directory: {:?}", current_dir),
        Err(e) => eprintln!("Failed to get current directory: {}", e),
    }
}
```

### ファイル名を変更する

`PathBuf`の`set_file_name`メソッドを使うと、そのパスが示しているファイルの名前を変更できます。

```rust
use std::path::PathBuf;

fn main() {
    let mut path_buf = PathBuf::from("/home/user/documents/file.txt");
    path_buf.set_file_name("new_file_name.txt");
    println!("Updated PathBuf: {:?}", path_buf);
}
```

:::note warn
`set_file_name`は`PathBuf`のメソッドであり`Path`にはありません。`PathBuf`がミュータブルなのに関係しているんでしょうか・・・
:::

## ファイルを扱う

### ファイルを開く

`File::open`で指定したパスのファイルへのファイル参照を作成します。これは読み取り専用になり、`io::Result<File>`型を返します。そのため、ファイル読み込みに成功したか失敗したかは`match`などで判定できます。

```rust
use std::fs::File;
use std::io;

fn main() -> io::Result<()> {
    let file_path = "example.txt";
    match File::open(file_path) {
        Ok(file) => println!("File opened successfully: {:?}", file),
        Err(e) => eprintln!("Failed to open file: {}", e),
    }
    Ok(())
}
```


:::note
`File`オブジェクトがスコープを抜けるとドロップされるので、明示的なファイルを閉じる（close）処理は必要ありません。
:::

### ファイルを読み取る

`File`オブジェクトの`read_to_string`メソッドで、ファイルの中身を`String`オブジェクトに読み取ります。あらかじめ`String`オブジェクトを作成しておき、それへのミュータブルな参照（`&mut`）を引数に渡します。

```rust
use std::fs::File;
use std::io::{self, Read};

fn main() -> io::Result<()> {
    let file_path = "example.txt";
    let mut file = File::open(file_path)?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    println!("File contents: {}", contents);
    Ok(())
}
```

### ファイルに書き込む

`File::create`でファイルにバイト列の内容を書き込みます。渡したパスのファイルがすでに存在している場合、上書きされるので注意しましょう。

```rust
use std::fs::File;
use std::io::{self, Write};

fn main() -> io::Result<()> {
    let file_path = "output.txt";
    let mut file = File::create(file_path)?;
    file.write_all(b"Hello, Rust!")?;
    println!("File written successfully");
    Ok(())
}
```