OmniAICreator/Qiita-1.07M huggingface dataset:
[Bevy] 画面サイズを取得して、利用する

自分向けのTipsです。

Rust製ゲームエンジンBevyをさわり始めたので、やりたいことを実現するためのコードをメモしていきたいと思います。

全体像は本記事の最後に記載しています。

# リソース

ウィンドウサイズをアプリケーション全体で共有するため、リソースを準備します。

```rust
#[derive(Resource)]
struct WindowSize {
    width: f32,
    height: f32,
}
```
main関数でリソースを追加しておきます。
```rust
app.insert_resource(WindowSize {
    width: 0.0,
    height: 0.0,
});
```

# ウィンドウリサイズのイベント

```rust
use bevy::window::WindowResized;
```
上記を追加しておいて、以下を`Update`のシステムへ加えます。
ウィンドウリサイズのイベントを処理して、取得した横幅縦幅をリソースのWindowSizeへ保存します。

```rust
fn window_resize_system(
    mut window_size: ResMut<WindowSize>,
    mut resize_reader: EventReader<WindowResized>,
) {
    for e in resize_reader.read() {
        window_size.width = e.width;
        window_size.height = e.height;
    }
}
```

# テキスト表示

テキスト表示は`Startup`処理でエンティティ？を準備します。

ウィンドウ右下に文字が表示される設定です。

```rust
commands.spawn((
    Text::new("".to_string()),
    Node {
        position_type: PositionType::Absolute,
        bottom: Val::Px(5.0),
        right: Val::Px(5.0),
        ..default()
    },
    TestText,
));
```
最後に表示しているテキストを書き換える処理を`Update`のシステムへ加えます。
```rust
fn window_draw(
    window_size: Res<WindowSize>,
    mut query: Query<&mut Text>>,
) {
    for mut text in query.iter_mut() {
        **text = format!(
            "Window size: {} x {}",
            window_size.width, window_size.height
        );
    }
}
```

以上をあわせると以下のようなウィンドウが表示されます。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3821654/a5d007d9-da40-52c4-858e-d58add1c894f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3821654/bb1a94be-64c9-572b-c944-9444e92e51d8.png)

# 終わりに

まだ仕組みがわかっていないため、ふわふわとコードを書いています。

でも、見た目にわかりやすいものをつくるのは楽しいなと思いました。

それでは、ここまで読んでいただきありがとうございました。


以下は付録コードです。

# 付録：全体像
```rust
use bevy::prelude::*;
use bevy::window::WindowResized;

#[derive(Resource)]
struct WindowSize {
    width: f32,
    height: f32,
}

fn main() {
    let mut app = App::new();
    app.add_plugins(DefaultPlugins);
    app.insert_resource(WindowSize {
        width: 0.0,
        height: 0.0,
    });
    app.add_systems(Startup, setup);
    app.add_systems(Update, (window_resize_system, window_draw));
    app.run();
}

fn setup(
    mut commands: Commands,
) {
    commands.spawn(Camera2d);

    commands.spawn((
        Text::new("".to_string()),
        Node {
            position_type: PositionType::Absolute,
            bottom: Val::Px(5.0),
            right: Val::Px(5.0),
            ..default()
        },
    ));
}

fn window_resize_system(
    mut window_size: ResMut<WindowSize>,
    mut resize_reader: EventReader<WindowResized>,
) {
    for e in resize_reader.read() {
        window_size.width = e.width;
        window_size.height = e.height;
    }
}

fn window_draw(
    window_size: Res<WindowSize>,
    mut query: Query<&mut Text>>,
) {
    for mut text in query.iter_mut() {
        **text = format!(
            "Window size: {} x {}",
            window_size.width, window_size.height
        );
    }
}
```
[個人開発]CICDとChakra UI V3を使用した学習記録アプリの完成

## はじめに
学習記録アプリにUI機能をつけた完成版が出来ました。

CICD機能やChakra UI V3を使ってUIを付けたりと色々と実務に即した挑戦ができたと思います。

今後の目標も踏まえて作成したアプリと内容をご紹介します。

前回の記事

https://qiita.com/shin-tech/items/1639ed81afecf1e4fa3d

## 作成したアプリ

![シン・学習記録アプリ.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3289947/5ce07864-2e13-4159-aebd-61343c460b95.gif)

本質的な機能は前回とほぼ同じですが、UIがついてモーダルから新規登録できたり、React Hook Formにより入力時のバリデーションも動的に表示されています。

シンプルなTODOアプリの機能を持った学習記録アプリです。

## 学習の振り返り
開発の流れとしては下記を実施しました。
* React+TypeScriptの開発環境をViteで用意
* Supabaseと連携し学習記録データをクラウドに保存
* React Hook Formを使用したフォーム作成
* Chakra UIでUIを追加したアプリ作成
* Fireabseを使用しデプロイ
* Jestでテスト作成

今回はChakra UIのV3を使ってUIをつけたのですが、Jestとの互換性の問題なのかビルドが通らなかったりして苦労しました。

JavaScriptならエラーにならないコードでもTypeScriptだと型エラーになったりと苦戦しましたが、すべての型エラーがなくなると堅牢なアプリを作成できている実感が湧きました。

テストコードの作成では、10個以上テストを作成しましたが途中でここのテストは共通化してまとめられるとか、userEventを使えば実際の操作をシミュレーションしてテストできるということを学ぶことが出来ました。

途中あまりの難しさ（特にテストコードの記述）にAIエディタのCursorの力も借りながらなんとか進めることが出来ました。

話はそれますが、個人的にはGitHub CopilotよりもCursorがUIの使いやすさの点で好みです。（機能自体は大きく変わらないようです）

AIとペアプログラミングしながらまずは動かしてみる。そして後からなぜこのコードは動くようになったのかを考えたり調べたりしました。

デプロイの際にCICDが動き、自身のPCやスマホからアプリが表示されたときはとても嬉しかったです。

## 今後の目標
毎日コードを書くという習慣を継続する。一つアプリが出来たらちょっと休みたいなという気持ちが湧くこともあるのですが、簡単なことでもいいから一歩前進する事が大事だと思っています。

今回のアプリ作成でUIをつけてみたのですが、もっとユーザー視点に立ったUIをつけられるセンスを磨いていけたらいいなと思いました。

エンジニアは壁に何度もぶち当たることで成長するという意外と体育会系な側面もあると思っています。

次のアプリ作成でも壁は沢山出てくると思いますが、成長の機会だと捉えて前向きに頑張りたいです。

## JISOUのメンバー募集中！
プログラミングコーチングJISOUでは、新たなメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか？
興味のある方は、ぜひホームページをのぞいてみてください！
▼▼▼

https://projisou.jp
Railsの公開メソッドについて

この記事は東京海洋大学NePPの Advent Calendar 2024の18日目です。

# はじめに
こんにちは！この記事は、私が実装中に、privateメソッド内にself.を書こうとして怒られた経験から、メソッドの公開レベルについて自分なりの理解をこの記事に記録するため書きました。

# メソッドの公開レベルってなんぞや
Rubyでは、メソッドの公開レベルは、クラスやモジュール内で定義したメソッドへのアクセスを制御するために使われます。この制御により、外部から意図しない操作を防ぎ、コードの安全性や可読性を高めることができます。
## 種類
### public（公開メソッド）

デフォルトの公開レベル。
外部から自由に呼び出し可能なメソッドを定義します。
APIの一部として利用者に公開したいメソッドを定義するのに使用されます。
```
class User
  def greet
    "Hello!"
  end
end

user = User.new
puts user.greet  # => "Hello!"
```

### protected（保護されたメソッド）

同じクラスまたはサブクラスのインスタンスからのみ呼び出せるメソッドを定義します。
外部から直接呼び出すことはできません。
```
class User
  def initialize(name)
    @name = name
  end

  def compare_name(other_user)
    name == other_user.name
  end

  protected

  def name
    @name
  end
end

user1 = User.new("Kaiyo")
user2 = User.new("Kaiyo")
puts user1.compare_name(user2)  # => true
puts user1.name  # エラー: protected method `name` called
```
name メソッドは、protected によって外部から直接呼び出せません。
しかし、compare_name メソッド内で other_user.name として、同じクラス内の別のオブジェクトのメソッドを呼び出すことができています。

### private（非公開メソッド）

同じインスタンスのコンテキスト内でのみ呼び出せるメソッドを定義します。
レシーバ（self）を明示して呼び出すことはできません。
```
class User
  def initialize(name)
    @name = name
  end

  def greet
    "Hello, #{formatted_name}!"
  end

  private

  def formatted_name
    @name.capitalize
  end
end

user = User.new("alice")
puts user.greet  # => "Hello, Alice!"
puts user.formatted_name  # エラー: private method `formatted_name` called
```
外部や他のオブジェクトから呼び出すことはできません。
クラスの内部だけで使い、外部から「formatted_name」を直接チェックされることを防ぎます。




## 公開レベルについてのまとめ
public: 外部から呼び出せるメソッド（クラスのインターフェース）。
protected: 同じクラスやサブクラス内で共有するメソッド。
private: 完全に内部専用のメソッド。
公開レベルを適切に使うことで、コードの可読性、保守性、安全性を向上させることができます。

# なぜ怒られたのか
以上の点を踏まえれば、self. を明示する場合は「外部からの呼び出し」とみなされるため、エラーになります。まあ、ちゃんと知っていれば当たり前と言えば当たり前ですよね。
### 補足
なぜこのルールがあるのか？
カプセル化を強化するため

private メソッドは「クラス内部でのみ使われるもの」という意図を持っています。
self. を使うと外部からアクセス可能な public や protected メソッドと区別がつきにくくなります。
意図を明確にするため、self. を使わないことで、「これはクラス内でのみ使用される内部メソッド」という意図が明確になります。
# どうしたか

```
team.update(b)
      [name(a,b)]
private
def self.name(a,b)
```
元々はこんな感じのコードでprivate内にself.nameを書いて非公開にしたいはずなのに、外部からアクセス可能にしていて怒られています。
じゃあ、nameメソッドは外部には非公開（private）で、クラス内部でのみ使用できるクラスメソッドとして定義するにはどうすればいいのか、
## 結論
注意：一部コードを隠しているので、このコードだけだと動きません。あくまで一部を転載、改修。
```

team.update(b)
      [name(a,b)]
class << self
  private

  def name(a,b)
    # メソッドの処理省略
  end
end
```
これにより
***カプセル化（情報隠蔽）***
name はクラス内部専用のロジックを持つメソッドです。外部からアクセスさせないことで、クラスの使い方を明確にできます。
***意図の明確化***

「外部から使わない」ことを明示することで、コードの読み手に「このメソッドは内部ロジック専用」という意図を伝えられます。
***安全性***

外部から呼び出されることで起こる予期せぬ不具合や誤用を防げます。

外部から使わないのに、publicにしてクラスメソッドとして使用していると、「外部から呼び出す意図があるのか。」という意図をコードレビューの時に指摘させてもらいました。

# 終わり
公開メソッドの意図として、セキュリティ的な意味合いもありますが、コードの読み手に自身の意図を告げることができると感じました。
Core Smart Contracts

[Previous << Working With Parent Accounts](https://qiita.com/flowcadence/items/e9a3fc97d60bb007b878)
[Next >> Fungible Token](https://qiita.com/flowcadence/items/2c2451d0b6bd889f407d)

https://qiita.com/flowcadence/items/3073d69c6e9895e68b5a#flow-developers

Flowは、Flowのプロトコルの主要部分を定義する一連のコアコントラクトに依存しています。

これらのコアコントラクトは、以下の事項を規定します:
* Standard fungible token behavior. ([FungibleToken, FungibleTokenMetadataViews, FungibleTokenSwitchboard, Burner](https://qiita.com/flowcadence/items/2c2451d0b6bd889f407d))
* Flow Protocol Token. ([FlowToken](https://qiita.com/flowcadence/items/41308221443f207a7921))
* Flow Service Account. ([ServiceAccount, NodeVersionBeacon, RandomBeaconHistory](https://qiita.com/flowcadence/items/c11bd0dfea9691961946))
* Account, transaction and storage fee payments. ([FlowFees and FlowStorageFees](https://qiita.com/flowcadence/items/0f41148ca231a09d1efb))
* Staking and delegation ([FlowIDTableStaking](https://qiita.com/flowcadence/items/1d432b038762c7bf8063))
* Epochs ([FlowEpoch, FlowClusterQC, FlowDKG](https://qiita.com/flowcadence/items/f5e22a34d79769cb5c5d))

コアプロトコルには含まれていないものの、Flowの開発者にとっては重要なコントラクトが他にもあります:
* Standard Non-Fungible Token Behavior. ([NonFungibleToken](https://qiita.com/flowcadence/items/152a2fb0c9acb1a6769c))
* NFT Metadata Standard. ([MetadataViews, ViewResolver](https://qiita.com/flowcadence/items/191e2e765391e636a89c))
* Staking Collection. ([StakingCollection](https://qiita.com/flowcadence/items/89d155bb9a803da06b45))
* NFT Storefronts. ([NFTStorefront](https://qiita.com/flowcadence/items/93a05e653883a93b617a))
* Account linking and Hybrid Custody. ([AccountLinking](https://qiita.com/flowcadence/items/59158ab2b64af5844082))
* EVM interfacing contract. ([EVM](https://qiita.com/flowcadence/items/84d2ab27cfc5080c92e6))

*Last updated on **Dec 11, 2024** by **Chase Fleming***

翻訳元

https://developers.flow.com/build/core-contracts

***


<b>[Previous << Working With Parent Accounts](https://qiita.com/flowcadence/items/e9a3fc97d60bb007b878)
</b>

[Flow blockchain / Cadence version1.0ドキュメント](https://qiita.com/flowcadence/items/3073d69c6e9895e68b5a) (Core Smart Contracts)

<b>[Next >> Fungible Token](https://qiita.com/flowcadence/items/2c2451d0b6bd889f407d)</b>
米田の補題 #12 圏の補足　対象の個数　射の個数

# 米田の補題は、圏論でもっとも重要な定理です（繰り返し）
圏論は、数学の基礎理論です。いままで、[万物の理論](https://amzn.to/3ZLmCJH)
といわれていましたが、[数理科学 11月号](https://amzn.to/4iz6NgM)では、なんと　<font color="Red">万物・万事・万人</font>のための数学理論とまでいわれるようになりました
このAdventCalendar は、体験的に圏論の最も重要な定理である米田の補題を体験的に理解してもらうためにかいています

参考にしているのは、[圏論の道案内](https://amzn.to/4iH2Rus)です

# 対象の個数　射の個数
無限に組み合わせがありますが、覚えておくと便利なのを紹介します。

### 対象がひとつで射の個数がたくさん（無限）にあるのが、数学的には重要です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48387/826601c1-bb6f-6b9c-ef18-25ef74bb85e3.png)

なぜそうかは、数学的に関手、自然変換とすすむうちにそうだと思えるのですが、ここでは、数学に重要だで押し切ります。米田の補題川柳 **関係は内容よりも重要だ** 的に理解してもらいます。
</br>
### 次は、射は対象の間には、一つかふたつしかない簡単な例でいきます。
- 普段非常によくつかう対象が２つの事例です。もちろん、これだけでは、圏の体裁はもっていません。以下の事例もそうです。
逆方向の射がある事例もくわえました
```mermaid
graph LR;
a[域]-.->|射|b[余域]
a1[域or余域]-.->|f|b1[余域]
b1[域 or 余域]-.->|g|a1[域 or 余域]
```
- 対象が３つの事例です。いくつかあげます。場合が増えるので、対象間の射はひとつにしています
```mermaid
graph LR;
a[a]-.->|ｆ|b[b]-.->|g|c[c]
a1[a]-.->|ｆ|b1[b]
a1[a]-.->|g|c1[c]
a2[a]-.->|ｆ|b2[b]
a2[a]-.->|g|c2[c]
b2[b]-.->|h|c2[c]
```
- 対象が４つの事例です。組み合わせはさらにふえます。場合が増えるので、射は３つにしています
```mermaid
graph LR;
a[a]-.->|ｆ|b[b]-.->|g|c[c].->|h|d[d]
a1[a]-.->|ｆ|b1[b]
a1[a]-.->|g|c1[c]
a1[a]-.->|h|d1[d]
a2[a]-.->|ｆ|b2[b]
a2[a]-.->|g|c2[c]
c2[c]-.->|h|d2[d]
```
普段の企画会議では、対象ふたつ射がひとつが主なので、結合則まで意識した射３つの事例は、ゆっくり使いましょう

**米田の補題川柳　矢印は３つまでまずきわめよう**
圏の体裁をとらないと関手、自然変換にはすすめません。米田の補題は夢のまた夢です。だから、１日目に、米田の補題川柳を、「関係は内容よりも重要だ」として紹介したのです。でも、少しは数学的にも頑張って解説を試みます
nablaを用いたgradient・divergence・rotationの定義

## 演算子の定義
### nablaの定義
演算子$\nabla$は下記のように定義されます。

```math
\nabla = \frac{\partial}{\partial x} \mathbf{i} + \frac{\partial}{\partial y} \mathbf{j} + \frac{\partial}{\partial z} \mathbf{k}
```


### laplacianの定義
ラプラシアン演算子$\nabla \cdot \nabla$は下記のように定義されます。

```math
\nabla \cdot \nabla = \frac{\partial^{2}}{\partial x^{2}} + \frac{\partial^{2}}{\partial y^{2}} + \frac{\partial^{2}}{\partial z^{2}}
```



## grad・div・rotの定義
### gradの定義
多次元スカラー関数$\phi (x,y,z)$の勾配$\mathrm{grad} \phi$は下記のように定義されます。

```math
\mathrm{grad} \, \phi = \nabla \phi = \frac{\partial \phi}{\partial x} \mathbf{i} + \frac{\partial \phi}{\partial y} \mathbf{j} + \frac{\partial \phi}{\partial z} \mathbf{k}
```


### divの定義
空間内のある領域に含まれる全ての点における関数を$V(x,y,z)$のように定義すると、このとき$V$のダイバージェンス(divergence)である$\mathrm{div} V$は下記のように定義されます。

```math
\begin{align}
\mathrm{div} \, V &= \nabla \cdot V = \left( \frac{\partial}{\partial x} \mathbf{i} + \frac{\partial}{\partial y} \mathbf{j} + \frac{\partial}{\partial z} \mathbf{k} \right) \cdot (V_{1} \mathbf{i} + V_{2} \mathbf{j} + V_{3} \mathbf{k}) \\
  &= \frac{\partial V_{1}}{\partial x} \mathbf{i} + \frac{\partial V_{2}}{\partial y} \mathbf{j} + \frac{\partial V_{3}}{\partial z} \mathbf{k}
\end{align}
```


### rotの定義
空間内のある領域に含まれる全ての点における関数を$V(x,y,z)$のように定義すると、このとき$V$の回転(rotation)である$\mathrm{rot} V$は下記のように定義されます。

```math
\begin{align}
\mathrm{rot} \, V &= \nabla \times V = \left( \frac{\partial}{\partial x} \mathbf{i} + \frac{\partial}{\partial y} \mathbf{j} + \frac{\partial}{\partial z} \mathbf{k} \right) \times (V_{1} \mathbf{i} + V_{2} \mathbf{j} + V_{3} \mathbf{k}) \\
  &= \left| \begin{array}{ccc} \mathbf{i} & \mathbf{j} & \mathbf{k} \\ \displaystyle \frac{\partial}{\partial x} & \displaystyle \frac{\partial}{\partial y} & \displaystyle \frac{\partial}{\partial z} \\ V_{1} & V_{2} & V_{3} \end{array} \right| \\
  &= \mathbf{i} \left| \begin{array}{cc} \displaystyle \frac{\partial}{\partial y} & \displaystyle \frac{\partial}{\partial z} \\ V_{2} & V_{3} \end{array} \right| + \mathbf{j} \left| \begin{array}{cc} \displaystyle \frac{\partial}{\partial x} & \displaystyle \frac{\partial}{\partial z} \\ V_{1} & V_{3} \end{array} \right| + \mathbf{k} \left| \begin{array}{cc} \displaystyle \frac{\partial}{\partial x} & \displaystyle \frac{\partial}{\partial y} \\ V_{1} & V_{2} \end{array} \right| \\
  &= \mathbf{i} \left( \frac{\partial V_3}{\partial y} - \frac{\partial V_2}{\partial z} \right) - \mathbf{j} \left( \frac{\partial V_3}{\partial x} - \frac{\partial V_1}{\partial z} \right) +  \mathbf{k} \left( \frac{\partial V_2}{\partial x} - \frac{\partial V_1}{\partial y} \right) \\
  &= \mathbf{i} \left( \frac{\partial V_3}{\partial y} - \frac{\partial V_2}{\partial z} \right) + \mathbf{j} \left( \frac{\partial V_1}{\partial z} - \frac{\partial V_3}{\partial x} \right) +  \mathbf{k} \left( \frac{\partial V_2}{\partial x} - \frac{\partial V_1}{\partial y} \right)
\end{align}
```
ArgoCDの複数クラスタ運用で本番環境と開発環境を便利に分ける


みなさんこんにちは。
今回は、ArgoCDに2クラスタ登録して本番環境と開発環境を一つの画面で操作する話です。

## ArgoCDとは

ArgoCDとは、K8sにGitHubから自動的にデプロイしてくれる、いわゆるGitOpsです。

https://argoproj.github.io/cd/

## クラスタを追加するとは？

クラスタを追加するというのは具体的にどういうことか。

みなさん、デプロイする時このような画面から設定しますよね？

![argocd-dest-setting.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3342262/4bb8a51d-d722-4876-3492-4f2a3cfcd423.png)

ここです。
この、クラスタという部分から外部のクラスタを選択できるようにするのです。
これにより、

- 本番環境と同じリポを使いたい
- 設定するのだるい

などの問題を解消することができます。

## コンテキストを準備する

まず、kubeconfigファイルに追加する環境のcontextがなければなりません。
私の環境はmicrok8sなので、とりあえず、とってきます。

```sh
microk8s config
```

こうすると、context一覧が出てきます。
今回は権限設定なんぞはめんどくさいので、adminに関連するところをコピペして、追加元から操作できるようにします。

## argocd CLIを使って追加する

さて、ここからが本題です。
ArgoCD CLIをまだインストールしていない方は、以下のリンクを参照してください。

https://argo-cd.readthedocs.io/en/stable/cli_installation/

一応コンテキスト名を確認します。

```sh
kubectl config get-contexts

## 例)
## CURRENT   NAME                                         CLUSTER                        AUTHINFO                             NAMESPACE
## *         default/api-cluster-staging:6443/admin       api-cluster-staging:6443       admin/api-cluster-staging:6443       default
##           default/api-cluster-production:6443/admin    api-cluster-production:6443    admin/api-cluster-production:6443    default
```

お次に、argocd CLIで、以下のコマンドを打ち込みます。

```sh
argocd cluster add default/api-cluster-production:6443/admin
```

これで何やら聞かれるかと思いますが、ArgoCDの動作のために、Admin権限を持ったサービスアカウントの作成をしても良いか？ということなので、yを入力します。
このコマンドで作成されるのは、ServiceAccountとClusterRole、ClusterRoleBindingです。

## 確認してみる

ArgoCDのWebダッシュボードを見てみましょう。
名前などは違うと思いますが、このようになっているはずです。

![argocd-cluster-list.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3342262/5635ce8a-1c28-ca0e-c851-39039b8b845e.png)

これで、Applicationの作成時も、新しい方のクラスタを使用できます。
お疲れ様でした！！
@cosmeトップ画面リプレースにおける負荷試験と速度改善事例

## この記事は?
[@cosme](https://www.cosme.net/)のPC版トップでは今年6月に全ての画面上のUIとAPIに関して刷新的なリプレースが行われ、
それに伴ってバックエンドはNode.jsに統合されました。
10年越しのリプレースとなり、大変骨が折れる作業でしたが、なんとか大きなバグもなくリリースすることができました。

現在、[@cosme](https://www.cosme.net/)のMonthly Active Userは1700万を超え、この負荷はNode.jsやmemcached、kafka、ロードバランサーなどの諸技術を用いることによって捌くことができています。この記事ではリプレースに伴って行った負荷試験と速度改善、および[@cosme](https://www.cosme.net/)メディアが負荷対策と速度改善に用いている諸技術を皆さんと振り返りたいと思います。

負荷試験や速度改善に興味のある方はぜひご覧ください！

## 負荷に関する基本的な用語
基本的な用語をおさらいしておきましょう。
**ここは復習パートなのでわかる方はスキップしてください。** 
### ・システムの性能評価の基本

#### レイテンシー：処理にかかる時間
リクエストを送ってからレスポンスを受け取るまでの時間
例：APIリクエストが200msで返ってくる
ユーザー体感に直結する指標
p50, p95, p99などのパーセンタイル値で表現
#### スループット：単位時間あたりの処理量
単位時間あたりの処理量
例：1秒あたり100リクエスト処理（RPS: Requests Per Second）
システムの処理能力を示す指標
TPS (Transactions Per Second) としても表現
#### ワークロード：システムにかける負荷の内容
例：「1秒間に1000ユーザーがログイン」「商品検索が1日10万回」など
実際に起こる負荷を想定したもの

#### Error Rate（エラー率）：
ER = (失敗したリクエスト数 / 全リクエスト数) × 100%

### ・負荷試験における主な設定項目

#### スレッド数（同時ユーザー数）
10スレッド = 10人が同時アクセス
各スレッドは1人のユーザーを模擬

#### Ramp-Up期間（ユーザーの増え方）

例：スレッド数10、Ramp-Up 100秒の場合
- 開始0秒で1人目がリクエスト開始
- 開始10秒で2人目がリクエスト開始
- 開始20秒で3人目がリクエスト開始
...と10秒ごとに100秒までユーザーが1人ずつ増加

#### ループ回数（繰り返し回数）

各ユーザーが同じ操作を何回繰り返すか
前の操作が終わったら即座に次を実行

## どうやって負荷を測定するのか？
@cosmeのシステムでは**NewRelic**を活用することで、
日々負荷を測定することができています。

ところで、今回のリプレースに伴う負荷テストとして、jmeterを使って通常時の負荷から**ピーク時をはるかに超える負荷** を掛けて行っています。

通常時のパフォーマンスは日々測定しておく傍ら、負荷テストでは想定以上の負荷をかけることによって、どこまでの負荷を耐えられるシステムであるか？がわかり、通常の状態では露出しなかったシステムパフォーマンスのボトルネックが露呈してくるため、そこをNewRelicなどの分析ツールと合わせて見ていくことによって、改善点を特定することが可能です。

## どうやってパフォーマンスを改善するのか？
システムリプレースに伴って@cosmeのパフォーマンス改善が行われた結果として、**中央応答速度を最大30%程度ほど向上**させることができました。


![スクリーンショット 2024-09-13 19.20.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3470696/11e5d771-e3ee-5fff-2374-7705ce0fc727.png)

今回のリプレースに伴っては、新たにNode.jsを採用したため**Promise.all** によって非同期処理を並列に行ったことが速度の改善に役立ちました。

また、JMeterで負荷をかけたときのそれぞれのAPIのパフォーマンスを分析してみて、@cosmeトップ画面で実行されるSQLに関してもボトルネック分析を行い、インデックス等の全体的な見直しを行いました。

このように、**数値を測定しつつ、ボトルネックを特定し、その部分の改善をしていくという流れがパフォーマンス改善の基本**になってきます。
## @cosmeメディアの負荷戦略
@cosmeのバックエンドは前述の通り、Node.jsのI/Oバウンドに強い特性を活かして高速に大量トラフィックを裁くことができています。
@cosmeメディアを支える技術はNode.jsと周辺技術から成ります。

特筆すべき負荷戦略には次の3つがあります。

1つ目はAWS ASGの使用による局所的な負荷対策です。
各サービスへの局所的な負荷に対しては、そのモジュール専用のASGを用意することで負荷に備えることができます。


2つ目は、memcachedをキャッシュサーバーとして使うことでの負荷対策です。memcachedを使ってDBへの負荷を抑えています。

3つ目はkafkaによるさらなる負荷の対策です。例えば、会員情報を返すAPIのように負荷が甚大だが変更に伴って即座な情報反映が必要な箇所はKVSで負荷を抑えつつ、情報反映があった時はkafkaが情報を受け取ってKVSのキャッシュを破棄更新することで、会員情報APIへの参照を最低限に抑えつつ、リアルタイムな情報を高速に返すことが可能です。

詳しくは著者による以下のLTをご覧ください。

[大規模な美容メディアのフロントエンドを支えるサーバー技術](https://www.youtube.com/watch?v=z8eI0bgzPTM
)



## 終わりに
メリークリスマス。皆さんが幸せなクリスマスを過ごされますことを！
React supabaseの削除後のdataを表示する方法について

## はじめに

supabaseのデータをアプリから削除する実装をする際、削除後のデータを表示する方法でつまずいたため内容を共有します。

<br>

「修正前」
以下のように記述していました。
```Todo.jsx
const onClickDelete = async (id) => { // idの中にrecord.idが入っている。ここの名称は何でもよい
    const deleteData = await deleteTodo(id);
    setRecords(deleteData); // ← 原因の場所
  };

<button className="delete-button" onClick={() => onClickDelete(record.id)}>
  削除
</button>
```
deleteTodo関数はSupabaseから指定されたidのデータを削除してその結果（削除されたデータ）を返しますが、返ってくるdataは削除されたレコードのみ。
setRecords(deleteData)だと、削除前のrecordsデータから該当のIDだけを取り除く処理が行われず、データ全体が上書きされてしまう。よって、削除しようとした該当データだけ残り、その他が消えてしまう症状が発生していました。

<br>

「修正後」
```Todo.jsx
const onClickDelete = async (id) => {
    const deleteData = await deleteTodo(id);
    setRecords((prevRecords) => prevRecords.filter((records)=> records.id !== id))
  };
```
filterを使ってidが一致しないレコードだけを残す新しい配列を作成する。
ReactでuseStateを使う場合は、状態の更新を行うために「直前の状態」を関数形式で参照しつつ、新しい状態を返す必要があるようです。
filterメソッドは条件に一致する要素だけを残すためのメソッドですが、recordsという関数や条件が指定されていない引数を渡していると、エラーになります。
なお、prevRecordsはReactのuseStateのsetState関数内で使われる引数であり、直前の状態（state）を自動的に参照するためのものです。
ReactのuseStateのsetState関数に関数を渡すと、その関数の引数には「直前のstate」が渡されます。
なお、Reactが自動的にその引数に直前の状態を代入してくれるため、prevRecordsという名前をあらかじめ定義する必要はないみたいです。
　以上で意図した挙動になってくれました。
 
<br>

「参考」
```Todo.jsx
const onClickDelete = async (recordId) => {
    const deleteData = await deleteTodo(recordId);
    setRecords((prevRecords) => prevRecords.filter((records)=> records.id !== recordId))
   
  };
```
上記のようにidを別の名称にしても良い。onClickDelete(record.id)からrecord.idが渡ってきているので名称を変更しても中身は同じです。

# 参考資料

https://ja.react.dev/reference/react/useState

# JISOUのメンバー募集中！
プログラミングコーチングJISOUでは、新たなメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか？
興味のある方は、ぜひホームページをのぞいてみてくださ！
▼▼▼

https://projisou.jp
海外でびっくりされるPLATEAU

:::note info
この記事は、[3D都市モデル Project PLATEAU Advent Calendar 2024](https://qiita.com/advent-calendar/2024/plateau)の24日目の記事です。
:::
こんにちは。元PLATEAU担当です。（担当を離れてもPLATEAU大好き！）
10月11月のPLATEAUアカデミー、参加された方も事務局の皆様も大変お疲れ様でした。
本日はクリスマスイブなので、少し緩やかな記事にお付き合いいただければと思います。

## 海外からも注目され始めたPLATEAU
Prpject PLATEAUの担当をしていた今年の７月までの間、海外の会議でプレゼンテーションを行う機会が複数回ありました。
どこの国でも大きな注目をいただいたのですが、よく質問された点や驚かれた点があるので、いくつかポイントをご紹介したいと思います。

### データ作成が自治体主体なのが凄い！
PLATEAUのデータは基本的に自治体が作成主体であり、ここから測量会社に委託して作られています。
ひとつの主体が作成しているわけではないのになぜここまで規格が揃っているのか（皆様は既にご存じの標準製品仕様書シリーズがしっかり整備されているから）、そしてわずか４年で200都市という広がりも毎度かなりびっくりされます。
PLATEAUでは自治体向けの補助制度を用意していますが、そういったやり方は海外では意外とメジャーでないのかもしれません。
個人的には、かなりの手作業を要するPLATEAUデータ作成において、決まったルール通りにぴしっと仕上がるのは日本人の強みかもなーとも思っています。

### 既に動くアプリケーションがいくつもある！
デジタルツインはまだまだ各国が、どんな使い方があるの？と試行錯誤を繰り返している状況です。
実際に会議でのプレゼンテーションでも、構想だけの発表や、水害対策等の災害分野に限定されたユースケースの発表がほとんどです。
一方、Project PLATEAUでは、これまでとんでもない数の[ユースケース](https://www.mlit.go.jp/plateau/use-case/)開発に取り組んできました。
こんな風に使えるよーというアイディアを、様々な分野で、そして実際に動く状態でいくつも提示できるのは、海外で感じる特に大きな強みです。
ユースケース側の技術もこのプロジェクトと一緒に育ってきていることを実感します。
今年11月に開催された[Smart City Expo World Congress 2024](https://twitter.com/ProjectPlateau/status/1854463817117561326)でも、実際にまちづくりで活用されているツールを触れる形で展示し、大いに盛り上がったようです！


### データの使い方解説が充実しすぎている！
海外の多くの国ではデータを公開して終わり！が多く、活用サポートやユーザーからのフィードバックを一生懸命集めているところはほとんどありません。
Project PLATEAUでは、ラーニング用に様々なバラエティの[記事](https://www.mlit.go.jp/plateau/learning/)が公開されています。
しかも絶えず更新を続けており、最近では今年のPLATEAU AWARDのグランプリ作品から、PhthonでPLATEAUを活用する方法の[解説記事](https://www.mlit.go.jp/plateau/learning/tpc28-1/)やPLATEAUを使った[映像作品](https://www.youtube.com/watch?v=Xim2_tARjhU)の作り方のハンズオン動画が公開されています。
是非様々な分野で、PLATEAUデータを活用してみてください～

## おわりに
 担当を離れても、どこでどんな仕事をしていても、ずっと緩く関わっていられるのがPLATEAUオープンコミュニティの良い所だと思っています。
 今回PLATEAUアカデミーに参加された皆さんも、是非長くPLATEAUとお付き合いいただければと思います。
 データを活用する観点でのイベントもたくさんありますので、ご関心あるものに参加してみてください。
では、良いクリスマスを！
 
（ところで、TVアニメ株式会社マジルミエのOPがPLATEAUっぽいなーとずっと気になっています。真相はいかに、、)
テスト作成に悩む人へ送るテストの心得【テストは彫刻】

## はじめに
本記事は、テスト作成における技法の話ではなく、
それら以前の根本的な理念や心得の話です。
要するに、テストの作成や設計、そのための技法・技術を
知る前に知っておいた方が良いであろう話です。

「テスト作成は底知れない、難しいものだ」と思ってる方は、
テスト作成に対しての心理的ハードルが下がってくれると嬉しいです。

## テストとは「０から創る」ではなく「１００から削る」もの
テスト作成における根幹の話からです。

### テストを「０から創る」のは難しい
勝手な想像ですが、多くの人はテスト作成を
「何もないところから創り上げる」と考えていると想像しています。

例えるなら、広大な森から必要な木々を探して拾い上げて、家を創るような。
目の前にあるシステムから、必要な因子水準を探してきてExcel上に広げて、どう組み合わせようか悩んでいる。

それは非常に難しいです。
何故ならば、すべてはバラバラであり、
小さな一因子を相互に正しく組み上げなければなりません。
それも、実施したいテストに合わせて都度０から考えなければなりません。
そして、完成するまで全体像が見えず、
どこまで大きくなるか、大きくしてよいかの想像ができず、着地点を見失います。

### 「全数テストは不可能」
少し話は逸れますが「全数テストは不可能」という話を聞いたことはありますか？
これは「ソフトウェアテストの７原則」のうちの１つです。

その理由は細かいのを除くと、
+ すべての因子水準を掛け合わせるとケース数が膨大になり、莫大なコストがかかる
+ 技術的に難しい/不可能なケースが含まれる

の２点に概ね集約されます。

「じゃあその理由を払拭すればできるじゃないか」という話は一旦置いといて、
この「全数テストは不可能」は正しく言い直すと
「全数テストの作成は概ねできるが実施は不可能」です。

テスト設計や作成というものは、
「全数テストの実施は不可能だから、可能な数に絞る」という行為です。

話が見えてきたでしょうか？

### テストとは「１００から削る」もの
つまりテスト作成とは、
「森から木々を拾い集めて家を建てる」ような創作ではなく、
「大きな岩から余分な個所を削り取る」ような、彫刻的な創作です。

「どこまで大きくしよう/なっちゃうかな」ではありません。
そもそも全数テストという最大サイズが存在しており、
そこから小さくしていくことがテスト作成です。

+ 巨大な岩山（全数テスト）から、
石材をある程度の大きさに切り出す（全数テストの一部を切り出す）
+ 切り出してきた石材から不要な部分を削って彫刻を創る（テストを作る）

という大きく２つの手順があります。
それぞれについて引き続き話していきます。

## 「テストの目的」を忘れない

### 作り始めるとついつい忘れる「テストの目的」
「このテストの目的をはっきりしよう」ということはよく注意すると思います。
何を確認するのか、保証するのか、そういったことが決まらないとテスト作成は始まりません。

しかし、作り始めていると、本来のテスト目的を忘れてしまい、
「テストを作ること」が目的になる場合があります。
人はついつい忘れる生き物なのでやりがちですが、
これをすると、重要なものを忘れてしまったり、
逆に不要なものを付け足してしまったりします。

すると、最終的にテストの作り直しになったり、
不要なテストを大量に実施してしまうなど、
工数を無駄にしてしまいます。

### 「テストの目的」とは「全数テストから切り出してくる」こと
テストの目的を決めるということは、
全数テストから切り出してくることです。

特定機能についてなら、その周辺領域を。
脆弱性についてなら、セキュリティ関連を。
全数テストから切り出してくる場所が大きく異なります。

切り出してくるべき場所を決めて、
正しく切り出しましょう。

そして、決めたテスト目的のために切り出してきたものは、
その目的のためだけに使うようにしましょう。

### 「テストの目的」を忘れないこと、そしてブレないこと
例えば、特定機能のテストのために切り出した後、
「セキュリティもやりたいな」などとそこからテストを削っていくと、
上手くいきません。
上述の通り、切り出してきた中には全部が含まれていないからです。

だからといってそこに付け足すと、
歪な彫刻になってしまったり、
美しくないものになったりしてしまいます。
歪や美しくないというのは、
必要なテストが抜けていたり、
実行し辛いという形で表れてきます。

「テストの目的」を忘れないようにするのも必要ですが、
「当初の目的からブレないこと」も重要です。
他の目的を思いついたら、新たに切り出してきましょう。
それが綺麗な彫刻、もとい綺麗なテストを作るのに必要です。

## 「テスト設計技法」は、創る技法ではなく削る技法
### 「テスト設計技法」の用途
先述の通り、そして掲題の通り、
「テスト設計技法」は一見して組み立てる創造の技法に見えますが、
その実は削る技法です。

全数テストから、テスト目的を元として大まかに切り出してきたものから、
不要な部分を削り取って、テストを作成します。

分かりやすいもので行けば、
+ 多く存在するデータ入力値を数個に削る「同値分割法」「境界値分析」
+ 不要なテストを事前に削れるデシジョンテーブルの「簡単化」
+ 膨大な掛け合わせを大きく削る「ペアワイズ法」「オールペア法」

などになります。
一見して「掛け合わせる」ということをするので０から創るように見えますが、
その実は「全数テストは無理だから効率の良い掛け合わせをする＝削る」ということです。

テスト設計技法の各詳細については今回割愛します。

### 必要なテストからさらに削る場合もある
今までの記載で、必要なテスト設計≒彫刻を創るようなイメージはついたかと思います。

QAではコストや納期の関係上、さらに削らざるを得ないことがあります。
その場合、テスト技法ではなく「テスト目的を果たせるか」という観点で削ります。

例えば「彫像が重すぎるからもっと軽くしてくれ」という話です。
どう削ってよいのか、はテスト目的を崩さないようにです。
彫像なら「美しいように作ったなら、美しいまま削れ」ということです。
詳細は割愛しますが、ミロのヴィーナスが美しいように、実現することです。

## さいごに
テスト作成というものは、
「０から創る」ではなく「１００から削る」ものであると、
感じていただけたでしょうか。

今すぐ実践に持ち込むのは難しいかもしれませんが、
どこまでも無限に膨らむような底知れないなものではなく、
どんどん小さく削っていく理解の及ぶものであると、
心理的ハードルが下がってくれていると嬉しいです。
jQuery テーブルページネーション

```js
var menu = {};
// JSONファイルのデータを読み込み: $.getJSONだとうまくいかないので、$.ajaxを使用
$.ajax({
    url: './json/menu.json',
    dataType: 'json',
    async: false,
    success: function (data) {
        menu = data;
    }
});

// ページング機能
var pagination = function () {
    // 初期値設定
    var page = 1; // 現在のページ（何ページ目か）
    var step = 5; // ステップ数（1ページに表示する項目数）

    // 現在のページ/全ページ を表示
    var count = function (page, step) {
        var total = (menu.length % step === 0) ? (menu.length / step) : (Math.floor(menu.length / step) + 1);
        $('.count').text(page + "/" + total + "ページ");
    };

    // ページを表示
    var show = function (page, step) {
        // 一度テーブルを空にする
        $('.menu_list tbody').empty();
        var first = (page - 1) * step + 1;
        var last = page * step;

        for (var i = 0; i < menu.length; i++) {
            if (i < first - 1 || i > last - 1) continue;

            // テンプレートリテラルを避ける
            var row = $('<tr data-id="' + menu[i].id + '">').append(
                '<td>' + menu[i].name + '</td>',
                '<td>' + menu[i].price + '</td>'
            );
            $('.menu_list tbody').append(row);
        }
        count(page, step);
    };

    // 最初に1ページ目を表示
    show(page, step);

    // 最前ページ遷移トリガー
    $(document).on('click', '#first', function () {
        if (page <= 1) return;
        page = 1;
        show(page, step);
    });

    // 前ページ遷移トリガー
    $(document).on('click', '#prev', function () {
        if (page <= 1) return;
        page = page - 1;
        show(page, step);
    });

    // 次ページ遷移トリガー
    $(document).on('click', '#next', function () {
        if (page >= Math.ceil(menu.length / step)) return;
        page = page + 1;
        show(page, step);
    });

    // 最終ページ遷移トリガー
    $(document).on('click', '#last', function () {
        if (page >= Math.ceil(menu.length / step)) return;
        page = Math.ceil(menu.length / step);
        show(page, step);
    });
};

$(window).on('load', function () {
    pagination();
});
```
Elixirチートシートを作ろう、番外編その７ アドベンドカレンダーはとりあえず完走

# 1. OverView

どもども、うん、アドベントカレンダーの完走賞狙いなんだ、すまない。

今回は、やらかしたTIPSをまとめときたいと思います。


# 2. 懺悔
## 2.1 kinoがインストールできない！…違います、ただのバージョン指定ミスです。

Livebookでkinoを使おうと思った賢い俺様、先頭のDependenciesのところで、Mix.Installでkinoを入れたにも関わらず、
 Kino.Textが使えません。 

Mix.Installで指定したKinoのバージョンが0.6.0
そして、今のKinoのバージョンはv0.14.2です。

https://hexdocs.pm/kino/Kino.html

素晴らしい参考資料があったのにねぇ。
Kino まとめ - Livebook があれば何でもできる -
https://qiita.com/RyoWakabayashi/items/dc1cbd9be772fdcbce74


## 2.2 iexがexampleをロードしねぇ！

iex.bat -S mixをしても、 iexがexampleをロードしねぇ！なので、ブレークポイントを設定どころではない。

…mix cleanで、古いファイルを消したら、治りました。

起動時に以下の様なエラーが出ていて、気づきましたとさ。

```
(base) C:\Users\nanbu\example>iex.bat -S mix
Erlang/OTP 27 [erts-15.2] [source] [64-bit] [smp:16:16] [ds:16:16:10] [async-threads:1] [jit:ns]

Interactive Elixir (1.18.0) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)>  c "lib/example.ex"
    warning: redefining module Example (current version loaded from _build/dev/lib/example/ebin/Elixir.Example.beam)
    │
  1 │ defmodule Example do
    │ ~~~~~~~~~~~~~~~~~~~~
    │
    └─ lib/example.ex:1: Example (module)

[Example]
iex(2)>
```

## 2.3 Debuggerが起動しねぇ！

Debuggerが起動しない。
iex.batを実行すると出来るけど、iex.bat -S mixを実行すると起動しない。

```
iex(1)>  :debugger.start()
** (UndefinedFunctionError) function :debugger.start/0 is undefined (module :debugger is not available)
    :debugger.start()
    iex:1: (file)
iex(1)>
```
これ、公式に書いてありました。
https://hexdocs.pm/elixir/debugging.html
Missing dependencies
Mix.ensure_application!(:wx)             # Not necessary on Erlang/OTP 27+
Mix.ensure_application!(:runtime_tools)  # Not necessary on Erlang/OTP 27+
Mix.ensure_application!(:observer)
Mix.ensure_application!(:debugger)

以下で怪傑
```
(base) C:\Users\nanbu\example>iex.bat -S mix
Erlang/OTP 27 [erts-15.2] [source] [64-bit] [smp:16:16] [ds:16:16:10] [async-threads:1] [jit:ns]

Interactive Elixir (1.18.0) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> Mix.ensure_application!(:debugger)
:ok
iex(2)>  :debugger.start()
{:ok, #PID<0.135.0>}
iex(3)>
```
僕の追加ってる環境はErlang/OTP 27なので、上の一行で大丈夫でしたね。

# 最後に

さて、そんなわけで無事？三年目にしてアドベントカレンダーを完走出来ました。
fukuoka.ex, piyopiyo.exのみなさん、ありがとうございました。

こつこつ、チートシート作りは実用的？な方面に手を出したいと思うので、ご支援よろしくお願いします。
"にょろぼん" のコンテスト作品🖼️制作日記2024②

みなこんばんちわ！　”にょろぼん”です。
『コンテスト作品』**その第一歩の踏み出し方が分かんなくて困るんよね！** というお話しです。
前回は、踏み出す、最初の🐾 第０歩～０.５歩の日々を描きました！
伝えたかったのは📣何もないとこから始めたわけじゃないってこと！
『おもいつき💡を、過去に習ったありもの知識の、組み合わせで実現しようとした』のが最初なんだよ！
でもって、お次の今回こそが。**問題の第一歩目！** 実は、最も読んで欲しい内容かも。

## DAY②『コード描き描きの。ホントはじめの一歩！』
作品を作るためには！何か描き始めないと始まらない！(あたりまえ♫体操～♪チャンチャン)
ですよね。。”にょろぼん” が最初に手を付けたのは、htmlファイルへの部品配置でした。
★コンビニチケットアプリを作るために最低限必要な部品数を洗い出す★
入力情報：引換開始日、引換終了日、引換コンビニ名、引換商品名　＋決定ボタン！
	⇒すなわち、インプット入口部品5つ！
	(それぞれ変数名：validDate, expireDate, cvs, goodsName と、Submit)
出力情報：入力情報をもとに加工した加工済データ
	⇒すなわち、アウトプット出口部品１つ！(変数名：result)
	
最低限、機能実現の為に、htmlに６つの部品(タグです＜タグ＞)を置かないとぽいです！
でも、ただ部品置くだけじゃ動かにゃい。そう！部品を掴んで動かすためには、id付きタグにしなきゃです！
id付きタグをつくるには⇒　**#validDateと書いて、Enterキーを押すのでした！**
ひたすら、上の変数名に#を付けて。ワシワシ作業していきます。
と、いうわけで。。とりま描いたのが！超原始版cvsTicket.html 
```html:cvsTicket.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
<div id="validDAte">引換開始日</div>
<div id="expireDAte">引換終了日</div>
<div id="cvs">CVSﾁｴｰﾝ</div>
<div id="goodsName">商品名</div>

<div id="submit">決定する</div>

<div id="result">!引換可能なチケットリストは以下の通りです!</div>

</body>
</html>
```
ああ。かんたんすぎてハズいけど😅これが現実。

## Day③『はじめの１．５歩目！ 部品置いたらidで部品掴んでJSファイルに持ってこよ～』
htmlに置いた部品(id付きのタグ)をグイっと掴んでJSファイルに持ってきたいワケです！！
そうです！document.getElementByIdをファイル最初に書いとけばJSファイルで操作できるようになるんでした！
機械的に、let *** = document.getElementById(`***`);　の***をひたすら埋めてく
(↑変数名とid名を同じにしちゃってます💦だって...同じ名前の方が分かり易いんだもん）
(↑あくまで”にょろぼん”の好み。。変数名とid名をちゃんと変える意味もよくわかるし。。)
だけの簡単なお仕事をカタカタと。。とりま描いたのが！超原始版cvsTicket.js
```js:cvsTicket.js
let validDate = document.getElementById(validDate);
let expireDate = document.getElementById(expireDate);
let cvsName = document.getElementById(cvs);
let goodsName = document.getElementById(goodsName);
let submit = document.getElementById(submit);
let resultArea = document.getElementById(result);

//以下、あとで使う部品
//  date = new Date();　
//  if(validData <= date && date <= expireData) {
```
あはは。。。これだけ！！超単純作業だよね～！
でもね。ここまでくると。webページに部品を配置出来て。その部品を掴んできて
プログラムで動かす為の準備が整うワケなんですよ！

なんだよ！つまんね～な（プンプン！）という苦情の声が聞こえてきそうですが。。。
正真正銘、これがアプリ製作の第一歩なんでした。。
むしろ、ここまで来たら。あとは、使えそうな部品やロジックを、N予備の過去の授業からもってきたり、ググって探して当てはめて行けばイイ！
もう、半分出来たようなもん！だと、 ”にょろぼん” は本気で思っているよ。

作品作り第一歩がな～とお悩みのみなさん！　だまされたと思って、Day③のステップまで単純作業してみませんか
もし、Day③のgetElementById並べるところまで済ませたら。
『なんだか、行ける気がする～』と思って貰えるんじゃないかな！！たぶんですけど。

”にょろぼん”がすごく大事だと思う事！もう書きました！！冬のコンテストとかでトライしてもらえるとうれCY
次回はもっと小手先テク。。部品探しとか、その時参考にしたページとかを描くつもり！次回も読んでくれると嬉しいです ٩( 'ω' )و
短期間・短時間で合格したITパスポートの体験記！

## はじめに
　皆さんご存じのITパスポートを短時間・短期間で学習・合格する方法を共有し、皆様のスキルアップの役に立てていただけると幸いです！こちらの勉強方法は、他のスキルや資格にも転用できるように書きました！
　たまたま、見ていただいた方にも、もう合格している方もぜひ読んでご感想書いていってください。

## 【ITパスポートの平均勉強時間】
　ネット上では、50時間～80時間ぐらいといわれており、1日2時間の勉強が出来れば、1ヶ月～2ヶ月程度で合格できる資格となっております。合格率の50％台と、2人に1人は合格しています！
　今回の学習方法の目標時間は35時間（2週間）です。
 ##### ・その他の情報
受験料は7700円（2024年時点）、試験は比較的いつでも受けることが出来ます！

 ## 【勉強計画と参考】
　では、短期間・短時間なので、実際の勉強時間と使用した参考書・サイト・youtubeについて、お教えいたします。
 ##### ・勉強時間と計画
　1日/2時間30分×2週間＝35時間で合格しました。2週間限定で集中して勉強していくことで、短期記憶と長期記憶でカバーリングしながら、短期間合格を達成しました。
 　計画：参考書通読：5ｈ、練習問題：25ｈ　動画学習・参考書復習：5ｈ


 
では、実際に使用した参考書やサイトやyoutubeについて紹介していきます。
## 【使用した参考書・サイト・youtube】
 実際に使用した参考書は「[1回で受かる!ITパスポート合格テキスト](https://www.amazon.co.jp/1%E5%9B%9E%E3%81%A7%E5%8F%97%E3%81%8B%E3%82%8B-IT%E3%83%91%E3%82%B9%E3%83%9D%E3%83%BC%E3%83%88%E5%90%88%E6%A0%BC%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88-24%E5%B9%B4%E7%89%88-2024%E5%B9%B4%E7%89%88-%E7%BE%8E%E9%A6%99%E5%AD%90/dp/441523786X)」です。
 （価格：1,650円）
![スクリーンショット_24-12-2024_163639_www.amazon.co.jp.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3952661/b33ce44f-6851-fea2-506f-e189cb05fdcf.jpeg)


参考サイト：
「[ITパスポート　過去問道場](https://www.itpassportsiken.com/ipkakomon.php)」
「[ITパスポート試験問題（情報処理推進機構）](https://www3.jitec.ipa.go.jp/JitesCbt/html/openinfo/questions.html)」
※過去問をダウンロードして本番と同じ感覚で過去問を解くことが出来ます。
 参考youtube：「[ITパスポート聞き流し（みみスタ）](https://www.youtube.com/watch?v=jam4p94A2Tk&t=200s)」
 


 ## 解説！〈勉強時間と計画〉
1.まず初めに参考書を5時間で通読します！
  その際に、難しくてわからない言葉を暗記するのではなく、全体的に理論の理解を優先してください。
　通読の際に、周りの注釈や派生事項も目を通して全体の把握してください。また、ITパスポートには「ストラテジー系・マネジメント系・テクノロジ系」の3種類の分野に分かれております。この分野のうち、どこが苦手で読み進めずらいのか、も理解して学習してください。
 　筆者はテクノロジ系が最初から壊滅的でした。。。

2.通読が終わりましたら、巻末の模擬試験を行います。ここでは、点数などは気にせずに、復習の為と思ってやってみましょう。通読・一回目の模擬試験が終わりましたら、次はサイトの「[ITパスポート　過去問道場](https://www.itpassportsiken.com/ipkakomon.php)」へ移行しましょう！
　 ここでは、ITパスポートの過去問を一問ずつ受けることが出来、回答するとすぐに解説がわかるサイトになってます。ログインしなくても、回答中の正答率についても出てきますので、正答率も確認できます！
  このサイトでは、正解不正解に関わらず、問題文や選択肢の解説があります。解説の部分をよく読み、単語の理解をしていきます。この際、暗記を進めていきます。どの言葉がどんな意味でつかわれるのか、理論と繋げて、選択肢の単語や問題文の単語を覚えていきます。もし、その単語から周りの言葉や理論が思い出せない際は参考書の末尾にある索引から目的のページを探し、復習してください。この際、簡単に調べるだけだと定着しにくいので、参考書を使うことをお勧めします！

★過去問道場では分野指定して問題の出題もできるため、分野指定して苦手分野の克服や得意分野の復習をしてください。

3.過去問道場で全体的に6割をとれるようになってきたら、腕試しで「[ITパスポート試験問題（情報処理推進機構）](https://www3.jitec.ipa.go.jp/JitesCbt/html/openinfo/questions.html)」から過去問をダウンロードし、本番環境で挑戦します。過去問なので、過去問道場で回答していたりしているので高得点でも、浮かれないよう注意です！3年間分ぐらいを7割平均でとれるようになることを目指してください。


4.過去問道場や本番環境の過去問で安定して6割近く取れてきたら、最後の詰めで「[ITパスポート　過去問道場](https://www.itpassportsiken.com/ipkakomon.php)」の「ITパスポート用語辞典」から、最近追加された単語を覚えていくようにしてください。
　通勤や通学、遊びの予定などがある際は移動時間中に「[ITパスポート聞き流し（みみスタ）](https://www.youtube.com/watch?v=jam4p94A2Tk&t=200s)」などのyoutubeで学習してみましょう。移動時間を有効活用することで、短期間合格を目指せます！


 ## 最後に
　「全体把握→要点学習→分野学習→全体学習」と言ってしまえば当たり前の学習方法です。
　簡単で当たり前のなので見落としがちですが、この学習方法は新しい分野の仕事始めの際にも有効活用できるので、ぜひITパスポート合格後も、やり方を忘れずに、様々なことを学習していってください。
 　筆者は1児のパパで、まったく未経験のIT業界に転職する為、ITパスポートを学習しました。平日の夜21時～23時半までが主な学習時間で、休日は家族サービスしていました。そんな中でも合格できるので、これからもいろいろな資格や仕事の知識をつけていくことに挑戦したいとおもいます！
`__FILE__`、`__LINE__`とは

```rb
ActiveSupport::CodeGenerator.batch(_owner, __FILE__, __LINE__) 
```
https://github.com/rails/rails/blob/cf6ff17e9a3c6c1139040b519a341f55f0be16cf/activemodel/lib/active_model/attribute_methods.rb#L311C7-L319C1

>`__FILE__`
現在のソースファイル名

>フルパスとは限らないため、フルパスが必要な場合は File.expand_path(__FILE__) とする必要があります。

>`__LINE__`
現在のソースファイル中の行番号

https://docs.ruby-lang.org/ja/latest/doc/spec=2fvariables.html#:~:text=__FILE__,%E3%81%AE%E8%A1%8C%E7%95%AA%E5%8F%B7

```rb
irb(main):016> __FILE__
=> "(irb)"
irb(main):017> __LINE__
=> 17
```
シェルスクリプトやmakefileでWSLかどうかを判定して、コマンドを切り替える

## TL;DR

比較的簡単な方法として、次のようなものがありそうです。

### シェルスクリプト

```bash
if [[ -d /run/WSL ]]; then
    ADB=adb.exe
else
	ADB=adb
fi
```

### makefile

```makefile
WSL := $(shell test -d /run/WSL && echo 1 || echo 0)
ifeq ($(WSL), 1)
    ADB = adb.exe
else
	ADB = adb
endif
```

## やりたかったこと

最近は基本的にはWSL上で開発をしています。

WSLは非常に良いのですが、デバイスと通信するときとかは少し工夫が必要になります。

たとえば、Androidなどの開発をしているときに、USBでデバイスを接続して、adbコマンドでおしゃべりすることがありますが、USBデバイスの接続のサポートはWSLではネイティブに使用できないので何らかの対応をしなければなりません (たとえば、https://learn.microsoft.com/ja-jp/windows/wsl/connect-usb )。

比較的簡単な方法として、そもそもホストWindows側にインストールしたadb.exeを使用するという方法があります。

これは簡単でよいのですが、`adb.exe`というのをプロジェクトのシェルスクリプトなどに記述してしまうと、今度は、普通のLinux上でそのシェルスクリプトは動かなくなってしまいます。

そこで、そのシェルスクリプトが実行されている環境がWSL上なのか、それとも普通のLinux環境なのかを判定して、WSL上ならホストWindowsの`adb.exe`を呼び出し、そうでなければ単に`adb`コマンドを呼び出すというふうにしたいなと思いました (ネイティブのWindows上やMac OS上、あるいは他のOSのことは一旦ここでは考えないことにします)。

## 説明

調べてみると、`uname -r`コマンドを使用して、microsoftという文字列が入っているかで判定する方式が見つかります (https://gist.github.com/mmktomato/e75a166a09fe8920919cf67e5599487d など)。

それでも良いのですが、grepにパイプしたりしなくちゃいけなくて、少し複雑な感じがしました。

そこでさらに調べてみると、WSL上には`/run/WSL`というディレクトリがあり、そこでホストWindowsとの情報共有や通信を行っているようです。

良いかどうかは微妙ですが、このディレクトリの有無で判定すると、かなり簡単に「WSLかWSL以外か」を判定できそうでした。

TL;DRに記載した方法はこの方法で、今のところこの方法を採用しています。

## エンジニアを募集しています

最後に宣伝となります。

私の所属するピクシーダストテクノロジーズ(PxDT)では、この記事の中で書いたように、`adb`コマンド等を使用してAndroidスマホや組み込み機器の開発をしています。

この記事は小ネタのような内容ですが、複雑ながらも面白い製品開発に業務として日々取り組んでいます。

ピクシーダストテクノロジーズでは、組み込みエンジニアやモバイルアプリエンジニアを募集していますので、もしご興味があればぜひご応募ください。

お待ちしております！

https://herp.careers/v1/pxdt
`_`で始まる識別子

```rb
def define_attribute_method(attr_name, _owner: generated_attribute_methods, as: attr_name)
 ActiveSupport::CodeGenerator.batch(_owner, __FILE__, __LINE__)
 ....
``` 
https://github.com/rails/rails/blob/cf6ff17e9a3c6c1139040b519a341f55f0be16cf/activemodel/lib/active_model/attribute_methods.rb#L311C7-L319C1

* `_owner`はメソッド呼び出しているのか

>`小文字`または`_`で始まる識別子は`ローカル変数`または`メソッド呼び出し`です。ローカル変数スコープ(クラス、モジュール、メソッド定義の本体)における小文字で始まる識別子への最初の代入はそのスコープに属するローカル変数の宣言になります。`宣言されていない識別子の参照は引数の無いメソッド呼び出し`とみなされます。

>ローカル変数のスコープは、`宣言した位置からその変数が宣言されたブロック、メソッド定義、またはクラス/モジュール定義の終りまで`です。`寿命もそのブロックの終りまで`(トップレベルのローカル変数はプログラムの終了まで)ですが、例外としてブロックが手続きオブジェクト化された場合は、そのオブジェクトが消滅するまで存在します。同じスコープを参照する手続きオブジェクト間ではローカル変数は共有されます。

```rb
# (A) の部分はスコープに入らない
2.times {
  p defined?(v)    # (A)
  v = 1            # ここ(宣言開始)から
  p v              # ここ(ブロックの終り)までが v のスコープ
}

# => nil
#    1
#    nil           <- これが nil であることに注意
#    1
```

https://docs.ruby-lang.org/ja/latest/doc/spec=2fvariables.html#:~:text=%E5%B0%8F%E6%96%87%E5%AD%97%E3%81%BE%E3%81%9F%E3%81%AF%60_,%E3%81%93%E3%81%A8%E3%81%AB%E6%B3%A8%E6%84%8F%0A%23%20%20%20%201
【競技プログラミング】AtCoder Beginner Contest 061_C問題

# 問題
https://atcoder.jp/contests/abc061/tasks/abc061_c

## 要約
1. 空の配列が1つある。
2. この配列に対して、N回の挿入操作を行う。
3. i回目の操作（1 ≤ i ≤ N）では、整数aiをbi個配列に挿入する。
4. N回の挿入操作が終わった後、配列の中でK番目に小さい数を求める。

- N: 挿入操作の回数
- ai: i回目の操作で挿入する整数
- bi: i回目の操作でaiを挿入する個数
- K: 求めるべき小さい順の位置

例として、最終的な配列が {1,2,2,3,3,3} の場合、4番目に小さい数は3となります。

# 既存投稿一覧ページへのリンク
[一覧ページ](https://qiita.com/o_chan_t/items/fc759695acfaef8df2cc)
[1回目の挑戦(AC)](https://qiita.com/o_chan_t/items/37e647801ac7a744bd91)

# アプローチ

挿入される数とその個数の組を保持し、ソートして効率的に処理を行う。
実際に配列を作成せずに、K番目の要素を特定する。

# 解法手順

1. 入力を受け取り、(ai, bi)のペアを配列に格納する。
2. 格納した配列を、aiの値でソートする。
3. ソートされた配列を順に走査し、以下の処理を行う：
   - 現在の要素のbi（個数）をKから引く。
   - Kが0以下になった時点で、その要素のaiがK番目に小さい数となる。
4. K番目に小さい数（ai）を出力する。


# ACコード
```python:ac.py
def io_func():
    # 入力を受け取る
    n, k = map(int, input().split())  # nとkを入力から取得
    pairs = []  # (ai, bi)のペアを格納するリスト
    for _ in range(n):
        a, b = map(int, input().split())  # aiとbiを入力から取得
        pairs.append((a, b))  # ペアをリストに追加
    return n, k, pairs

def solve(n, k, pairs):
    # ペアをaiの値でソート
    sorted_pairs = sorted(pairs)  # aiでソート

    # ソートされた配列を走査
    for a, b in sorted_pairs:
        k -= b  # 現在の要素の個数をkから引く
        if k <= 0:  # kが0以下になったら
            return a  # その要素のaiがK番目に小さい数

# メイン処理
n, k, pairs = io_func()  # 入力を受け取る
result = solve(n, k, pairs)  # 解を求める
print(result)  # 結果を出力

###
# 変数の意味:
# n: 入力される数の種類
# k: 求めるK番目の数
# pairs: (ai, bi)のペアを格納するリスト
# sorted_pairs: aiでソートされたpairsのリスト
# a: 現在処理中の数
# b: 現在処理中の数の個数
# result: K番目に小さい数

# 1. io_func関数:
#    - 標準入力からn, k, そして(ai, bi)のペアを読み込む
#    - 読み込んだデータを適切な形式で返す
# 2. solve関数:
#    - 入力されたペアをaiでソートする
#    - ソートされたペアを順に走査し、kから各要素の個数を引いていく
#    - kが0以下になった時点で、その要素のaiを返す
# 3. メイン処理:
#    - io_func関数を呼び出して入力を受け取る
#    - solve関数を呼び出して解を求める
#    - 結果を出力する
```
react-scrollを使ったページ内スクロールを実装・テストも作成


react-scrollを使ったページ内スクロールを実装します。

スクロールのトリガーとなるボタンをコーディングし、クリックイベントを追加します。
`handleScrollToSearch`関数がクリック時に呼び出され`scrollToContents()`が発火します。

```Component.tsx
export const Component: FC = () => {

  const handleScrollToSearch = () => {
    scrollToContents()
  }

  return (
      <button onClick={handleScrollToContents}>
        ボタン
      </button>
    )
}
```


`scrollToContents`関数は汎用的に使用できるように切り出します。

react-scrollをインストールし、importします。

`yarn add react-scroll`

```scrollToContents.ts
import { scroller } from 'react-scroll'

export const scrollToContents = () => {
  const defaultHeaderHeight = 68;　

  scroller.scrollTo('scrollToContents', { //scrollさせたい場所のclassNameを指定
    duration: 200, //スクロールにかかる秒数
    delay: 0, //遅延
    smooth: true,
    offset: -defaultHeaderHeight, // 今回の例ではヘッダー分の高さを追加しています
  })
}
```

オプションについては[公式ドキュメント](https://github.com/fisshy/react-scroll?tab=readme-ov-file#propsoptions)から。

スクロールさせたい場所にclassName`scrollToContents`を指定します。


```Component.tsx

export const Component: FC = () => {
  return (
    <div className="scrollToContents">
       ...
    </div>
    )
}
```

これで実装完了です。


さらにJestを使ったテストはこちら。

```scrollToContents.test.ts
import { scroller } from 'react-scroll'
import { scrollToContents } from './scrollToContents'

jest.mock('react-scroll', () => ({
  scroller: {
    scrollTo: jest.fn(),
  },
}))

describe('scrollToContents', () => {
  it('should call scroller.scrollTo with correct arguments when offset is positive', () => {
    const HeaderHeight = 68

    scrollToContents()

    expect(scroller.scrollTo).toHaveBeenCalledWith('scrollToContents', {
      duration: 200,
      smooth: 'easeInOutQuart',
      offset: -HeaderHeight,
    })
  })
})
```

## 参照

https://github.com/fisshy/react-scroll?tab=readme-ov-file
Automation Hubのススメ

## はじめに
作ったRPAや作ろうとしているRPAのアイデアって、どのように管理していますか？
ほとんどの場合が『Excelのリストで一覧にしている』という管理方法がほとんどでは無いかなと思います。もちろん、出来ます！それもアリです！ですが、是非Automation Hubを活用することをオススメします。

### オススメその１
**テンプレートがあることで、全員がもれなく同じ項目について、ほぼ同じような認識で記載できる**
これはRPA管理者にとってはかなり重要で、特に「既存の作業時間」について、作業頻度や人数、その他にも手戻りの時間やチェックの時間なども含めて算出することができます。
既存の作業時間について、悩まれる業務ユーザーの方も多いと思いますし、手入力であれば見落としてしまう暗黙の時間なども含めることができるので、根拠のある時間になります。
>たまーに、掛け算でこの数字がとんでもないことになって一同驚愕した・・・！という事件もありましたが、入力時の勘違いもありましたが、実は実際にはこんなにかかっていたというケースもありました:zipper_mouth:

### オススメその２
**データを一覧でCSV形式にてダウンロードできる**
Excel管理と変わらないじゃないかと思われそうですが、どうしてもAutomation Hub上だけで見るには限界があるので、こうしたデータエクスポートの機能はSaaSシステムでは重要です！しかも出力項目や絞り込みなどかなりカスタマイズ可能で、さらにカスタマイズしたビューを同じロール内で共有することもできるようになりました。進化して嬉しいです。
この機能がないと、最悪、RPAでスクレイピングするしかなくなるので、実はポイントとして大きいです。

### 場合によってはオススメ
**進捗管理が可視化できる**
要件定義や開発、テストといったフェーズ管理ができ、さらに案件に依頼者や開発者など関わるメンバーを全員紐づけることができるので、プロ開発の場合でも、待ちなのか、開発中なのかなど確認することができます。
但し、この場合は関係者全員で統一ルールによる利用が必要であるため、やや活用ハードルは高めかもしれません:grimacing:

### 難点
* ライセンス費用がかかる
* ユーザー情報のメンテナンスが大変
* 集計などのBIデータを正確に利用するためにはかなりの入力精度が必要

難点もありますが、データクレンジングが完璧にできなくても共有情報としてだけでもかなり有益なものになっています。
もっともっとオススメしたいポイントもありますが、少しでも興味を持ってくれる管理者の方がいたら嬉しいなと思います:blush:

公式リンク
[UiPath公式HP Automation Hub](https://www.uipath.com/ja/product/automation-hub)
Elixirチートシートを作ろう、番外編その５ hexdoc見てたら、おや？デバッグ方法、こんなにあるの？


# 1. OverView

どもども、うん、アドベントカレンダーの完走賞狙いなんだ、すまない。

hexdoc見てたら、おや？デバッグ方法、こんなにあるの？と言うお話をしてみたいと思います。

https://hexdocs.pm/elixir/debugging.html

IO.inspect/2
dbg/2
Pry
Breakpoints
Observer
Other tools and community

ざっと見たのですが、現時点でIO.inspect/2、Pry、Breakpointsくらいはすぐにでも抑えねば！

随時、Elixir入門を参考にさせていただいております。
https://dev.to/gumi/elixir-21--21a1


# 2. IO.inspect/2

## 2.1 hexdocで確認

hexdocでIO.inspect/2を読むところからやりましょう。

https://hexdocs.pm/elixir/1.12/IO.html#inspect/2

```
@spec inspect(item, keyword()) :: item when item: var
Inspects and writes the given item to the device.
```

引数で与えられたItemをDeviceに書き出してくれると書いてありますね。
こっからが面白い。（俺だけか？）

```
It's important to note that it returns the given item unchanged.
This makes it possible to "spy" on values by inserting an IO.inspect/2 call
almost anywhere in your code, for example, in the middle of a pipeline.
```

翻訳すると…
重要なのは、指定された項目を変更せずに返すことです。 
これにより、例えばパイプラインの途中など、コードのほぼどこにでもIO.inspect/2呼び出しを挿入して
値を「スパイ」することが可能になります。

…"It's important"とか書かれると、期待が広がりますねぇ。

## 2.2 IO.inspect/2を使ってみよう。

まずは、hexdocのサンプルから行ってみますか。
重要なオプション、label:width:が出てきております。


```
iex(2)> IO.inspect(<<0, 1, 2>>, width: 40)
<<0, 1, 2>>
iex(3)> IO.inspect(<<0, 1, 2>>, width: 4)
<<0,
  1,
  2>>
```
width: 4にしたのは、飽くまでもサンプルとしてですが、綺麗に改行してくれるものですね。
次、オプションlabel:
```
iex(5)> IO.inspect(1..100, label: "a wonderful range")
a wonderful range: 1..100
1..100
```
ラベルを付けてくれるので、とても便利ですね。

さて、パイプの中での使い方例を見てみましょう。

```
[1, 2, 3] |> IO.inspect(label: "before")
|> Enum.map(&(&1 * 2))
|> IO.inspect(label: "after")
|> Enum.sum()
before: [1, 2, 3]
after: [2, 4, 6]
12
```
…ちゃんと、前後がわかりやすく綺麗に出てますね。

では、もう一つbinding/0と組み合わせてみましょう。
binding/0は指定されたコンテキストのバインディングをキーワードリストとして返す変数ですが、
指定されたコンテキストがnilの場合、現在のコンテキストのバインディングが返されます。

ぶっちゃけ、そのスコープの変数のbinding状況を、全部出してくれます。

```
iex(30)> defmodule Example do
...(30)>   def show_binding do
...(30)>     x = 1
...(30)>     y = 2
...(30)>     IO.inspect(binding(),label: "Show binding:")
...(30)>   end
...(30)> end
iex(31)> Example.show_binding()
Show binding:: [x: 1, y: 2]
[x: 1, y: 2]
```
いちいち書かなくても、変数の状況が丸わかりですね。
これば便利、ではこの辺で…いや、もう一つちゃんとやりますから。

## 2.2 IO.inspect/3を使ってみよう。

```
h IO.inspect/3

                        def inspect(device, item, opts)
```

inspect/2のdeviceつきですね。第一引数にdeviceが加わってます。
これ、便利なんでメモしときます。

deviceをファイルに割り当てれば、記録が取れます。

```
{:ok, file} = File.open("example.txt", [:write])
IO.inspect(file, binding(),label: "Show binding:")
File.close(file)
```

実行結果はこんな感じになります
```
iex(20)> test=1
1
iex(21)> test2=2
2

type example.txt
Show binding:: [file: #PID<0.110.0>, test: 1, test2: 2]
```

と、言うわけでIO.inspect/2で遊んでみました。
…うん、ググればわかるって、まぁ、そう言わずに。
E2EテストでGaugeが辛いなぁと思ったときに読む記事

## はじめに
はじめまして、[HITOTSU株式会社](https://www.hitotsu.co.jp/)の河村康治です！
これまでE2EテストはGaugeで実施していたのですが、だんだんとGaugeが辛くなり、Playwirghtに移行しました。
今回はGauge→Playwrightに移行した時の経緯を記事に残していこうと思います！！

## Gaugeいいじゃん！って思ったとき
GaugeはMarkDown形式でシナリオが記載でき、ユーザのシナリオが自然言語にかけるのはいいなと思い採用しました。また自然言語にかけることで、ユーザシナリオをPDMが作成し、シナリオを元にDevがテストコードに落とし込む事ができるので、役割分担ができます。

MarkDownと実際のテストコードの結び付け方も簡単で、Markdown形式のspecファイルに書いた内容を`@Step`のメッセージと紐づいているだけです。(下記画像のような感じです)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/487c8ad9-0ffa-ed37-8b27-6148912ea3c2.png)

Gaugeはデフォルトでブラウザ操作ツールは**taiko**でしたが、**Playwright**の方が扱いやすいなと思い、Gauge✖️Playwrightという構成に着地しました。

:::note info
Gauge✖️Playwrightで実装が固まった時は、おお、これはいいぞ！！とワクワク感が止まらなかったです。
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/ea49ef85-0c25-5964-3a10-7069d18768fa.png)

## あー、Gauge辛いなぁと感じる
実際にE2Eテストの運用を実施していくと、Gaugeでのいくつかの課題が出てきます。
### Specファイルではテストコードの戻り値を管理できない
ブラウザで登録作業を実施した場合、管理IDが表示されたとします。
その場合次のStepでも利用したいので呼び出し元に返却します。ただ、GaugeはMarkDown形式のテキストファイルです。**戻り値をそもそも管理できる機構がない**のです。
あれ？？この値どうやって管理すればいいの？次のStepでも使いたいのだが。。。となる。回避策として、グローバルインスタンスを作成し、そこで値を管理する機構を作ることになります。このグローバルインスタンスをどのようなフォーマットで保持しておくのがいいのかというのも、頭を悩ませるポイントの1つでした。

### 再利用性を考慮した結果、テストケースの意図が伝わりにくくなる
異なるユースケースだけど、同一の関数を利用したい場合ありますよね。
ただ、マッピングファイルはspecファイルと同等のテストケース名で紐づけているので、1個変更すると動かなくなります。対策としては、specファイルの内容を抽象化する or 同様の関数を追加するかです。流石に、同様の関数を追加するのはナンセンスなので、specファイルの内容を抽象化することになります。ただ、せっかく具体的な内容を記載してわかりやすくしたのに、抽象化するのはもったいないなぁと感じます。

## 脱Gaugeに向けた対応
CodeceptJSを触ってみました。触った感触としては悪くなかったんですが、これだったらPlaywright1本でよくない？って結論になりPlaywright1本で実装することにしました。

https://zenn.dev/kouji0705/articles/5310c5cbbdeff0


## 参考
https://qiita.com/koji0705/items/d1503d981b8fe9412742

https://qiita.com/koji0705/items/ccd57df99f296c782aa9
キャッシング

>以前に表示したWebページに戻ってきたり、関連するWebページには同じリソースが埋め込まれていることがよくある。例えば、サイト内のナビゲーションに使われてる画像や共通のスタイル・シート、スクリプトなどである。ブラウザはすでにコピーを持っているため、表示のたびにこれらのリソースをすべて取得するのは無駄が多い。
　取得したページをその後の利用のために蓄えておくことはキャッシング(caching)と呼ばれる。


### キャッシングの問題
>HTTPキャシシングの難しい問題は、キャッシュしたページのコピーが、再度取得した時のページと同じであることをどのように判断するかということである。この判断はURLだけではできない。
### 問題解決の手法
#### 有効期限と日時で判断する
>ページの検証(ステップ２）である。キャッシュが参照され、要求されたURLのページのコピーが新鮮である。（まだ有効である）ことがわかっている場合は、サーバーから新たに取得する必要はない。代わりにキャッシュされたページを直接返すことができる。キャッシュされたページを最初に取得したときに返されたExpiresヘッダーと、現在の日時がこの判断をするのに用いられる。

>ただし、すべてのページに、ページを再度取得する必要があるかを教えてくれる便利なExpiresヘッダーがついてるわけではない。結局のところ、特に将来について予測することは難しいということである。

>あるページのキャッシュ可能性は時間の経過とともに大きく変化する可能性がある。

>サーバーは、いつページが更新されるかわからないため、Expiresヘッダーを保守的に用いらざるを得ない。

#### 条件付きGETで有効であるかを確認
>キャッシュされたコピーがまだ有効であるかどうかをサーバーに問い合わせることである。その要求は条件付きGET(conditional GET)であり、図7-28のステップに示されている。サーバーはキャッシュされたコピーがまだ有効であることがわかると、それを知らせる短い応答を返す(ステップ4a)。そうでない場合は、完全な応答を送信する必要がある。

https://bookplus.nikkei.com/atcl/catalog/23/03/16/00728/