OmniAICreator/Qiita-1.07M huggingface dataset:
JavaScript/ディープコピー

## ディープコピーとは
ディープコピーとは、オブジェクトのすべてのレベルのプロパティを再帰的にコピーすることを言います。シャローコピーと違いはコピー元とコピー先が完全に独立することです。

## ディープコピーをする方法
JSON.parse()とJSON.stringify()を使った方法がシンプルでわかりやすいです。

```javascript
const person = {
  name: 'Takuto',
  gender: '男',
  info: {
    age: 20,
    interests: 'reading',
  },
};

const copy = JSON.parse(JSON.stringify(person));  //ディープコピー

copy.name = 'Kazuya';
copy.info.age = 21;

console.log(person.name);  //Takuto  変更されない
console.log(person.info.age);  //20  変更されない
```
:::note warn
メモ
この方法では...
・関数や特殊なオブジェクト（Date, Set, Mapなど）はコピーできない。
・循環参照（オブジェクトが自身を参照する構造）に対応できない。
:::

## 追記
structuredCloneメソッドを用いてもディープコピーを簡単に行えます。
この方法だと特殊なオブジェクト（Date, Set, Mapなど）のコピーも可能です。

先ほどの例でディープコピーの行をこのようにしても同じ結果になります。
```javascript
const copy = structuredClone(person);  //ディープコピー
```
[Rust]ループ処理の基本：for、while、loop

## `for`

イテレータに対してループ処理を行う場合は`for`を利用します。一番シンプルなケースは`Range`オブジェクトを使用するパターンです。`Range`オブジェクトは`..`を使うと簡単に作成できます。

```rust
fn main() {
    for i in 0..5 {
        println!("i: {}", i);
    }
}
```

:::note
「イテレータ」は`Iterator`トレイトのインスタンスであること、を指しています（ややこしい）。
普段は（少なくとも筆者は）あまり意識することはありませんが、JavaScriptにもイテレータの概念があります。詳しくは[イテレーターとジェネレーター](https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Iterators_and_generators)を参照してください。
:::

配列やベクタのようなコレクションに対しても`for`を使用できます。注意点として、単に`for`に対してコレクションを渡すとデフォルトでは暗黙的にそのコレクションの`into_iter`が呼び出されます。この方法では、コレクションの各要素は直接使用されます。すなわち、コレクションの要素の所有権はループに移るため、ループの後にコレクションを参照することはできません。

```rust
fn main() {
    let numbers = vec![1, 2, 3];
    for num in numbers {
        println!("num: {}", num);
    }
    // println!("{:?}", numbers); // エラー: 所有権が移動している
}
```

これを防ぐには、明示的に`iter`を呼び出します。この方法では、各ループで要素の参照を借用するので、所有権は移動しません。

```rust
fn main() {
    let numbers = vec![1, 2, 3];
    for num in numbers.iter() {
        println!("num: {}", num);
    }
    println!("{:?}", numbers); // 問題なく参照可能
}
```

## `while`

イテレータ関係なく、指定の条件を満たす限りループ処理を続行したい場合は`while`を使用します。

```rust
fn main() {
    let mut counter = 0;
    while counter < 5 {
        println!("counter: {}", counter);
        counter += 1;
    }
}
```

`if`と同様に、`Option`な値（`Some`か`None`の値）を扱いたいが、`None`のときは何もしたくないケースでは`while let`構文を使用できます。

```rust
fn main() {
    let mut numbers = Some(5);

    while let Some(num) = numbers {
        println!("num: {}", num);
        numbers = if num > 1 { Some(num - 1) } else { None };
    }
}
```

## `loop`

`while(true)`と同等の働きをします。条件判定の処理がないので、若干高速です。

```rust
fn main() {
    let mut count = 0;

    loop {
        if count >= 5 {
            break;
        }
        println!("count: {}", count);
        count += 1;
    }
}
```

`loop`は値を返すことができます。`break`の後に値を書いておくと、その値を`loop`を抜けた後に使用できます。ユースケースとして、処理が成功するまでリトライするものが挙げられます。

```rust
fn main() {
    let mut attempts = 0;

    let result = loop {
        attempts += 1;
        if attempts == 3 {
            break "Success!";
        }
    };

    println!("Result: {}", result);
}
```

## ループを飛ばしたいとき、抜けたいとき

各ループを次に飛ばしたいときは`continue`を使用します。また、途中でループそのものを抜け出したい場合は`break`を使用します。

```rust
fn main() {
    for i in 0..10 {
        if i % 2 == 0 {
            continue; // 偶数をスキップ
        }
        if i > 7 {
            break; // 7を超えたらループを終了
        }
        println!("i: {}", i);
    }
}
```
Goでログファイルのリロードを実現する

Goのログローテーションは[lumberjack](https://github.com/natefinch/lumberjack)というイメージがあったが、2024/12時点で1年以上更新がない  

とりあえず[io.Writer](https://pkg.go.dev/io#Writer)にファイルをリロードするインタフェースを追加したら使い勝手が良さそうかなと思ったので実装してみた  

## 実装

https://github.com/Haya372/go-rfwriter/tree/main

```go
type RFWriter interface {
	io.WriteCloser
	Reload() error
}
```

やりたいこと的に書き込み対象がファイルなのでインタフェースでは[io.WriteCloser](https://pkg.go.dev/io#WriteCloser)を採用  
プラスアルファでリロードしたいときに呼び出す`Reload()`メソッドを定義  

## 動作確認
↓サンプル
```go
package main

import (
	"context"
	"fmt"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/Haya372/go-rfwriter"
)

func main() {
	w, err := rfwriter.NewRFWriter("example.txt")
	if err != nil {
		os.Exit(1)
	}
	defer w.Close()

	ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM)
	defer stop()

	sig := make(chan os.Signal, 1)
	signal.Notify(sig, syscall.SIGINT)
	go func() {
		for {
			fmt.Println("wait signal...")
			select {
			case <-ctx.Done():
				fmt.Println("finish goroutine")
				return
			case <-sig:
				fmt.Println("received signal")
				w.Reload()
			}
		}
	}()

	time.Sleep(1 * time.Minute)
}
```

```bash
$ go run main.go
wait signal...
^Creceived signal
wait signal...
^Creceived signal
wait signal...
finish goroutine
```

途中で`example.txt`を削除してもSIGINTを送ればファイルが再作成されるのでリロードできてそう  

動作確認しやすいようにSIGINTでリロードするようにしたけど、SIGUSR1とかでリロードするようにしておけばnginxの設定を真似てlogrotateの設定を書けばいい感じにログローテーションしてくれそう  

# 参考

https://pkg.go.dev/io  

https://qiita.com/koudaiii/items/23322bf7037c6a7b1cea
新卒1年目エンジニアが技術キャッチアップのために何をした(している)か

# 目的
* 新卒1年目エンジニアがこれまで触れたことのない技術を目の前にして何を思ったのか、何をしたのかを知ってもらう
* 同じような1年目のエンジニアや、それを教育する立場の人たちにとって何か参考になれば嬉しい

# 前提
## 入社前のプログラミング経験（時系列順）
* Ruby on Rails
    * 簡単なCRUDのアプリケーションを作成したことだけある
    * Railsの勉強までにHTML/CSS/JavaScriptの知識はさわりだけ
* Vue.js(JavaScript)
    * 開発のアルバイトの際に初めて触れる
    * コンポーネント間のイベント・データの受け渡しに当時かなり苦戦
    * 最後の方はなんとなく読めるようになってきていた
* Swift
    * 開発のアルバイトで少しだけ触れる
    * 型をちゃんと定義するありがたみを少しだけ知る

## 入社当初のPJで使用されていた技術
* React(TypeScript)
* Laravel(php)
* Inertia.js
    * （とてもざっくりいうと）LaravelのbladeでのHTMLの描画処理をまるっとReactやVueなどのモダンなフロントエンドフレームワークに置き換える技術

上記を見てわかるように、入社当初に渡された技術にはどれも直接的には触れたことがありませんでした。

しかし直属のOJTのような方はおらず、ある程度自力でやっていかなくてはいけないという状況であったため、キャッチアップもある程度自分で行う必要がありました（技術研修的な側面も含んでおり、決して完全に放り投げられていたわけではないので悪しからず）。

この状況でどのような勉強をしたのか・なぜその勉強をしたのか、などを記録しておくことで新人エンジニアの空気感だったりを感じていただければと思います。

# 技術ごとに何を思ったのか・何をしたのか

## React

**思ったこと**

* Vueを触っていたことで抵抗感は薄かったものの、当初は値が更新されるタイミングに困惑した
    * Vueの方が`mounted`、`beforeUpdate`など実行されるタイミングがわかりやすいと思っていた

**やったこと**

* シンプルにReactの[公式チュートリアル](https://ja.react.dev/learn)を熟読した
    * おそらくVueの下地がなかったらいきなり公式のチュートリアルを読むことはできなかったかもしれない
（実際Vueを最初に勉強した時には公式チュートリアルの用語の意味がわからずに挫折しています）

https://ja.react.dev/learn

Reactの公式チュートリアルは個人的にめちゃくちゃわかりやすく書かれていたと思います。
ここまで丁寧なチュートリアルがあるのは珍しいんじゃないかと思っています。

Reactの勉強としてはこれだけで、自分で試すみたいなことはあまりしていませんでした。

代わりに日々の実装の中で疑問に思ったらチュートリアルに戻り、わかった気がしたらまた実装にあたり、もう一回読み返してみたり...を繰り返していました。

結果としてベーシックなReactについてはなんとなく読める・実装できる、というところまで行けたんじゃないかと思っています。

## TypeScript

**思ったこと**

* 元々Vue.jsはJSで書かれていたものを触っていたが、実行してみて期待される結果が入っていない、ということが多かった
* 実行前に目に見えてわかるエラーをあぶり出すことができるのはめちゃくちゃありがたいと思っていた

**やったこと**

* [プロを目指す人のためのTypeScript入門](https://amzn.asia/d/5L4yMzB)を読もうとした→挫折しました
    * 中盤にかけてかなり詳しく型注釈・型推論などの仕様を説明していたが、しんどくなってしまって途中で辞めてしまった
        * Kindleで読んでいると分量が多く感じてしまいきつかった
    * そろそろもう一回読み直して見てもいいのかもしれない

https://amzn.asia/d/5L4yMzB

* ブルーベリー本は挫折したので代わりに[サバイバルTypeScript](https://typescriptbook.jp/)を読んだ
    * 「実務でサバイブできるようにする」ために作られているだけあり、TypeScriptのポイントが簡潔にまとまっている
    * 大抵詰まった時にはこれを読むことで解決できた

https://typescriptbook.jp/

## Laravel

**思ったこと**

* できることが多すぎて追いきれない
* 基本的な処理は簡潔に書けすぎて、逆に怖い
    * 本当にこれだけでいいの？感

**やったこと**

* [Laravelリファレンスの日本語版](https://readouble.com/laravel/11.x/ja/installation.html)を一部読んだ
    * 各機能の使い方を読みつつ、重要そうなセクションにまとめられている「サービスコンテナ」や「ファサード」ってなんだろうっていうのを何回もやっていた

https://readouble.com/laravel/11.x/ja/installation.html

* リファレンスを読んだだけではLaravelのコアな部分が全然伝わって来なかったので、以下のような記事をはじめ少しでもヒントが得られそうなものはとにかく一度目を通した

https://zenn.dev/yskn_sid25/articles/71a17cf67d6461

https://qiita.com/minato-naka/items/afa4b930a2afac23261b

## Inertia.js

https://inertiajs.com/

* Inertiaについては、実務で使う中で使い方はわかるが、実際どんな作りになっているのかはあまりわかっていない
* React、Laravelという両者にまたがった技術がどのように実現されているのかを今後調べて記事にもする予定

# 最後に

色々読んでみたはいいものの、正直まだ自分の中では有用性を感じ取れていない部分や仕組みを理解しきれていない部分があります。

技術を使いこなすのだけでもとても大変だと思うのですが、純粋な興味と、色々できることが増えるかもしれないという期待もあるので

これからもどう使うのが良いのか、なぜそういう仕組みになっているのか？を深めていけたらと思っています。
[Rust]関数の基本とスコープ管理

## 関数

関数の宣言は`fn`を用います。引数がある場合は`fn foo(bar: i32)`のように`()`の中に引数名とその型をペアにして列挙します。
戻り値は`-> <型>`の形で宣言します（戻り値が無い場合は省略できます）。

Rustの特徴として、関数の最後に`return`を明示的に書かなくても値を返すことができます。Rustでは文末にセミコロンがないものを「式」と呼び、何らかの値に評価されます。逆に、セミコロンが付いている場合はそれが「文」となり、値に評価されません。関数やブロックの最後にセミコロンを付けない「式」を書くと、その値がその関数やブロックの戻り値として扱われます。そのため、関数の最後に戻り値を示す式（セミコロンを付けない形）を書くことで、`return`を使う場合と同じように値を返せます（もちろん、`return`文を明示的に使うことも可能です）。

```rust
fn add(a: i32, b: i32) -> i32 {
    a + b
}

fn main() {
    let result = add(5, 3);
    println!("The sum is: {}", result);
}
```

:::note warn
TypeScriptと違い、関数の戻り値は型推論されないので、明示的に指定する必要があります。

```ts
// `:number`が無くても暗黙的にnumberを返す関数と推論される
const multiply = (x: number, y: number) => {
    return x * y;
};
```

```rust
// `-> i32`は省略できない
fn multiply(x: i32, y: i32) -> i32 {
    x * y
}
```
:::

## スコープ

ブロック`{}`内で宣言された変数は、そのブロックの中でしか利用できません。この有効範囲を「スコープ」と呼びます。
ある変数のスコープを抜けると、その変数のメモリは解放され、もうアクセスすることはできません。

```rust
fn main() {
    {
        let x = 42; // xはこのスコープ内でのみ有効
        println!("x: {}", x);
    }
    // println!("x: {}", x); // エラー: xはスコープ外
}
```

## 引数のコピー

関数が引数を取る場合、その引数は型によってコピーされるかどうかが決まります。`i32`や`bool`のような型の引数の場合、コピーされて関数に渡されます。一方で、`String`や独自の構造体のような型の引数の場合、コピーされません。

```rust
fn takes_ownership(s: String) {
    println!("{}", s);
}

fn makes_copy(n: i32) {
    println!("{}", n);
}

fn main() {
    let s = String::from("hello");
    takes_ownership(s); // sの所有権が関数に移動
    // println!("{}", s); // エラー: sはもう使えない

    let n = 42;
    makes_copy(n); // nはコピーされる
    println!("{}", n); // nはそのまま利用可能
}
```

## クロージャ

クロージャは関数の一種で、定義外の変数を捕捉することが可能です。記法が通常の関数宣言と異なっており、`()`の代わりに`||`を利用します。ブロック部分も、式が一つだけでそれをそのまま戻り値として使うのであれば`{}`も不要になります。
また、変数にバインディングすることができます。

```rust
fn main() {
    let add = |a: i32, b: i32| a + b;
    println!("5 + 3 = {}", add(5, 3));

    let x = 10;
    let print_x = || println!("Captured x: {}", x);
    print_x();
}
```

クロージャに関しては強力な型推論が働きます。通常の関数宣言と異なり、型アノテーションは省略することができます（引数名は省略できません）。

```rust
fn main() {
    let square = |n| n * n;
    println!("Square of 4: {}", square(4));
}
```

:::note
このクロージャという仕組みはTypeScriptでいうアロー関数と似た使用感を持っています。
```ts
const add = (a: number, b: number) => a + b;
console.log(`5 + 3 = ${add(5, 3)}`);
```

筆者の感想ですが、アロー関数は単に記法の話で無名関数として使うことが多い一方、Rustでは明確に「スコープ外の変数を利用できる」という特徴を持たせているのが印象的です。

また、引数の型アノテーションまで不要なのに驚きました。
:::

クロージャがスコープ外の変数を参照するとき、以下のどれかの方法で参照します。基本的には（イミュータブルな）参照を取得しようとし、場合に応じてミュータブルな参照もしくは値そのものを取得します。

値そのものを取得するとき、それがコピー可能であればコピーします。コピー不可能である場合、所有権そのものをクロージャに移動します。`move`キーワードを使うと、所有権の移動を強制できます。


```rust
fn main() {
    let mut x = 5;

    let immut_closure = || println!("x: {}", x); // 共有参照
    immut_closure();

    let mut_closure = || {
        x += 1; // 可変参照
        println!("x after mutation: {}", x);
    };
    mut_closure();

    let move_closure = move || {
        println!("x moved: {}", x); // 所有権移動
    };
    move_closure();
}
```
AtCoder ABC382 PythonでA〜Cを復習

## ABC382 感想まとめ

今週は色々あって忙しく、ABC382コンテスト本番から６日後の金曜日にようやく復習できました。

* C問題が配点350となっていて、いつもよりも難しいのでは...と思いながら解いていたのですけど、difficulty 476でそうでもないのでした
* D問題は問題を読んで「難しそう」と思い未着手で終わったのですけど、こちらもdifficulty 685 で、D問題としてはそこまででもない難易度でした

ちょっと今回は、最近の練習不足が表に出てしまった感じですね...。

## [A - Daily Cookie](https://atcoder.jp/contests/abc382/tasks/abc382_a)

クッキーを食べる数をカウントして、食べた数だけ空き箱が増える...という方針です。




``` python
N, D = map(int, input().split())
S = input()

cookie_count = 0 # クッキーの数
empty_count = 0  # 空箱の数

for i in range(N):
    if S[i] == '@':
        cookie_count += 1
    else:
        empty_count += 1

# 食べた数をカウント
if D > cookie_count:
    eat_count = cookie_count
else:
    eat_count = D

print(empty_count + eat_count)
```

問題文 ``` @ は D個以上含まれる ``` という条件を見落としていて、その場合の対応処理を書いていたので、もう少し簡単に書けそうです。


## [B - Daily Cookie 2](https://atcoder.jp/contests/abc382/tasks/abc382_b)

文字列Sの右から、Dの数だけ '@' を '.' に置き換えます。

``` python
N, D = map(int, input().split())
S = list(input())

eat_count = 0

# 文字列の右側からチェック
for i in range(N-1, -1, -1):
    # '@' を '.' に置き換え
    if S[i] == '@':
        S[i] = '.'
        eat_count += 1

    # D 回置き換えたら終了
    if D == eat_count:
        break

print(''.join(S))
```

## [C - Kaiten Sushi](https://atcoder.jp/contests/abc382/tasks/abc382_c)

この問題はソースコードの実装量が多くなってしまい、難しかった。
方針は以下のようにしました。

１. Aを左から見ていって、その時点での最小値の配列を求める
> A = [3 8 2] なら、[3 3 2]

２. 重複しているところを省略する。また、美食度:indexのdictを作る
> [3 3 2] → [3, 2] (サンプルでは min_a_list )

> {3 : 0, 2 : 2} (サンプルでは value_to_index )
> 美食度3の人は index=0 にいる。美食度2の人は index=2 にいる。という情報。

３．Bの各値(美味しさ) について、Aの中のどの人に食べられるのかを求める
 　3.1 min_a_list を２分探索して、どの美食度の人に食べられるかを調べる
 　3.2 value_to_index をつかって、美食度の人がどの位置にいるかを調べる

``` python
N, M = map(int, input().split())
A = list(map(int, input().split()))
B = list(map(int, input().split()))

min_a = min(A) # A内の最小値

min_a_list = [] # Aを左から見ていったときの、最小値の配列
min_a_list.append(A[0])
value_to_index = {A[0]: 0} # {美食度 : index} の dict
current_min = A[0] # 現在の最小値
for i in range(1, N):
    if A[i] < current_min:
        current_min = A[i]
        min_a_list.append(A[i])
        value_to_index[A[i]] = i

# 配列を反転
min_a_list.reverse()

answers = []
for i in range(len(B)):
    b = B[i]
    
    # bがAの最小値未満なら、-1
    if b < min_a:
        answers.append(-1)
        continue

    # 二分探索で、食べる人の位置を検索
    index = bisect.bisect_right(min_a_list, b)

    # value = 食べる人の美食度
    value = 0 
    if index == 0:
        value = min_a_list[0]
    else:
        value = min_a_list[index-1]

    # 美食度valueを、Aのindexに変換して、格納
    answers.append(value_to_index[value] + 1)

print('\n'.join(map(str, answers)))
```
cdでディレクトリ移動は時代遅れ？？zoxideで簡単高速ディレクトリ移動！！

## はじめに
ターミナルでのディレクトリ移動といえば`cd`コマンド。しかし、より効率的な方法があることをご存知でしょうか？本記事では、ディレクトリジャンプツール「zoxide」の魅力をご紹介します。

## zoxideとは
zoxideは、機械学習を利用したスマートなディレクトリジャンプツールです。よく使用するディレクトリを記憶し、曖昧な検索で素早くアクセスできます。Rustで書かれており、高速で軽量という特徴があります。

## なぜzoxideを使うべきか
1. **直感的な操作**
   - `z documents`のように、フルパスを入力する必要がありません
   - 曖昧検索に対応しているため、完全一致でなくてもOK

2. **学習する賢さ**
   - 頻繁に訪れるディレクトリを自動で学習
   - より使用頻度の高いディレクトリが優先的に選択される

3. **高速な動作**
   - Rustで実装されているため、処理が非常に高速
   - シェルの起動速度への影響も最小限

## インストール方法

### macOS (Homebrew)
```bash
brew install zoxide
```
他のインストール方法

https://github.com/ajeetdsouza/zoxide?tab=readme-ov-file#installation

## 設定方法

### bash
```bash
echo 'eval "$(zoxide init bash)"' >> ~/.bashrc
```

### zsh
```bash
echo 'eval "$(zoxide init zsh)"' >> ~/.zshrc
```

### fish
```bash
echo 'zoxide init fish | source' >> ~/.config/fish/config.fish
```

## 使い方
- **一度だけ**でもdocumentsというフォルダに移動すると曖昧検索
    ```bash
    # ~/Documents に移動
    z documents 
    or
    cd documents   
    ```
    ```bash
    z doc         # 曖昧検索で ~/Documents に移動
    ```
<br/ >
- ネストが深い場所でも簡単に移動が可能
    ```bash
    cd documents/GitHub/next_app
    ```
    ↓
    ```bash
    z ne #neの中で一番頻繁に使うディレクトリがnext_appの場合
    ```

## cdとの比較
| 機能 | cd | zoxide |
|------|-----|---------|
| パス指定 | フルパス必要 | 曖昧検索可能 |
| 学習機能 | なし | あり |
| インタラクティブ選択 | なし | あり |
| 実行速度 | 速い | 同等 |


## まとめ
zoxideは現代のターミナル操作に欠かせないツールです。一度使い始めると、従来の`cd`コマンドには戻れなくなるでしょう。私はなりました。多くのプロジェクトで作業する開発者にとって、作業効率を大きく向上させてくれます。ぜひ、zoxideをインストールして、新しいディレクトリ移動の体験を始めましょう！

## 参考リンク
- [zoxide GitHub](https://github.com/ajeetdsouza/zoxide)
2024年版　Obsidianコミュニティプラグイン個人的レビュー

# はじめに
皆さん、Obsidian使ってますか？

https://obsidian.md/

Obsidianはマークダウンエディタでありながら、コミュニティプラグインを導入することで様々な機能を追加することができるアプリケーションです。

私は2024年1月あたりから使い始めたのですが、やれることの多さ、カスタマイズの自由度などから非常に気に入っています。
周囲の人間に地道な布教を続けた結果、徐々に利用者が増えているような気がしています。
嬉しいですね。

ただやはり、コミュニティプラグインを積極的に導入している方は少なく、単なるマークダウンエディタとしての利用にとどまっているように見えます。
もったいないですね。

個人的には、Obsidianのこのコミュニティプラグインが便利だった！的な会話をしたいのですが、いまいち盛り上がりに欠けている状態です。
本記事ではその先駆けとなるべく、2024年で利用したコミュニティプラグインを3段階評価でレビューしていきたいと思います。

:::note warn
評価軸はあくまで私の「入れてよかった」感です
使い方がいまいちわからないまま低評価にしてしまったものもあるので、気になったらご自身でお試しください
:::

## ☆☆★（3点満点中1点：入れてもいいし入れなくてもいい）
### Dialogue
https://github.com/holubj/obsidian-dialogue-plugin

対話形式のノートを作成できます。
ChatGPTとの問答を保存しておきたいと思い導入しましたが、いまいちレイアウトが綺麗にならず結果的に読みにくいノートにしかならなかったため、使用しなくなりました。


### Auto Card Link

https://github.com/nekoshita/obsidian-auto-card-link

URLを貼るとカードとして表示してくれます。
ノートの見た目が綺麗になるので使い出はあります。
入れない理由もないですが、入れなくても大丈夫です。

### Highlighter

https://github.com/chetachiezikeuzor/Highlightr-Plugin

名前の通り、ノートをハイライトできるようになります。
白黒のObsidianで色をつけられるのは便利では？と思い導入しましたが、思っていたより使用しませんでした。
また、編集モードと表示モードを切り替える際に埋め込まれたコードがちらつくため、やや邪魔な瞬間もあります。

### Hover Editor

https://github.com/nothingislost/obsidian-hover-editor

ノートのリンクにマウスオーバーすることで、リンク先ノートのホバー表示・編集が可能になります。
ノートはタブで開いてしっかり読み書きしたい場面が多く、ホバーできてよかったと思うタイミングはかなり少なかったです。

### Floating Search

https://github.com/holubj/obsidian-dialogue-plugin

Obsidian内での検索をモーダルで出来るようにするプラグイン。
検索窓が見やすくなるため一定の利便性はありますが、既存の検索窓でも十分です。


## ☆★★（3点満点中2点：便利、入れてよかった）
### kanban
https://github.com/mgmeyers/obsidian-kanban

Obsidian内にカンバンボードを作成できます。
思っていたよりもスムーズに動くこと、カンバンボード内に作成したタスクからノートを作成できることから想像よりも便利だと思いました。
日々のタスク管理アプリに悩んでいる方にはおすすめできます。

### Git
https://github.com/Vinzent03/obsidian-git

Obsidian全体をGitのリポジトリに保存できるようになります（自動commit & pushも可能）。
モバイル含む別端末からアクセスできるようになる上、バックアップにもなるので安心ですね。
入れておいて損はないかなと思います。

### Marp Slides
https://github.com/samuele-cozzi/obsidian-marp-slides

マークダウンからパワーポイントスライドを自動作成してくれるmarpのObsidian拡張版。
いつものようにメモ取って編集しておくだけで、発表等で利用できるスライドができます。
一発でいい感じのものができるわけではないですが、メモがスライドになる感覚が面白いので使ってみてほしいと思ってます。

### Open In New Tab
https://github.com/patleeman/obsidian-open-in-new-tab

ノートを開く際に新規タブで開いてくれるようになるプラグイン。
複数タブを開いて行き来しつつ作業をする方にはぜひおすすめしたいプラグインです。
地味ながら、非常に便利ですね。

## ★★★（3点満点中3点：欠かせない）
### Calendar
https://github.com/liamcain/obsidian-calendar-plugin

タブとしてカレンダーを表示することができます。
日付をクリックするとその日のDailyに飛べたり、Weeklyを作成できたり…
Daily内にタスク（未済のチェックボックス）が残っているとカレンダー上での表示が変わるので、後述のThinoと合わせるとタスクの漏れを減らせます。

### Thino（旧:Obsidian memos）
https://github.com/Quorafind/Obsidian-Thino

Twitterのような形式で、Dailyにタイムスタンプ付きのメモを残せます。
チェックボックスとして残すことも可能で、ちょっとした思いつきや軽いタスクなどを残しておけます。
考えてる最中に出てきた疑問を残しておくとか、一旦思考内容を置いておけるのは想像よりも便利です。

### Templater
https://github.com/SilentVoid13/Templater

ノートのテンプレート作成をより強力にするプラグインです。
マークダウンのノートにJavaScriptを埋め込むことが可能になるため、動的なDailyNoteやメモを作成できます。
曜日ごとのタスクをDailyテンプレートに埋め込んでおくとか、スクリプトを実行するとかとか…ややハードルはありますが、なんでもできるようになるため必須のプラグインです。


## 終わりに
今回レビューしたプラグイン以外にも大量のプラグインを試した記憶はあるのですが、ほとんどがアンインストールされた or 使用用途すら覚えていないため、割愛しました。
是非皆さんもおすすめのプラグインを教えて下さい。
社内SEとして１年経験して、よかったこと、悪かったこと

# はじめに
田舎で社内SEをしているあたなと申します。
タイトルにもありますが、社内SEという職種を１年ほど体験して感じたことをまとめたいと思います。社内SEに転職しようか迷っている人やどんな職種か気になっている人の助けになれば幸いです。
企業の概要は下記になります。

・田舎の中小企業
・社内システムがなく、Excelで全てを管理
・この度新しく情シス部門を設立



:::note warn
※この記事は私が体験したことが主な内容となっておりますので、
社内SEすべてに当てはまるものではないことをご了承ください。
:::

## よかったこと

### ●ITに関する全般的な知識が身につく
Windowsの設定やインフラ面、時にはハードの分解などの幅広いITに関する知識をつけることが出来ます。一般的に言われるPCに詳しい人になれます。

### ●コミュニケーション能力が身につく
社内の人はもちろん、多くのベンダー様と関わる機会が増えたことによってコミュニケーション能力が身につきました。
会議が多かったことで自分から積極的に発言することの大切さも学びました。
声のデカい人は強い

### ●上流工程に携われる機会がある
社内で新しくソフト等を導入する際に上流工程を経験することが出来ます。
社内の関連する部署の方に現状を聞き、システムに起こす際の要件定義、基本設計などを経験できます。
また議事録作成などの書類作成スキルも上がります。

### ●ヘルプデスク能力が身につく
トラブルに際し、迅速に解決に導く問題解決能力が上がりました。
PCがフリーズする、ソフトの使い方がわからない、WordやExcelがわからないといった多岐にわたる質問がきます。
それぞれが独自に設定を施しているPCに対して、適切に対処する必要があります。
Office関連のスキルもここで伸びました。


## 悪かったこと
### ●肩身が狭い
直接的に企業に利益を出して貢献しない間接部門なので、何かと肩身を狭い思いをします。

### ●開発スキルが下がる
プログラミングをしない人にとっては関係ないかもしれませんが、基本的にシステム開発はベンダーに依頼する形をとるため、自分から進んで学習しない限りプログラミングスキルや開発スキルは下がります。

### ●システムトラブルにてパワハラを受ける可能性がある
PCが遅い、サーバにアクセスできない、メールが届かない等の機械に関わるトラブルは全て情シスの責任になるのでトラブルが頻発すると大声で怒鳴る人も出てきます。
経験談ですが、社内で使用している複合機が頻繁に紙詰まりやしわが発生した時は、社内のど真ん中で「どうしてくれんねんこれぇ」「仕事ならんぞぉ」などの叱責を大声で受けました。

→ストレス耐性が上がったので結果としてアドとなりました。

## さいごに
これからIT化を進めていくという段階にて入社したので、他企業では経験できない業務が多くありました。またプログラミングの経験しなかった自分にとってPCに詳しい人になれたことが嬉しかったです。
エンジニアというより会社員、サラリーマンという響きが似合う職種なので、専門性が低くなることだけが唯一のデメリットかなと感じました。
メリット、デメリットは人それぞれだと思いますが、この記事が情シス未経験の参考になれば幸いです。
ちゃんと英語を勉強した人でも英語で業務遂行は難しい

# はじめに
海外に数年留学して日本で英語を使って仕事を始めてみたら、日本の英語力と自分の英語力の方向性の違いが見えてきました。
  
英語を話せる人、英語を理解できる人は重宝される。 
昔から皆がそれを理解し、その事実があるにも関わらず習得している人は少ない。 
「学生時代にあの人は成績優秀で～」みたいな話があるとする、英語の評価満点で中学校から高校英語の文法すべて覚えています！もう完璧ですって人でも英語が話せないことがほとんどである。 
ここでは日本独自の教育が原因の可能性がある。 
  
# 日本人は話すための実践英語を学んでいない？
  
我々の英語教育の中で最も優先的に学んでいたものは何だろうか。文法、単語、そして決められた範囲のリスニング。 
話すことについては二の次になっているように見受けられる。 
”英語の勉強ってどうやってする？”　って聞かれたときに英語の本を読む、問題集を解くなど当たり前の返答が返ってくるだろう。しかし勉強方法として英語が出来る人とコミュニケーションを取るって答える人はおそらくほぼいない。 
だが振り返っても見てほしい我々がまだ何も話せない赤子であった時、何から学んだ？文法？単語？リスニング？スピーキング？どれも違う。皆絶対に会話から始めているはずだ。 
文法を間違えていたとしても自分でその間違えに気がつき改善し、自分自身で学んできたはず。意思疎通を取るために親から始まりいろんな人と会話してきたはず。 
だが日本の教育では使うことよりも理解することに重きを置いている為、英文法の習得は他国と比べて優秀でも、英会話になると急にレベルが低くなってしまっていると言える。 
  
# なぜTOEICの点がとれる日本人も、実際の会話ではYES/NOしか言えなくなるのか？ 
  
　先ほどお話しした中で英会話になると急にレベルが低くなってしまうといったが、それはどの場面でもあり得ることだ。 
私がいる現場で先日インドの方と仕事をする機会があった。客先にいる英語環境に慣れている方々はうまく仕事をこなしていたが、英会話の経験が少ない私の同僚についてはかなり難しい顔をされていた。しかしチャットベースだと会話が順調に進んでいるように見受けられた。 
　たまに英語を話せる人が偉そうに「そのチャットでやってる会話をそのまま口で言えばいいだけだよ」って言うが、実際にできない側からしたらたまったものではないだろう。間違えてでも相手に意図が伝わればいいと思って英語を習得した人と、絶対に間違えてはいけない前提（定期テストや受験など）で英語を習得した人では1つの文に対して考える時間がそもそも違うのだ。結果的に自分が返答でき、即答できるワードYES, NOしか言えなくなる。 
  
  
# 英語を使って業務するのは難しい。より会話を円滑にするには英会話を学ぶべきだ 
  
　上記に述べたように日本の試験前提で習得した英語では業務どころか英会話も難しいだろう。なぜなら日本では使うことよりも理解することに重きを置いているがゆえに実践の英会話はあまり教わらない。正確には教師も同じような教育を受けて育ったので、有効的な会話を十分には教えられない。ここまでだと日本の教育はよろしくないと思う方もいるかもしれないが、それは英会話のみに焦点を置いた場合であり、逆に日本の教育で教わる文法をちゃんと会話で扱えるようになれば、一気にコミュニケーションの幅は広がる。 
　なのでまずは英会話が上手な人と話してみて、その人の会話の仕方を真似する。文法が間違っていても、まずは伝わればいいぐらいの軽い気持ちで挑戦していけば自然とコミュニケーションが取れるようになるだろう。間違えていい教育をされていない日本人からすると難易度は高く詰まってしまう事が多いかもしれないが、やっていくうちに会話でしか使わない言い方や、簡単な言い回しなんかも自然と身につくので英語への苦手意識も自然と弱まっていくのではと思う。
NeoVimの環境構築のエラーについての備忘録

私は、Lazy.vimを用いてプラグインを管理しており、ddc.vimのインストールを行おうとしていた。すると、以下のようなエラーを吐かれてしまった。
```
E117: 未知の関数です: denops#plugin#is_loaded
```

解決策としては、dependenciesの項目に"vim-denops/denops.vim"を追加するだけであった。skkelton.vimためのdependenciesにvim-denops/denops.vimを書いているから、ddc.vimのためのdependenciesには書かなくても大丈夫だと思ったが、どうやらそういうわけではないらしい。つまらないミスであった。
オドメトリ　勉強

　こんにちは、ロボットテクノ部です。
 今回の部活では、オドメトリの勉強を基礎的なところから勉強しました。

 ![1000000064.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3914799/77de1c79-7ccf-b2f1-465d-86d368074347.jpeg)

参考文献
・正木良三(2018) 『自律走行ロボットの制御技術』
・奥田哲郎、田井普、髙木健太、中西泰人　(2024) 『UnityとRos2で実践するロボットプログラミング　ロボットUI/UXの拡張』
【TypeScript】条件値によって戻り値を切り替える型の実装（type-challenges 初級編 268・if）

## お題
条件値`C`、`C`がtruthyである場合の戻り値の型`T`、`C`がfalsyである場合の戻り値の型`F`を受け取る`If`を実装する。条件値`C`は`true`か`false`のどちらかであることが期待されるが、`T`と`F`は任意の型を取ることができる。
## やりたいこと
```typescript
type A = If<true, "a", "b">; // => "a"
type B = If<false, "a", "b">; // => "b"
type C = If<boolean, "a", "b">; // => "a" | "b"
```
## 解答
```typescript
type If<C extends boolean, T, F> = C extends true ? T : F;
```
## 解説
### 処理の流れ
- `<C extends boolean, T, F>`
`C`には`true`か`false`が期待されているので、`boolean`に制限する。
- `C extends true ? T : F`
Conditonal Typesを使って、`C`がtruthyなら、`T`、falsyなら`F`を返す。

### なぜbooleanの場合ユニオン型が返されるのか？
```typescript
type C = If<boolean, "a", "b">; // => "a" | "b"
```
**`boolean`型は`true | false`のユニオン型だから。**

### Conditional Typesとは...
https://qiita.com/yuto99999/items/057e28323118c4ac5de0#conditional-types%E5%9E%8B%E3%81%AE%E6%9D%A1%E4%BB%B6%E5%88%86%E5%B2%90%E3%81%A8%E3%81%AF

## 参考記事
https://mosya.dev/blog/tc-if

## 今回の問題
https://github.com/type-challenges/type-challenges/blob/main/questions/00268-easy-if/README.ja.md
AWS Transfer Family SFTP で「固定IP」「接続元IP制限」「パスワード認証」を実現する

# はじめに
気がついたら華金の投稿が多くなっている [@\_\_\_nix___](https://twitter.com/___nix___)  です。


# 背景
AWS Transfer Familyを使用してSFTPサーバーを構築し、ファイルをS3バケットにアップロードするワークフローを設定することは、多くの企業にとって重要なタスクです。
このTerraform構成は、AWSのさまざまなサービスを組み合わせて、セキュアでスケーラブルなファイル転送ソリューションを提供します。


# 概要
このプロジェクトは、AWS Transfer Familyを使用してSFTPサーバーを設定し、ファイルをS3バケットにアップロードするためのワークフローを構築します。
アップロードされたファイルはSQSキューを介して管理され、Lambda関数によって処理されます。
SFTPサーバーは、SSHキー認証とパスワード認証の2つの認証方法をサポートしており、ユーザーのニーズに応じて選択できます。
この記事で紹介するポイントはここで、パスワード認証を許可しようとするとフルマネージドでは無くなってしまう為、自前で構築するにはやや面倒な部分を隠蔽できるという点です。


# 特徴

* SFTPサーバーのIP固定化
    * 厳しい接続元の場合、接続先IPを固定化する要件がある
* 接続元IP制限
    * 流石にどこからでも接続できてしまうのはリスクがある
* マルチ（鍵＋パスワード）認証対応
    * クライアントの都合でパスワード認証を求められることがある

# アーキテクチャ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22939/f279eb8b-dc1b-c815-67c0-7d31f1f1ce6a.png)


# リポジトリ

https://github.com/nix-tkobayashi/terraform-aws-sftp-multi-auth


# 導入

1. リポジトリのクローン: このリポジトリをクローンします。
2. 変数の設定: terraform.tfvarsファイルを作成し、必要な変数を設定します。
3. Terraformの初期化: terraform initを実行してTerraformを初期化します。
4. リソースの確認: terraform planを実行して作成されるリソースを確認します。
5. インフラのデプロイ: terraform applyを実行してインフラをデプロイします。


# 終わりに
このTerraform構成は、AWS Transfer Familyを使用したSFTPサーバーの設定を簡素化し、ファイル転送のセキュリティと効率を向上させます。SSHキー認証とパスワード認証の両方をサポートしており、ユーザーのニーズに応じた柔軟な設定が可能です。S3バケット、SQSキュー、Lambda関数を組み合わせることで、ファイルのアップロードと処理を自動化し、運用の効率化を図ります。

【謝辞】
以下の公式ブログのコードを利用させて頂きました。

https://aws.amazon.com/jp/blogs/storage/enable-password-authentication-for-aws-transfer-for-sftp-using-aws-secrets-manager/

# 一言
最初の要件は、メディア変換用としてのSFTPサーバーでした。
ただ、固定費用が意外にお高いのね、と感じた記憶がありますが、マネージドサービスなのでそこも踏まえての金額なので仕方が無いですね。

この記事良かったと少しでも思って頂けたら是非 [@\_\_\_nix___](https://twitter.com/___nix___) をフォローしてあげてください。或いは記事に対してリアクションをお願い致します。
初めて参画するプロジェクトPM(PMO) 基本設計の工程

こんにちは、小磯と申します。
プロジェクトの中にいくつかの工程があります。
その中にある基本設計について纏めようと思います。
初めて業務を行うPM(PMO)の方へ参考になればと思います。

### システム開発の上流工程プロセス

要件定義と詳細設計の間に位置するソフトウェア開発の工程の一つです。
前工程の要件定義において抽出した要件を機能単位に分割し、それぞれの機能が何を実現するのかを決める工程です。


### 1.基本設計

開発担当者がクライアント担当者にヒアリングした内容をもとにソフトウェアに必要な機能等を盛り込んだ資料です。
要件定義にもとづいて、外側から見てどのような動きをするのかを確認します。


### 2.設計内容

基本設計では以下のような項目を設計します。
プロジェクトによって項目の増減があります。
　①業務フロー
　　→業務の流れを理解し機能を洗い出す
　②機能一覧表
　　→開発範囲となる機能の一覧
　③ネットワーク構成図
　　→ネットワークの構成
　④テーブル定義
　　→データベースのテーブルの定義
　⑤ER図（データベース設計における代表的な設計図）
　　→データベースのER図の作成
　⑥画面レイアウト
　　→画面イメージ
　⑦帳票レイアウト
　　→帳票イメージ


### 3.設計によくある課題

設計には色々と課題があります。
課題として以下になります。
　①設計の本質を理解していない
　→顧客へのヒアリング内容をもとに作成した要件定義をベースにして、顧客が持つビジネス上の課題を解決するようなソフトウェアの図面を作るというものです。
　　それだけでは設計の本質を捉えきれていません。
　　顧客の意図をくみ取り必要な機能を導入でき、システムを実現するための手順を明確にし、かつ品質を保証することです。
　②設計に関する基準が無い
　→システムを構築するためのプログラミングでは世界標準の言語を使用するので、ある程度の属人化は防げる傾向にあります。
　　個人的に開発したプログラミング言語を使用することはまずないので、言語さえ習得していれば理解は難しくありません。
　　一方で設計には世界標準が存在せず、最悪の場合社内の開発チームによって設計方法が異なります。
　　これが設計の属人化が発生する大きな理由です。
　③標準化のための仕組みを持たない
　→設計から属人化を排除するためには組織が定めるルールを作成する必要があります。
　　これを標準化というのですが、単にルールを作成するだけでは属人化は排除できません。
　　徹底した属人化の排除には標準化の仕組みが大切です。
　　プロジェクトごとに必要なものが異なるのは当然のことであり、テンプレートで必要なものが足りなかったとならないようにしなければいけません。


- まとめ
基本設計はそれぞれの機能が実現させるために重要な工程です。
クライアントや開発担当との認識が合わないと設計書の作成が出来ません。
クライアントと開発担当とのコミュニケーションを密に取り認識を合わせていくとよいと思います。

他にもプロジェクトに関する記事を投稿しておりますのでお役に立てればと思います。
[プロジェクト ウォーターフォールとアジャイルの違い](https://qiita.com/pesysyon/items/e77b869b5c90b667680b)

[初めてプロジェクトに参画する方へプロジェクトとタスクの意味について](https://qiita.com/pesysyon/items/a7da021a7d596df5e5fd)

[初めて参画するプロジェクトPM(PMO) 要件定義の工程](https://qiita.com/pesysyon/items/cf40037f484b99e16621)

以上、小磯でした。
【Next,js】layout.tsxの活用法

## はじめに
今回は、Next.jsのバージョン14にアップデートされた際、`layout.tsx`の使い方について新たに学んだことを解説します。初歩的な使い方から、応用的な活用法までを具体例を交えて説明していきます。

## 目次
1. layout.tsxって？
2. 応用したlayout.tsxの活用法

## layout.tsxって？
Next.jsで新しいプロジェクトを作成すると、`src/app`ディレクトリ内に`layout.tsx`というファイルが生成されます。このファイルは、**同じ階層以下の全てのページに適用されるレイアウト**を定義するためのファイルです。

例えば、全ページに共通するヘッダーを表示したい場合、以下のように`layout.tsx`内に`Header`コンポーネントを記述することで簡単に実現できます。`Header`コンポーネントは別階層で作成していますが、今回は省略しています。


```typescript:src/app/layout.tsx
import type { Metadata } from "next";
import "./globals.css";
import { ToastContainer } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body>
      <Header/>
        {children}
        <ToastContainer />
      </body>
    </html>
  );
}

```

私はここまでの使い方しか知らず、「単一の`layout.tsx`で全ページ共通のレイアウトを定義する」ものだと思っていました。



## 応用したlayout.tsxの活用法
`layout.tsx`は単に全ページ共通のレイアウトを設定するだけでなく、特定のグループに限定したレイアウトを適用することも可能です。これにより、異なるページグループごとにレイアウトを分けられます。


例えば、以下のようなケースを考えます。
　①ログインページとサインアップページで共通のレイアウトを使用。
　②その他のページでは別のレイアウトを使用。
 
この場合、ログインとサインアップページをグループ化し、それぞれのグループ内に専用の`layout.tsx`を作成します。


以下のように作成することによって認証ページはその階層に作成された`layout.tsx`が適用されることになります。


```
src/
├── app/
│   ├── (auth)/
│   │   ├── layout.tsx
│   │   ├── sign_in/page.tsx
│   │   └── sign_up/page.tsx
│   ├── layout.tsx
│   ├── page.tsx
```

app内に作成された`(auth)`ディレクトリについて説明します。
ディレクトリ名を()で囲むと、**URLにはそのディレクトリ名が含まれません。**
例: `localhost:3000/auth/sign_in` → `localhost:3000/sign_in`
特定のページグループ専用の`layout.tsx`を定義できます。

つまり、今回のように、`layout.tsx`をそのグループ内で適用させるために、ディレクトリは作成したいが、URLいには含めたくない場合に()は便利です。



## 終わりに
今回は、`layout.tsx`の基本的な使い方から、ページごとにレイアウトを分ける応用例まで解説しました。また、()ディレクトリを活用することで、URL構造を簡潔に保ちながら柔軟なレイアウト管理ができるようになります。

Next.jsにはまだまだ便利な機能が多くあるので、これからも活用例を見つけ次第共有していきたいと思います！
ここまで読んでいただき、ありがとうございました。
【Java】文字列を連結する汎用メゾッド

文字列を連結するための処理を共通化したメゾッド。<br>
`StringbBuilder`および`StringJoiner`を使っています。
毎回忘れているので自分用にメモ。

参考文献：

https://blog.retheviper.com/posts/java-string-concat-and-split/


# StringBuilderを使った文字列連結メゾッド
拡張for文を使って実装しています。

```java
  /**
   * 引数を連結して返却します。
   * 
   * @param srgs 連結する文字列
   * @return 結合後文字列
   */
  public static String concatStr(String... args) {
    StringBuilder sb = new StringBuilder();
    for (String str : args) {
      sb.append(str);
    }
    return sb.toString();
  }
```

メソッド呼び出し例：
```java
String concatStr = StringUtills.concatStr(String.valueOf(001),"apple",String.valueOf(100.00));
```
今回はメゾッドの引数をString型に限定していますが、
`StringBuilder.append()`自体はString型以外も引数に指定できる仕様です。

例：
```java
StringBuilder sb = new StringBuilder();
sb.append("str");
sb.append(100);
sb.append(100.00);
sb.toString();
```


# StringJoinerを使った文字列連結メゾッド
文字列の間にカンマなどの区切り文字を挿入しながら結合したい場合は`StringJoiner`を用いています。

```java
  /**
   * 指定した区切り文字と引数を連結して返却します。
   * 
   * @param deli 挿入する区切り文字
   * @param args 連結する文字列
   * @return 結合後文字列
   */
  public static String concatStrAndDeli(String deli, String... args) {
    StringJoiner joiner = new StringJoiner(deli);
    for (String str : args) {
      joiner.add(str);
    }
    return joiner.toString();
  }
```

メソッド呼び出し例：
```java
String concatStr = StringUtills.concatStrAndDeli(",",String.valueOf(001),"apple",String.valueOf(100.00));
```
context 、example group、describe

# describe
### describeはexample groupを作成するメソッド
>`The describe method creates an example group`.

### `describe`か`context`メソッドを使ってネストされたグループを宣言できる 
>Within the block passed to describe you can declare nested groups using the describe or context methods, 

### itまたはspecifyメソッドを使っても例を宣言できる
>or you can declare examples using the it or specify methods.

### exampleとは
最終的に何をするのかをテストされるもの

# 会話的な例
```rb
something # 主語
  in one context # 主語の場合分け
    does one thing # 主語が何をするか
  in another context 
    does another thing
```    
># Nested example groups (using context)
>Given a file named “nestedexamplegroups_spec.rb” with:
```rb
RSpec.describe "something" do　# ここでexample groupを作成している
  context "in one context" do  # ここではcontextでネストしたグループを宣言
    it "does one thing" do     # ここではitを使って例を宣言
    end
  end

  context "in another context" do
    it "does another thing" do
    end
  end
end
```
* 条件のような、場合分けのようなことをcontextでは書くのだろう
* どうやらdescribe -> context -> itのように宣言の親子ではないが、関係性があると考える

### example groupはdescribeかcontextのブロックのグループ
>Under the hood, an example group is a class in which the block passed to describe or context is evaluated. 

### インスタンスの内容でテストされる
>The blocks passed to it are evaluated in the context of an instance of that class.


https://rspec.info/features/3-13/rspec-core/example-groups/basic-structure/

# 感想
テストを行う守護に対してグループ分けをしてitでテストが行われる
NFTで一攫千金を狙ったら、夢が粉々に砕けた話



## NFTとはなんぞや  
NFTとは「Non-Fungible Token」の略です。「ノンファンジブル…トークン？」。初めて聞いた人にはちょっと難しそうに感じますが、簡単に言うと **「デジタル世界の一品モノ」** という意味です。  

例えば、100円玉は誰の手にあっても同じ価値ですが、NFTは「これ、世界に一つしかないデジタルアートなんだ！」と主張できるアイテム。Wikipedia先生によれば「NFTはブロックチェーン技術を用いてデジタル資産の所有権を記録するもの」とのことですが、要するに**デジタル版の限定グッズ**と考えればOKです。  

リンクはこちら： [Wikipedia: NFT](https://ja.wikipedia.org/wiki/Non-Fungible_Token)  

---

## 実際にNFTを買ってみた  
「NFTで一攫千金」という夢に心躍らせた私は、まずは仮想通貨を手に入れることからスタートしました。[コインチェック](https://coincheck.com/ja/)でウォレットを開設し、0.01 ETH（イーサリアム、約6000円分）を購入。  

限られた資金で買える「未来のモナリザ」を探すため、NFTマーケットプレイス「[OpenSea](https://opensea.io/ja)」を覗いてみることに。
値段もそれなりに高く、自分の持ち合わせで良いものを探すこと30分
ドッド調でありながらも白い蛇のデジタルアートを見つけました。
「これは縁起が良い白蛇！」と信じたデジタルアートを購入しました。その価格は**0.01 ETH**。  

ワクワクしながら「これでお金持ちになれる！」と期待して数日間フロアプライス（最低価格）を眺め続けた結果…  

**結果：0.005 ETH（約3000円）**  

なんと、価格が半分に！  

---

## 自分でも売ってみた！  
「そうだ、自分でNFTを作って売ればいいんじゃないか！」とひらめいた私は、AI画像生成ツールを使ってNFTアートを自作することにしました。  

テーマは「近未来SF」。完成した作品は、某スター○ォーズに登場してもおかしくないほど派手でかっこいい仕上がり！
そのほかにも風景など10点ほど画像を生成


自信満々で「[OpenSea](https://opensea.io/ja)」に出品し、価格を **0.01 ETH（約6000円）** に設定しました。  

「きっと誰かがこのアートに惚れてくれる！」と期待しながら1週間待った結果…  

**購入数：ゼロ** 
**閲覧数：一番多い作品で 12回 ※ほとんど自分自身** 
もちろんオファー等もありませんでした :cry: 

結局、私のNFTは「デジタルの片隅」に眠り続けることとなりました。  

---

## 結論：儲からない  
NFTは確かに魅力的な技術ですが、「一攫千金」という夢を叶えるにはあまりにも甘すぎる考えでした。よく聞く大成功例は、全体のほんの一握り。現実は非情のためきちんとみなさん働きましょう。

とはいえ、NFTを体験すること自体はとてもユニークで楽しいものでした。
動機はどうであれ新しい技術に触れる目的としては良かったのかなと思います

皆さんもぜひ挑戦してみてください。儲からなくても、新しい技術に触れる面白い経験だけは保証します！
IBM API ConnectのAutoTest Assistについて

# IBM API ConnectのAutoTest Assistについて
[IBM API Connect AutoTest Assist](https://www.ibm.com/docs/ja/api-connect/saas?topic=testing-autotest-assist)は、テスト プロセスを自動化し、エラーを検出することで、API テストを簡素化および高速化します。AutoTest Assist は、API 定義とカスタム ルールに従って AI ベースのランダム要求を生成することで、開発中に API に関する貴重なフィードバックを提供します。

AutoTest プロファイルを作成して実行することで、Assist の動作を制御し、同じ API に対して複数のプロファイルを作成して、さまざまなユースケースに対応できます。プロファイルは、自動テストの実行方法とテストするエンドポイントを指定します。デフォルトのプロファイルは、大規模なセットアップを行わなくてもすぐにフィードバックが得られるように構築されています。

### 機能と利点
1. 自動テスト: AutoTest Assist は、ランダムに生成されたリクエストを送信して API を実行し、大規模なテスト ケースを作成する必要なく、適合エラーとサーバー側のエラーを識別します。

2. 簡単な構成: AutoTest プロファイルを作成して実行することで、Assist の動作を制御し、テストするエンドポイントを指定できます。デフォルトのプロファイルは、ターゲット URL と資格情報のみを使用して簡単に設定できます。

3. 早期エラー検出: API 開発中に、AutoTest Assist は実装エラーを迅速に特定し、開発者が問題を修正して API の品質を確保できるように支援します。

4. 強化された回帰テスト: AutoTest Assist のリクエストのランダムな性質により、従来のテスト ケースでは見逃される可能性のある回帰が明らかになり、API を包括的にカバーします。

5. 補完的なテスト ソリューション: AutoTest Assist は既存のテスト ツールと連携して動作し、テスト戦略を補完し、重点的なテスト ケースを作成するための貴重な情報を提供します。

IBM API Connect AutoTest Assist の動作を確認するには、この 2 分間のデモをご覧ください。
以下の画像をクリックすると、デモ動画が別画面で表示されます。
<a href="https://mediacenter.ibm.com/media/IBM+API+ConnectA+AutoTest+Assist/1_q4uqoog8"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3928184/d598ffea-7f12-6149-6bf1-10265f30b282.png" alt="AutoTest Assist"></a>


[こちらから](https://register.saas.ibm.com/apic/trial/aws)AWS 上の IBM API Connect の 30 日間無料トライアルにサインアップして、AutoTest Assist を体験してください 。
【Eclipse】良く使うショートカット　part2

## はじめに
こんにちは。エンジニアの長谷川と申します。
前回[part1](https://qiita.com/pesysyon/items/348ee7870e94c852e5fe)では、
開発時に使用するショートカットをご紹介しました。

https://qiita.com/pesysyon/items/348ee7870e94c852e5fe

今回は観点を変えて、リモート会議で画面共有をする際に使用するショートカットをご紹介します。

### ズームイン（Ctrl＋＋）
:::note warn
Eclipseのバージョンによってデフォルトのショートカットキーが違うようです。
ここではPleiadesのVersion: 2024-09 (4.33.0)について記載します。
:::

リモートでソースコードの質問をしたり、解説したり、Web会議の場で画面共有することありますよね。
そんな時、「字が小さい」って悩んだことないですか？
やむなくテキストに張り付けて共有とかしてないですか？
ズームイン機能を使えば簡単に拡大できます。

■通常
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/c7ed8161-fa94-3832-a821-0890812a72e5.png)

■2回拡大
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/6287036f-f757-b03d-c5b7-cb7a69a3a53a.png)
大きく表示されて見やすくなりました。

:::note info
元に戻す時は「Ctrl+-」で戻ります。
:::

作業中はあまり使わないかもしれませんが、
Web会議が増加した昨今、参加者によっては拡大が必須だったりするので是非ご活用ください。

:::note info
なお、ショートカットキーが気に入らない場合は、
ウィンドウ→設定→一般→キー
で設定する画面で変更できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/711c0ce2-95ad-d959-35a5-f98e6b466018.png)
:::

以上、長谷川でした。
AWS SSL証明書の自動更新ができなかった理由

AWSからこんな通知が来た
----

> ===== AWS サポートからの連絡内容（翻訳） =====
主題：
必要なアクション - 証明書の更新
体：
Amazon Web Servicesよりご挨拶申し上げます。
AWS アカウントには、2024 年 xx 月 xx 日 23:59:59 UTC に有効期限が切れる AWS Certificate Manager の SSL/TLS 証明書があります。この証明書には、プライマリドメイン xxx と合計 1 つのドメイン。
AWS アカウント ID: xxxxxxxxxxx
AWS リージョン名: xxxx
証明書識別子: xxxx
AWS Certificate Manager (ACM) は、DNS 検証を使用して証明書を自動的に更新できませんでした。2024 年 xx 月 xx 日 23:59:59 UTC までに更新が完了するように対策を講じる必要があります。証明書が更新されず、現在の証明書の有効期限が切れると、Web サイトまたはアプリケーションにアクセスできなくなる可能性があります。
この証明書を更新するには、以下の各ドメインのDNS設定に適切なCNAMEレコードが存在することを確認する必要があります。ドメインのCNAMEレコードは、ACMコンソールで証明書とそのドメインエントリを展開することで見つけることができます。また、証明書のCNAMEレコードを見つけるには、ACM API[1]のDescribeCertificateコマンドまたはACM CLI[2]のdescribe-certificate操作を使用します。詳細については、ACMトラブルシューティングガイド[3]の「自動ドメイン検証の失敗」を参照してください。
>
>このプロセスについて質問がある場合は、サポートセンター[4]にお問い合わせください。AWSサポートプランをお持ちでない場合は、AWS Certificate Managerディスカッションフォーラム[5]に新しいスレッドを投稿できます。
[1] https://docs.aws.amazon.com/acm/latest/APIReference/API_DescribeCertificate.html
[2] https://docs.aws.amazon.com/cli/latest/reference/acm/describe-certificate.html
[3] https://docs.aws.amazon.com/acm/latest/userguide/troubleshooting-renewal.html#troubleshooting-renewal-domain-validation-failure
[4] https://console.aws.amazon.com/support
[5] https://repost.aws/tags/TAJ7zd4vjzSfC_8JNlsbq2tA?forumID=206



## 内容
- 社内のAWS環境のSSL証明書を更新できない

  - 通常は自動更新される予定だが、何かしらの不備により更新できないとの連絡
  - AWS環境が2週間後に使えなくなる


## ChatGPTに聞いた

AWS SSL証明書が自動更新できない主な理由は以下の通りです：
	1.	DNS検証設定の不備: 必要なCNAMEレコードが正しく設定されていない。
	2.	Email検証の利用: Email検証を使用した証明書は自動更新されない。
	3.	未使用の証明書: リソース（例: ELBやCloudFront）に関連付けられていない証明書は更新対象外。
	4.	インポート証明書: ACM外で発行された証明書は自動更新に対応していない。

これらを確認し修正することで、多くの場合、問題を解決できます。


## 調査

### CNAMEレコードが存在した。

→なぜできないのか。

調べていくと、この環境は開発環境で、別に本番環境が存在するらしい。

### 知らなかった！！！！

本番環境にログインし、Route53 のホストゾーンからCNAMEレコードを確認したところ、
対象IDのCNAMEレコードがなかった。

どうやら、去年SSL証明書を自動更新した後、本番環境への移行作業があったらしく、
CNAMEレコードが移行されていなかった。

そのため、今年はCNAMEレコードが存在せず、自動更新が行われなかった。
という経緯らしい。


## 修正

### 対象IDに、Route 53に紐づく、CNAMEレコードを登録。
（こちらは検証環境と同じIDのため、検証環境からCNAMEレコードをコピーしてきた。）

<img width="1237" alt="image" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3656729/d80287cd-d5eb-c8c7-7d62-8873a2d2d825.png"> 


## 結果

### CNAMEレコード登録後、更新できた！！！！！！！！

去年、検証環境から本番環境に移行した経緯があり、
CNAMEレコードが移行されていなかった(本番環境になかった)ため、自動更新ができなかった。

## 結論
:::note info
みなさん、CNAMEレコードの移行を忘れないようにしましょう。
:::
【TypeScript】Awaited<T>の自作（type-challenges 初級編 189・Awaited）

## お題
`Promise`の解決値の型Tを取得するユーティリティ型、`Awaited`を自作する。
## やりたいこと
```typescript
type ExampleType1 = Promise<string>;
type ExampleType2 = Promise<Promise<string | boolean>>;
type ExampleType3 = { then: (onfulfilled: (arg: number) => any) => any };

type Result1 = MyAwaited<ExampleType1>; // => string
type Result2 = MyAwaited<ExampleType2>; // => string | boolean
type Result3 = MyAwaited<ExampleType3>; // => number
```
## 解答
```typescript
type MyAwaited<T extends PromiseLike<any>> = T extends PromiseLike<infer U>
  ? U extends PromiseLike<any>
    ? MyAwaited<U>
    : U
  : never;
```
## 解説
### 処理の流れ
- `T extends PromiseLike<any>`
`T`を`PromiseLike`な型に制約する。
- `T extends PromiseLike<infer U> ...`
`infer U`で`Promise` or `PromiseLike`の中の型を抽出する。
- `U extends PromiseLike<any> ? MyAwaited<U> : U`
抽出された型`U`がPromiseLikeかどうかで条件分岐
= **入れ子になっているかどうかの確認。**
  - 入れ子になっている場合
  `MyAwaited<U>`で再帰的に処理。
  - 入れ子ではない場合
  そのまま抽出された`U`を返す。
- `... : never`
それ以外の場合に`never`を返す。

### PrmosieLikeな型とは...
- thenメソッドを持つオブジェクトのことで、完全なPromiseである必要はない。
```typescript
type ExampleType3 = { then: (onfulfilled: (arg: number) => any) => any };
```
- thenableオブジェクトとも呼ばれる。

### inferとは...
https://qiita.com/yuto99999/items/057e28323118c4ac5de0#infer%E3%81%A8%E3%81%AF

## 参考記事
### `Promise<T>`
- [Promise<T>  | TypeScript入門『サバイバルTypeScript』](https://typescriptbook.jp/reference/asynchronous/promise)
### `Awaited<T>`
- [Awaited | TypeScript入門『サバイバルTypeScript』](https://typescriptbook.jp/reference/type-reuse/utility-types/awaited)

## 今回の問題
https://github.com/type-challenges/type-challenges/blob/main/questions/00189-easy-awaited/README.ja.md
CLIでWEBP変換を行なう

CLI上で画像をWEBPに変換するための手順になります。

## cwebpをインストール
下記のいずれかを実行します。

```shell
# CentOSの場合
sudo yum install libwebp-tools

# ubuntuの場合
sudo apt install webp
```

## 下記のshファイルを作成

```shell
#!/bin/sh

DIR="resources/img"

Files=$(find $DIR -type f -iname "*.jpg" -o -iname "*.png" -o -iname "*.jpeg")

for File in $Files
do
    cwebp -metadata icc -sharp_yuv $File -o "${File%.*}.webp"
done
```

## 実行方法
`DIR`の部分を変換したい画像が配置されているディレクトリのパスに変更します。
`.jpg`、`.jpeg`、`.png`の画像を変換の対象としています。

上記シェルを実行することで変換したい画像と同じディレクトリにwebpに変換された画像が生成されます。
ユーザーヒアリングを実施して事業戦略に基づいたプロダクト改善を行う

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630254/5a17e9fe-da4e-2586-179d-8a298f93ad73.png)
![Designer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630254/e95cd768-dcba-61d8-9a58-43ec957c48da.png) 
Copilot で作成したイメージ画像

## はじめに
この記事は トラストバンク Advent Calendar 2024 の8日目の記事です。
私は、ふるさと納税サイト「ふるさとチョイス」で PdM をやっている @TK2357 と申します。

PdMの役割として、ユーザーの声を聴き、それを事業戦略に沿った形で、プロダクトに反映させる仕事があります。
その手段として、ユーザーヒアリングを実施することもあると思いますが、ユーザーに近付くということは、ユーザーが抱える課題の解像度が上がるという大きなメリットがある一方で、ユーザーの声に影響を受け過ぎる危険性もあります。
今回は、私が実際に行ったユーザーヒアリングの進め方について、書かせていただこうと思います。

## 前提として
トラストバンクは、ふるさと納税サイト「ふるさとチョイス」を運営しています。
私の担当はその CMS で、利用するメインユーザーは、自治体職員さんになります。

## ①．まずは準備が重要
### 専門家の協力を得る
トラストバンクには、UXリサーチの専門部隊あります。
今回の「トラストバンク Advent Calendar 2024」で、12/7 に記事を書いている @TBizuさんもその１人で、今回のユーザーヒアリングにもご協力いただきました。
余談ですが、トラストバンクは部署間での協力に、とても積極的な会社です。

### 事前アンケートの実施
今回のユーザーヒアリングの対象者は、ふるさと納税を担当する自治体職員さんです。
ふるさとチョイスにご掲載いただいている自治体さんは、1700自治体を超えるため、まずはアンケートを実施し、そのアンケートの結果を元に、ユーザーヒアリングを実施することにしました。

### ユーザーの業務を理解する
ヒアリングの対象者が誰であっても、インタビュアーのレベル以上の話を聞きだすことはできません。
そのため、今回は、ユーザーの業務を理解するためにフローを書き起こし、それを元に話を進めることにしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630254/8fffd391-8fdd-09df-2733-0479ceb0a57d.png)

### 業務以外のネタを集める
どんなコミュニケーションでも、つかみが重要であることは言うまでもありませんが、今はLLMを使えば、情報を簡単に集めることができます。
私の場合は、「Copilot」に下記のような質問を投げて情報を集めました。
- ○○県○○町について教えて
- ○○県○○町の特産物を教えて
- ○○県○○町の課題を教えて
- ○○県○○町の人口推移を教えて
- ○○県○○町の過去５年で発生した事件を教えて
etc

「Copilot」の回答で気になったことがあれば、さらに掘り下げて質問します。

## ②．ヒアリングを実施する
### 師匠と弟子モデル
リサーチ手法の１つに「師匠と弟子モデル」があります。
この手法は、調査対象者を師匠に見立てて、インタビュアーが弟子となり、実際の作業を見ながらインタビューを進める手法です。
弟子は師匠の行動を観察し、質問を通じて理解を深め、その結果、ユーザーの実際の行動やニーズを詳しく知ることができます。
ちなみに、今回は、ふるさと納税業務のフローをインタビューしたので、「ふるさと納税を後輩職員に教える」という設定でインタビューさせていただきました。

## ③．プロダクトに落とし込む
### 客観的に眺める
直接話を聞いたユーザーの意見と、そうでないユーザーの意見では、前者の意見の方が重要な意見だと思い込んでしまうことがあります。
１人１人の声を聴くことは重要ですが、その上で、全体を見て最も効果が高い改善ポイントを見つける必要があります。

### 事業戦略に一致しているかを確認する
ビジョンや事業戦略は、企業が社会貢献するための指針です。
それを前提として、「この改善や改修は、事業戦略に一致しているのか？」を常に意識することが重要です。
また、事業会社である以上、行動が無料ボランティアになると継続できません。
再現性あるサービス改善を行うためには、ユーザーに対して価値を提供することで、会社の利益を生み出し、その利益を次のサービス改善の予算に充てる、ということを半永久的に繰り返す必要があります。

## ④．フィードバックを受ける
言うまでもなく、より良いサービスを提供するためには、改善を繰り返す必要があります。
そのためには、改修したプロダクトに対して、ユーザーからのフィードバックを受け、そこから次の改善に繋げていきます。

## まとめ
百聞は一見にしかずで、ユーザーヒアリングを実施することで、多くの知識を得ることができます。
しかし、多くの意見の中で、どれが本当に必要な意見であるかは、その時のタイミングや立場によっても変わることがあります。
そういう時に、指標となるのがビジョンや事業戦略であり、PdMはこれらの理解を深めることが求められます。

## 最後におすすめの機能をご紹介
この度、ふるさとチョイスでリリースされた【お気に入りリストシェア機能】をご紹介します。
この機能は、 ふるさとチョイスのマイページに登録されているお気に入りの品の中から、リストを作って他人に共有することができます。
参考までに、ユーザーリサーチを通じて知り、実際にふるさとチョイスのインスタに掲載されたお礼の品をピックアップしました。
[【ふるさと納税】おすすめのインスタ映えするお礼の品✨📷✨](https://www.furusato-tax.jp/keeplist/product/share/SnHfbFjWY7glTaN0wmjoYlketH4c2cKItiZqMDqQPBo)

最後まで読んでいただきありがとうございます。
　

https://www.furusato-tax.jp/feature/a/commercial2024?top_ttarea=&srsltid=AfmBOoqrD1EZdGpBtYxzYxJFojLCD6IFiTzlM9VtVE0yc2QGi-8YrZuZ

https://www.furusato-tax.jp/contents/think_furusato_tax?srsltid=AfmBOopsWPLb-M0xHo4AXp6XHb7r_HC0cuRj_cJdE9A21lFAyoIElivV

https://www.trustbank.co.jp/recruit/wanted/
GORMのデフォルトロガーは初期設定だと標準出力にSQLをログとして記録してしまう

こんにちは！
LIFULLエンジニアの吉永です。

[LIFULL Advent Calendar 2024](https://qiita.com/advent-calendar/2024/lifull) 10日目の記事です。

先日Goの[GORM](https://gorm.io/ja_JP/)にてデフォルトロガーが意図しない設定になっていた件の調査と対応を行ったので注意喚起もこめて記事にします。

※この記事の内容は[GORM v.1.25.12](https://github.com/go-gorm/gorm/releases/tag/v1.25.12)時点の実装にもとづいたものになります

## GORMのデフォルトロガーについて

https://gorm.io/ja_JP/docs/logger.html

上記に記載の通り`デフォルトでは、スロークエリとエラーをロギング`する設定になっています。

### GORMデフォルトロガー初期設定コード

https://github.com/go-gorm/gorm/blob/f482f25c714b67562af1d487a669d80a527963b3/logger/logger.go#L75-L80

クエリ実行時間200msを超えたらWarnレベル以上のログを残す設定になっています。

### ログ出力個所

https://github.com/go-gorm/gorm/blob/f482f25c714b67562af1d487a669d80a527963b3/logger/logger.go#L155-L185

デフォルトロガーで実装されたTrace関数内で閾値を超えたクエリを標準出力に出しています。
この時、Trace関数の引数で渡されている`fc`経由で実行されたSQL全文が渡されており、`SQLがそのまま標準出力に出てしまいます。`

また、エラー発生時にも同様であり標準出力に意図せずSQLが出力されてしまうこともあります。

## SQLがログに出てしまうことについて

会社によってはSQLそのものがログに出てしまうことはセキュリティ要件に抵触してしまうこともあるかと思います。

SQLなので、SELECTする際のWHERE句に秘匿情報が含まれていることもあるかもしれませんし、場合によってはINSERT/UPDATE時に個人情報を暗号化した文字やハッシュ化した文字も含まれるかもしれません。

また、デフォルト設定で一部条件を満たした場合にのみ出力されていることからも、テスト環境で動作確認していた時には開発者が気づいていないこともありそうです。

```go
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
```

上記のようなデフォルト設定で利用しているとロガーの存在にすら気づいていないこともありそうですね。

## 対処方法

SQLをそのままログ出力したくない場合、下記2点の対処方法があります。

### ログ出力を無効にする

シンプルな対処はこちらです。

https://github.com/go-gorm/gorm/blob/f482f25c714b67562af1d487a669d80a527963b3/logger/logger.go#L156-L158

ログレベルを`Silent`にするとTrace関数から即リターンするようになっています。

先ほどのデフォルト設定の初期化でConfigに以下のようにパラメーターを渡すことでログレベルを`Silent`にできます。

```go
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{Logger: logger.Default.LogMode(logger.Silent)})
```

### ロガーを自前で実装する

https://gorm.io/ja_JP/docs/logger.html#Logger%E3%81%AE%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA

にもあるように、上記interfaceを実装した構造体を自前で用意して、初期化時のConfigに渡すことで実現できます。

## まとめ

- GORMのデフォルトロガーは条件を満たすとSQLを標準出力に出力してしまう
- 避けたい場合はログ出力を無効設定にしてデフォルトロガーを使うか、デフォルトロガー相当の構造体を自前で実装する必要がある

意図せず変なログが残っているのって怖いですよね・・・

GORMが悪いわけではないのですが、ライブラリを利用する場合はどんな設定があって、デフォルトだとどうなっているのか？はちゃんと事前に確認しないといけないなと改めて思いました！

最後まで読んでいただきありがとうございました！

また次の記事でお会いしましょう。
なぜＰＭはいつも不足するのか　－社員育成の記号接地問題－

# はじめに

IT企業で人を育成していると、PMがなかなか育たないという課題に行き着く。
 
「あの人はコーディングがとても速いんだ」とか「あの人はすごく抜け漏れのない仕様をかけるね」という評価をされながらも「ちょっと管理は任せづらいんだよね」という評価を上からされている人は少なくない。

「なんかスケジュール感がないんだよね」とか「なんか責任感がないんだよね」とか「なんか安心して管理を任せられないんだよね」という言葉がよく悩みとして聞こえてくる。
 
ここには、教育業界における「記号接地問題」がある。


# 記号接地問題とは？

記号接地問題というのは、子供にとって、学校で教えることが記号になってしまっていて、自分の生活にくっついていない（つまり本人にとって地に足の接していない状態になってしまっている）という問題である。
その結果、「学校の授業がなかなか頭に残らない」「一夜漬けだけしてしまって、本人の糧にならない」ということが起きている。
 
例えば、歴史の授業で記号接地問題を考えてみよう。

「第二次世界大戦の話」というのは、子供の心にも非常に残りやすい。
凄惨な写真もたくさん残っているし、日本には広島の原爆ドームという第二次世界大戦の凄惨さの象徴的な世界遺産もある。なので「戦争が怖い」とか「核爆弾は非常に危険なものだ」というような印象は子供にも伝わりやすい。
 
一方、「第二次世界大戦に参戦した話」というのは、子供に教えるのは難しい。
「なぜ日本は参戦したのか」「なぜ日本は参戦を止められなかったのか」という話を、子供に理解させるのは非常に難しい。 会社員的な表現をするなら、「参戦するか、参戦しないかは、各部署によって意見が異なり、日本という企業においては、一番その時幅を利かせていた部署が参戦を希望したために参戦をしてしまった」という話で会社員にはある程度伝わるのだが、「人それぞれの利害があって思いの違いがあって、意見を通せる人が通せちゃう時があるんんだよ」ということを齢15程度の学生生活の経験に結びつけること（接地させること）は本当に難しい。
 
これが学校教育における記号接地問題であるが、会社員の育成においても記号接地問題が起きている。それがIT業界におけるＰＭ育成である。


# ＰＭ育成はなぜ難しいのか？

私自身、今会社で課長職に当たるものをやっているが、メンバーを育成していると「ＰＭが何をやってるのか、あまりよく分かりない」という声をよく聞く。
 
バルテスは、テストの会社なので、おおよそのプロジェクトは「テスト実施者・テスト設計者・ＰＭ」という役割に分かれているが、テスト実施者とテスト設計者の仕事は非常に分かりやすい。
ＰＭをやったことがない人に接地した表現をするなら、テスト実施者は「テストケースを一つずつやっていって、バグを見つけたら起票すること」が仕事で、テスト設計者は「テスト実施に使うテストケースを作ること」が仕事である。やることも明快だし、成果物も分かりやすい。
 
一方、PＭはどうだろうか？
もし、あなたが若手の社員に「ＰＭって何してるんですか？　管理って何をすればいいんですか？」っていうことを質問されたら、その人がイメージできるような回答は諳んじられるだろうか？
 
「スケジュール管理、リスク管理、いろんな人とのネゴシエーション」という表現はＰＭの仕事を正確にとらえているが、その表現で「うんうん。それが仕事だよね」と納得できるのはＰＭを経験したことがある人だけかもしれない。 
「結局1日8時間どう過ごしてるんですか？」「私の成果はこのテストケースを作ったことですが、ＰＭの成果がよく分からないので見せていただけませんでしょうか？」と訊かれたら、綺麗に答えられるだろうか？

私も前に「小谷さん(私の苗字）って1日8時間ずっとチャット見てるだけで、何やっているかよく分かんないんですよね」と言われたことがある。
ＰＭをやったことがある人なら「チャットにこそ、スケジュールやリスクや人とのネゴシエーションに関係することが飛び交っている」という感覚が分かるのだが、質問した人は私を責める口調で言ったのではなく、本当に分からない様子であった。
 
「ＰＭは何をやっていて、なぜ必要なのか」をＰＭをやったことがない人の仕事生活に紐づけて説明することが難しい、これがIT業界におけるＰＭ育成の記号接地問題である。


# おわりに 

もしあなたの会社がPＭ不足に困っているならば、ただ正確に正しい表現で「PＭの仕事というのは、スケジュール管理・リスク管理・人とのネゴシエーションだ」と発信するのはあまりＰＭ不足改善に寄与しないかもしれない。
それよりもＰＭをやったことない人に伝わる表現で「ＰＭというのは、皆さんに関係するところではこういう仕事をしています。例えばこういう時に頑張っているのがPＭです」と発信する方が、ＰＭをやったことない人にとってのＰＭの解像度が上がって、記号ではなく接地した役職になるかもしれない。