OmniAICreator/Qiita-1.07M huggingface dataset:
Laravelのデータベースキャッシュドライバは、期限切れのキャッシュを自動的に削除しない

:::note
概要
有効期限切れのキャッシュのレコードは自動的には削除されません。
取得時（getメソッド）に有効期限切れかチェックされ、有効期限が切れていれば削除されます。
https://stackoverflow.com/questions/38250191/when-does-laravel-clear-the-cache
:::

# 背景

Laravelでデータベースキャッシュドライバを使用して、10s後に期限切れになるキャッシュを作成しました。
```php
Cache::put('key', 'value', $seconds = 10);
```

cacheテーブルに以下のレコードが追加されました

| key             | value           | expiration  |
|-----------------|-----------------|-------------|
|  key   | s:5:"value";        | 1731198618  |

しかし、10s後になってもレコードは残っていて[doc](https://laravel.com/docs/11.x/cache)にもそのような記載が見当たらない為調査しました。

# データベースキャッシュドライバは、期限切れのエントリを自動的に削除しない

こちらに記載されていました。

https://stackoverflow.com/questions/38250191/when-does-laravel-clear-the-cache


今回はLaravel 8.3を使っています。
最新だとこちらです

https://github.com/laravel/framework/blob/11.x/src/Illuminate/Cache/DatabaseStore.php

```php:vendor/laravel/framework/src/Illuminate/Cache/DatabaseStore.php
/**
     * Retrieve an item from the cache by key.
     *
     * @param  string  $key
     * @return mixed
     */
    public function get($key)
    {
        return $this->many([$key])[$key];
    }

    /**
     * Retrieve multiple items from the cache by key.
     *
     * Items not found in the cache will have a null value.
     *
     * @return array
     */
    public function many(array $keys)
    {
        if (count($keys) === 0) {
            return [];
        }

        $results = array_fill_keys($keys, null);

        // First we will retrieve all of the items from the cache using their keys and
        // the prefix value. Then we will need to iterate through each of the items
        // and convert them to an object when they are currently in array format.
        $values = $this->table()
            ->whereIn('key', array_map(function ($key) {
                return $this->prefix.$key;
            }, $keys))
            ->get()
            ->map(function ($value) {
                return is_array($value) ? (object) $value : $value;
            });

        $currentTime = $this->currentTime();

        // If this cache expiration date is past the current time, we will remove this
        // item from the cache. Then we will return a null value since the cache is
        // expired. We will use "Carbon" to make this comparison with the column.
        [$values, $expired] = $values->partition(function ($cache) use ($currentTime) {
            return $cache->expiration > $currentTime;
        });

        if ($expired->isNotEmpty()) {
            $this->forgetManyIfExpired($expired->pluck('key')->all(), prefixed: true);
        }

        return Arr::map($results, function ($value, $key) use ($values) {
            if ($cache = $values->firstWhere('key', $this->prefix.$key)) {
                return $this->unserialize($cache->value);
            }

            return $value;
        });
    }
```

:::note
期限切れのキャッシュは、取得時（getメソッド）にチェックされ、期限が切れていれば削除されます。
キャッシュのクリーンアップは、明示的にforgetやflushメソッドを呼び出す必要があります。
:::

試しにgetで取得し、その後レコードがcacheテーブルから消えていることを確認します。
```php
Cache::get('key');
```
確認した所レコードは確かに消えていました。

# 最後に
期限切れになったら消えると思っていたので勉強になりました。
WindowsでPythonを勉強してる新人へのアドバイス

WindowsでPythonを勉強してる新人へのアドバイス

- 画像認識系のサンプルはWSLからだとカメラへのアクセスがしんどいから気をつけろ
- Pythonの仮想環境構築がサンプルごとにバラバラだから気をつけろ
- WSLじゃなくてWindows＋Anaconda前提で語ってくる人もいるから気をつけろ
- ギリMS Store版のPythonで中途半端に動くけどSJIS前提になるから気をつけろ
- 諦めてGoogle Colab上でのみPythonを勉強するという選択肢もあるが、pythonプログラムは、.ipynbじゃなくて.pyで動くものを指すから気をつけろ
Pythonチュートリアル #4 -pipの意味をちょっと知る-

※以下の企画です

https://qiita.com/tatataichi/private/56936a028e625e62af8e


Pythonチュートリアル第４回目です。
ここまでやってきて早速実務の方にも以下のような、良い影響が出てきています。

1. Chat gptに書かせずに自分で先に書く
2. やっぱゼロから書いていくのって楽しいなと思えている

**…僕って新卒エンジニアだっけ？**

いや新卒エンジニアに失礼ですね。すみません。
ということで、コーディングを楽しむ心を取り戻しつつあるので、引き続き頑張ります。

# 第6章　学習内容まとめ
6章はモジュール系のお話が中心のよう。
めちゃくちゃ実務にも活かせそうでワクワク。

## モジュールとは
モジュールはめちゃくちゃ端的に言うと「〇〇.py」のこと。
同一カレントリ内にあるモジュールは`import 〇〇`で呼び出せる。ここらへんはC言語のincludeに似ているような気もする。

importにもいくつか方法があって、よく使うのは以下。
```python:import①-1
import hogehoge
```

hogehogeは`hogehoge.oy`というファイルのこと。こうすると指定したファイルの関数などにアクセスできる。
hogehoge.py内の関数を使うなら…

```python:import①-2
import hogehoge

hogehoge.function_name()
```

みたいにする。
もっとよく見るimport文だと…

```python:import②-1
from hogehoeg import function_name
```
とすることもできて、こう記述すると関数を使う際に、`hogehoge.`を省略出来る。

## 標準モジュール
〇〇.pyと自作したもの以外でも、最初からモジュールとして提供されるものがある。
例えば`sys.py`など。
全容は以下から見ることができて、`OS.py`などのよくみかけるものもあった。

https://docs.python.org/ja/3/library


## パッケージ
パッケージとは、**ドット区切りのモジュール名を使って、Pythonのモジュールを編成するもの**らしい。

**2ページくらいあって、細かくいろいろ解説されていたが、正直よくわからなかった( ◠‿◠ )**

ということでおなじみのGPTさんにも聞いてみた。
GPT曰く、

>パッケージは、複数のモジュールをまとめた「フォルダ」だと考えると分かりやすいです。パッケージの中には、たくさんのモジュール（＝Pythonファイル）が入っています。

とのこと。ふむふむ。これを踏まえて本書をもう一度読んでみるとそれなりに理解が深まった。

パッケージを活用すると、以下のような構成の複数モジュールを見かけ上一つの`import`で引っ張ってこれるみたい。
そして、それらのパッケージは`pip`を使えば簡単に入手できると。なるほどです。
ここで今までなんとなく使ってきた`pip`の必要性も理解できた。

パッケージとして認識させるには、`__init__.py`というファイルを生成しておく必要があるらしい。
**なんとなくわかった気がする( ◠‿◠ )**

ちなみに、よく使う`numpy`もパッケージだってさ。へぇ！

# まとめ
今回はコーディングテクニック的な内容ではなく、Pythonの裏側のルール的な内容を学習できた。
`モジュール`とか`pip`とか`パッケージ`とかなんとなく使っていたものを、「ちょっとわかる」レベルまでは上げられたと思う。
ちゃんと覚えてこう…！
【最新版】IT系ビジネスマンが読むべき有益資料まとめ

## はじめに

今回はIT系のビジネスマンが読むべき無料で公開されている有益資料をまとめました。

インターネットの仕組み、ブラウザ、WebAPI、要件定義など分野に特化せず幅広い内容が学べるようにピックアップしています。

資料も大手企業や、国、IPA(情報処理推進機構)といった機関が公開しているものを厳選しています。

## 紹介する資料一覧

- 要件定義ガイド(IPA)
- セキュアなWeb APIの作り方 (Oracle)
- 安全なWebサイトの作り方(IPA)
- セキュリティ研修 (MIXI)
- Webブラウザを作ってみよう
- インターネット仕組み (総務省)
- DX白書 (IPA)

## [ユーザのための要件定義ガイド(IPA)](https://www.ipa.go.jp/archive/publish/qv6pgp0000000wrt-att/000079352.pdf)

![スクリーンショット 2024-11-10 9.39.46.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/48c77ba9-feb9-1c97-2e1a-5921bd9363eb.jpeg)

IPAが公開している「要件定義」についての資料。

システム開発の現場や背景的な知識の整理から始まり、要件定義の問題認識、要件定義の全体像、要件定義における解決の勘どころ、計画立案、主要ドキュメントの作成方法と要件定義について、基礎から応用まで体系的に学ぶことができる。

## [セキュアなWeb APIの作り方 (Oracle)](https://speakerdeck.com/oracle4engineer/secure-web-api)

https://speakerdeck.com/oracle4engineer/secure-web-api

![スクリーンショット 2024-11-10 9.43.17.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/968022b1-a6ed-070f-8144-03c736fc982b.jpeg)

日本Oracle社が公開している資料。

SSL/TLS, 認証局, HTTP, DNSといった基礎用語の解説からはじまり、実際のWebAPIの処理の流れまで図解を通して学べる。  

解説がかなり丁寧かつ図解も豊富なのでイメージがしやすい構成になっている。

![スクリーンショット 2024-11-10 9.43.42.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/be69a866-2a7a-a8bc-5b34-ff5905ae2a25.jpeg)

## [安全なWebサイトの作り方(IPA)](https://www.ipa.go.jp/security/vuln/websecurity/ug65p900000196e2-att/000017316.pdf)

![スクリーンショット 2024-11-10 9.44.10.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/bd628959-9273-f63b-b0ef-0b9045f9f0ec.jpeg)

こちらもIPAが公開している資料になっている。

Webアプリケーションにおけるセキュリティの実装方法やWebの仕組み、安全性向上のための取り組み、失敗事例と基本用語の解説と具体的な事例がわかりやすく解説されている。こちらも図解が豊富に掲載されているので、仕組みの理解が初心者でもサクサクできる。

## [セキュリティ研修 (MIXI)](https://speakerdeck.com/mixi_engineers/2023-security-training)

https://speakerdeck.com/mixi_engineers/2023-security-training

MIXIが公開している新人研修資料。情報セキュリティの基礎整理から始まり、用語解説や演習問題を通した知識のアウトプットができる。

こちらも図解が豊富に掲載されているので、初心者でも学びやすい構成になっている。

なおMIXIは他にも様々な技術を学べる研修資料を公開しているので、確認してみてください。

https://zenn.dev/mixi/articles/2efdbeb0574906

## [Webブラウザを作ってみよう](https://browserbook.shift-js.info/)

https://browserbook.shift-js.info/

Webブラウザを実際に作りながら、ブラウザの基礎、DOM、レンダリングツリー、JavaScript、セキュリティの仕組みを学べる。

 Webの基本用語の整理から始まり、内部構造、実践演習と段階的に仕組みを学べる。

 ![スクリーンショット 2024-11-10 10.04.24.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/24f54e7b-36df-4a65-75e4-32ee721a393e.jpeg)

## [インターネット仕組み (総務省)](https://www.soumu.go.jp/main_sosiki/cybersecurity/kokumin/index.html)

https://www.soumu.go.jp/main_sosiki/cybersecurity/kokumin/index.html

総務省が公開しているインターネットの仕組み。

ホームページや電子メール、チャットボットなど幅広いWebサービスの仕組みが簡易的な言葉で解説されている。

## [DX白書 (IPA)](https://www.ipa.go.jp/publish/wp-dx/gmcbt8000000botk-att/000108041.pdf)

![スクリーンショット 2024-11-10 10.05.31.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/87c08660-617e-7f9e-d61a-cc91f3507cd2.jpeg)

国内産業におけるDXの取り組み取組状況から始まり、企業のDX戦略、デジタル時代の人材、DX実現に向けたITシステム開発手法と技術を学ぶことができる。

## 最後に

いかがだったでしょうか。

他にも様々な記事を出しているのであわせて読んでいただけると嬉しいです。

https://qiita.com/KNR109/items/ac51f7eeace9d1b7b81b

https://qiita.com/SMAC/items/e50c981e0518141be28f


https://qiita.com/SMAC/items/3b14e2e8f89a33c0f959
人材流出が止まらない理由を若手目線で考えてみる

# 人材流出が止まらない理由を若手目線で考えてみる

## 背景

新卒でSIerに入社して早くも4年が経とうとしています。

入社以来同じ部門に所属していましたが、この4年間で約10人の退職者を見送ってきました。この経験をもとに、若手の目線から「なぜ人材流出が止まらないのか」について考えてみようと思います。

今回この内容を書こうと考えたきっかけは、自分が「社内公募で異動しようか」と思ったことにあります。公募による異動を検討する中で、少し立ち止まってこの経験を言語化し、整理したいと考えました。

## 自己紹介

まず初めに、軽く自己紹介をしておこうと思います。

- 非情報系出身 (エクセルがちょっと使えるレベル、プログラミング未経験)
- 新卒で都内のSIerに入社し、Java研修がよくわからなかったためインフラエンジニアの道へ
- 現在はAWSを中心に各部門のインフラ構築支援や、生成AIを利用したサービス開発に従事

一般的な4年目の若手インフラエンジニアといった感じです。

## 人材流出の理由

ここでは、退職された方からお聞きした主な退職理由を記載します。本音では他にも理由があるかと思いますが、いくつか共通する要素があるようです。

- **給与**：転職先と比較して低い、労力に見合っていない
- **ワークライフバランス**：役職者が土日も仕事をしているのを見て、続けることに不安を感じた
- **成長機会**：実務で使わない資格を半強制的に目標に含められることが負担
- **評価**：査定基準が形式的で、努力が正当に反映されない
- **仕事内容**：同じ作業の繰り返しで、新しい技術に触れる機会が少ない

これらの理由を統合すると、以下の2点に集約されるのではないかと考えました。

1. **成長や自己実現への期待に応えられる環境が整備できていないこと**
2. **努力が正当に評価される環境が整備できていないこと**

### 1. 成長や自己実現への期待に応えられる環境が整備できていないこと

この点については、自分の同期も「クラウドの資格を取っても、クラウドの案件にアサインされないからほぼ無意味じゃん」と言っていたのを思い出しました。せっかくスキルを身につけても、手を上げても、実際にそのスキルを活かせる機会が与えられなければ意味がないのです。こうした若手が「サイレント退職ルート」に乗ってしまうのが、お決まりのパターンなのだと思います。

### 2. 努力が正当に評価される環境を整備できていないこと

こちらについても、先日あるイベントのコメントで「表彰されても会社がそのことを評価してくれない」という声があり、現実を目の当たりにしました。幸い、自分は多少評価されていると感じるのでまだ良いほうですが、表彰されても評価に反映されない会社が多いのかもしれません。正直、1の項目以上に、こちらのほうが人材流出につながるスピードが速いように感じます。


## 人材流出を止めるには

意外と基本的なことかもしれませんが、以下の点が重要だと思います。

- 被評価者に向き合い、評価すべきところをきちんと評価する（形式的な査定に留めない）
- 成長を実感できる機会を提供する
- 所属意識を軽視しない

一つずつ見ていきましょう。

### 1. 被評価者に向き合い、評価すべきところをきちんと評価する（形式的な査定に留めない）

多くの会社では年2回の査定評価のタイミングがありますが、評価者によっては一度に10名程度を評価することもあり、大変なイベントだと思います。私自身も被評価者として様々な評価者と話してきましたが、評価者によって評価基準や対応に大きな差があると感じることが多々ありました。

**【良かった評価者】**

- 今期の結果に対して納得できる理由と共に評価を示してくれる
- 今期の成果をもとに、「次にどのスキルを伸ばすべきか」「どの課題に取り組むべきか」を具体的に伝えてくれるため、次期へのモチベーションが向上する
- 現状の自分の位置づけやスキルを整理してくれ、進むべき方向や選択肢を提示してくれるため、将来のキャリアについて前向きなイメージを持てる
- 評価書の書き方（どう書けば適切に評価されやすいか）を指導してくれる

**【微妙だった評価者】**

- 形式的で事務的な評価で、フィードバックがない
- 評価がほぼ固定されており、事前に決まっているように感じられ、努力が反映されていない印象を受ける
- 次期の目標設定について全く会話がなく、成長の方向性が不透明になる

こうした事務的な対応が続くと、被評価者にとって「自分は評価されている」という実感が薄れ、モチベーションの低下につながる可能性があります。査定の際にどれだけ真摯に向き合ってくれるかは、被評価者にとって非常に重要で、モチベーションやキャリア形成に大きく影響します。きちんと向き合って評価する姿勢が必要だと感じます。

### 2. 成長を実感できる機会を提供する

この部分が非常に重要な要素だと考えています。成長機会が少ないと感じる社員は将来に疑問を持ち、離職の意志を強めることが多いため、具体的な成長機会の提供が重要です。

案件の中で成長してもらうことが主な育成とされていますが、本当に育成と呼べるのでしょうか？案件に丸投げしているようにしか思えませんし、そんな都合の良い案件が常にあるわけでもありません。

そのため、案件とは別に改善タスクを用意し、新しい技術領域について調査・検証・導入する機会を作るのが良いと思います。

実際に私が3年間お世話になった支援先では、案件とは別で新技術（生成AI、データ加工など）で既存の問題を解決できないかという取り組みを行っていました。この取り組みは個人の裁量が大きく、新技術に触れる機会があるため、知的好奇心が刺激され、成長も実感できる良い試みだったと今でも思います。

すべての会社でこのようにする必要はありませんが、私はこの活動のおかげで多くのことを学び、成長することができました。

### 3. 所属意識を軽視しない

私の場合は少し特殊かもしれませんが、入社以来ずっと別部門の支援を担当しています。

その結果、所属意識がほとんどない状態になりました。幸い、支援先の方から「その部門に居続ける意味ある？うちで一緒に仕事しない？」と声をかけられることもあり、改めて自分が今の部門に所属する意義に疑問を持つきっかけとなりました。

常駐して働いている方も、似たような経験をされたかもしれません。企業や部署に対する帰属意識を高めるためには、レクリエーションではなく、日々の業務を通じて「ここで働く意義」を感じられる仕組みが必要だと思います。この課題については、今後のキャリアの中で解決策を見つけていきたいと考えています。

## おわりに

ここまで、人材流出を防ぐために重要だと感じるポイントを挙げてきました。これらは私自身が感じた課題や、実際の現場で見てきた実例に基づいたものです。

人材流出を防ぐためには、単に制度や待遇を整えるだけでなく、社員一人ひとりが成長を実感し、自分の努力が正当に評価されていると感じられる環境を作ることが重要だと考えています。

この記事が、読んでくださった方々が現場での取り組みを見直すきっかけとなり、人材流出の歯止めにつながることを願っています。
【Playwright】API の Mock を導入する

# はじめに
この記事では、Playwright で API を Mock する方法を記載します。

https://playwright.dev/docs/mock

# 開発環境
開発環境は以下の通りです。

- Windows 11
- Next.js 14.2.13
- React 18.3.1
- TypeScript 5.6.3
- SWR 2.2.5
- Playwright 1.48.2

# テスト対象コード
ジョークを取得する API を実行して、その結果を表示するコードを実装します。
今回 API の呼び出しは fetch と SWR を利用しています。

https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API

https://swr.vercel.app/

```page.tsx
"use client";

import useSWR from "swr";

const fetcher = async (url: string) => {
  const res = await fetch(url);
  return await res.json();
};

export default function Page() {
  const { data } = useSWR<{
    id: number;
    type: string;
    setup: string;
    punchline: string;
  }>("https://official-joke-api.appspot.com/random_joke", fetcher);

  return (
    <div>
      <h3>{data?.type}</h3>
      <p>{data?.setup}</p>
      <p>{data?.punchline}</p>
    </div>
  );
}

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/20d26991-3125-8db9-509c-76a42f4c4a08.png)

# テストコードの実装
API を Mock して、その結果を確認するテストコードを実装します。
API のルーティングの Mock は [page.route](https://playwright.dev/docs/api/class-page#page-route) というメソッドを利用します。第一引数で Mock するルートを記載します。第二引数で、[fulfill](https://playwright.dev/docs/api/class-route#route-fulfill) というメソッドを利用してレスポンスを Mock します。

```page.spec.ts
import test, { expect } from "@playwright/test";

test("API response should be displayed as expected", async ({ page }) => {
  // Mock the api call before navigating
  await page.route(
    "https://official-joke-api.appspot.com/random_joke",
    async (route) => {
      const json = {
        id: 8,
        type: "general",
        setup: "How many lips does a flower have?",
        punchline: "Tulips",
      };
      await route.fulfill({ json });
    }
  );

  // Go to the page
  await page.goto("http://localhost:3000");

  // API response is visible
  await expect(page.getByRole("heading", { name: "general" })).toBeVisible();
  await expect(
    page.getByText("How many lips does a flower have?")
  ).toBeVisible();
  await expect(page.getByText("Tulips")).toBeVisible();
});

```

# 参考
- [fulfill](https://playwright.dev/docs/api/class-route#route-fulfill)
- [Mock APIs](https://playwright.dev/docs/mock)
- [page.route](https://playwright.dev/docs/api/class-page#page-route)
【Laravel/Breeze】仕組みまとめ

# はじめに
Laravel/Breezeを導入した際に、各ファイルの動きや認証の仕組みがわからなかったのでまとめてみました

**環境**
・Amazon Linux
・Laravel 11.9.2
・Laravel/Breeze 2.2.2


## Routeに対してログイン制限をかける
認証済みのユーザのみルートに通すときは、ルートミドルウェアという仕組みを使います
制限のかけ方は変わらず以下のように行います
```
Route::get('/flights', function () {
    // 認証済みユーザーのみがこのルートにアクセス可能
})->middleware('auth');
```
`Route::get()->midldeware(...);`のように普段のルート設定の後ろにmiddlewareメソッドを追加します
`Route::get()->midldeware(...)->midldeware(...);`というようにチェーンすることも可能

この設定により該当ルートに未認証のユーザが入ってきた場合は、ログインページにリダイレクトされ、ログイン成功後該当ルートのページを表示する動きとなります

:::note info
Laravel11から仕様が少し変更されています
ミドルウェアの設定をapp/Http/Middlewareでしていましたが、bootstrap/app.phpでの設定に変わりました
:::

## ログイン情報の取得
以下で取ってこれます
```
// Authは Illuminate\Support\Facades\Auth
Auth::user();
```
このコードでユーザ情報をまとめて取ることができます
あとはここから必要な情報を取得してくるイメージです

例えばユーザのメールアドレスを取得したいときはこう
```
userMail = Auth::user()->email;
```
SwiftUiデフォルトの戻るボタンを非表示にする方法

デフォルトで画面を遷移した時に戻るボタンが表示されますが、非表示にしたい時もあると思います。

```.swift
var body: some View {
    Text("戻る非表示画面")
        .navigationBarBackButtonHidden(true)
}
```

実装方法は`.navigationBarBackButtonHidden(true)`を追加するだけです。
![Simulator Screenshot - iPhone 16 Pro - 2024-11-10 at 09.42.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274615/0463e5b3-5aad-6cc2-9847-64d7cbdd1376.png)
Chakra UI v3でextendThemeが使用できない問題とその解決策

## エラー発生経緯
Chakra UIを使用してReactアプリケーションを開発している際に、extendTheme関数を使用してテーマをカスタマイズしようとしたところ、「Module '"@chakra-ui/react"' has no exported member 'extendTheme'」というエラーが発生。本記事では、このエラーの原因とについてまとめます。

## 対応したこと
・Chckra UIのバージョンを確認と最新バージョンのインストール
```react
npm list @chakra-ui/react
npm install @chakra-ui/react@latest
```

・バージョンを指定してインストール
※今回はこちらで解決
```react
npm install @chakra-ui/react@2.8.0
```

## 原因分析
当初は最新版をインストールしており、そちらは3.xだったため3.xとバージョン2.xではエクスポート方法が変わった可能性あり。
解決策としてはChakra UIのバージョンを下げることあるいはv3の変更に沿った書き方をする。

・Chakra UI 公式サイト v2 
https://v2.chakra-ui.com/docs/styled-system/customize-theme#theme-extension-withdefaultcolorscheme

```react
import { extendTheme } from '@chakra-ui/react';
```

・Chakra UI 公式サイト v3 
https://next.chakra-ui.com/docs/components/theme

→v3のドキュメントを見る限り、下記に変更
```react
import { Theme } from '@chakra-ui/react';
```

## 今後の教訓
・ライブラリのバージョンアップ時の変更点を確認する
・公式ドキュメントをこまめに確認する。

## まとめ
今回は、Chakra UIのバージョンアップに伴いextendThemeが使用できなくなったという問題を解決。バージョンアップに伴う変更点には注意し、公式ドキュメントを参考に開発を進めることが重要だとより感じました。
AtCoder ABC 379 C - Sowing Stones

コンテスト中に解けなかった問題を、自分的にわかりやすいコーディングで書き直したメモです。

トライアル＆エラーで問題切り分けて、やっと何故通せなかったかわかった。

これ300点問題にするなら、サンプルにソートされていないパターン入れておいてくれぃ(;´･ω･)

```cpp:Main.cpp
#include <bits/stdc++.h>
using ll = long long;
using namespace std;
struct cell
{
	ll index;
	ll count;
};

// 石が移動可能な空マスが足りているかチェックする
bool CanComplete( const vector<cell> & vecCells, ll N )
{
	ll r = N;			// 検証済みの終端
	ll emptyCount = 0;	// 検証中の空マスの数

	// 終端（右）からチェック
	for( auto itr = vecCells.rbegin(); itr != vecCells.rend(); ++itr)
	{
		// 終端からここまでの空マスを数える
		emptyCount += r - itr->index;
		// 今のマスで余った石の移動先の空マスが足りているか確認
		if( itr->count - emptyCount > 1 )
		{
			return false;	// 不可能
		}
		// 今のマスに1個残しておけば残りは移動して空白のマスを埋められる
		emptyCount -= (itr->count)-1;
		r = itr->index - 1;
	}

	return true;	// 可能
}


int main( void )
{
	// 入力
	ll N, M;
	cin >> N >> M;

	// 石の合計数
	ll stoneCount = 0;
	// マスのindex値をスコアとみなした場合の初期状態のスコア
	ll scoreInit = 0;
	// すべてのマスに石が１個ずつ入っていた場合のスコア
	//   遷移が可能な場合は、この差分が答え
	ll scoreComplete = ( 1 + N ) * N / 2;

	vector<cell> vecCells(M+1);	//
	for( ll i = 1; i <= M; ++i)
	{
		cin >> vecCells[i].index;
	}
	for( ll i = 1; i <= M; ++i)
	{
		cin >> vecCells[i].count;
		stoneCount += vecCells[i].count;
		scoreInit += vecCells[i].count * vecCells[i].index;
	}

	// 石の合計数とマスの数が合わなかったらそもそも不可能なのでここで終了
	if( stoneCount != N )
	{
		cout << "-1" << endl;
		return 0;
	}

	// 入力がソートされていないらしいので（#^ω^） index の昇順にしておく
	 sort( vecCells.begin(), vecCells.end(),
	 			[]( const cell & a, const cell & b){ return a.index < b.index; });

	// 始点のマスに石がなかったらそもそも不可能なのでここで終了
	if( vecCells[1].index != 1)
	{
		cout << "-1" << endl;
		return 0;
	}

	// 右に移動するだけで完了状態に遷移できるかチェック
	ll result;
	if( CanComplete( vecCells, N ))
	{
		// 遷移が可能な場合はこれで求められる
		result = scoreComplete - scoreInit;
	}
	else
	{
		result = -1;
	}
	cout << result << endl;

	return 0;
}
```
Spring Boot @Component @Profileについて

## 依存注入について
まず、依存とはあるオブジェクトや機能が動作するために
別のオブジェクトや機能が必要である状態を指します。
(あるクラスや、メソッドが他のクラスやメソッドに頼って動作すること)

次の例では、``MyService``がデータを取得するために``MyRepository``の機能を使っています。
そのため、``MyService``は``MyRepository``に依存していると言えます。
``` kotlin
@Service
class MyService(private val myRepository: MyRepository) {
    fun getData(): List<MyData> {
        return myRepository.findAll()  // MyRepositoryの機能を使ってデータを取得
    }
}
```
このような依存関係をスムーズに管理するために、
Springの「依存注入(DI)」機能が使われます。

依存注入を使うことで、``MyService``は自分で``MyRepository``を作るのではなく、Springが生成した
``MyRepository``のインスタンスを自動的に受け取ることができます。

---

**依存**：``依存 = 注入されるオブジェクト``と解釈できます。(ここでは``MyRepository``)
**依存注入**：``依存注入 = オブジェクトを注入すること``という意味になります。
(``MyRepository``を``MyService``に渡すこと)

## @Component
@Componentアノテーションは、
「注入できるObjectがここにあるよ」という宣言です。(あるある宣言)

@Componentアノテーションが付いたクラスは、
Springによって管理され、依存注入される対象になります。
そして、Springの魔法によって自動的に注入されます。 
注入するところは、型を見て決めています。

---

次の例では、``fugaService``という変数を作成し、
そのタイプは``FugaService``と宣言しています。

ここでは、「``fugaService``変数に``FugaService``型のインスタンス(オブジェクト)をください」
というコードになっています。

Springはコンテナに登録されている``FugaService``のインスタンスを自動的に
注入してくれます。

```kotlin
@Autowired
private lateinit var fugaService : FugaService
```
（ちなみに、@Autowiredは依存を注入してほしい場所に書くため、くれくれ宣言）


## @Profile
@Profileは、
特定の環境のみで使用できるようにするためのアノテーションです。

次の例では、@Componentで「注入するObjectです」という定義をし、
@Profileで``local``環境と``e2e``環境でのみ実行するという設定を行なっています。

このコードの後に続く、classは``local``,``e2e``環境の時のみ依存注入され実行されます。

```kotlin
@Component
@Profile(value = ["local", "e2e"])
class HogeHoge() {
}
```
Djangoを使って簡単なwebアプリケーションを作成する

# Djangoとは
Pythonで実装されたwebアプリケーションのフレームワーク
オープンソースのフレームワークで、コンテンツの管理システム,wiki,SNSなどのwebアプリケーションで扱われている

# 環境構築
今回は windows上のVScodeターミナル(powershell)で構築を行った
venvを使用した仮想環境上でDjangoを追加する

1. pythonの導入
   今回はDjangoがメインとなるためpythonの導入方法は省略する 
   自身が使用した環境は Python 3.12.5
2. powershellの実行ポリシーを一時的に変更する
   ```
   Set-ExecutionPolicy RemoteSigned -Scope Process
   ```
   これを行わないとvenvのアクティブに失敗する
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3895022/4a06822b-85b6-ca60-58c0-adaf892fbbc0.png)
3. pythonのvenv機能で仮想環境を作成する
   1. ディレクトリを作成
   2. venvで仮想環境を作成
   3. venvのアクティベートを行う
   ```
   D:\> mkdir webapp
   D:\> cd webapp
   D:\webapp> python -m venv webapp
   D:\webapp> .\webapp\Scripts\activate
   ```
4. Djangoをインストール
   ```
   D:\webapp> pip install django
   ```
5. プロジェクトの作成
   ```
   D:\webapp> django-admin startproject webproj
   ```
   プロジェクトのフォルダとmanage.pyファイルが作成されていることを確認する
   manage.pyはプロジェクトの管理を行うときに使用するファイル
   サーバーを立ち上げたり管理情報を編集します。
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3895022/f40a0af2-259b-b85e-b025-9e07295c531d.png)
6. サーバーを開始する
   ```
   D:\webapp> python webproj/manage.py runserver
   ```
   サーバー開始後 http://127.0.0.1:8000/ にアクセスし、起動していることを確認する
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3895022/9587ba54-a265-1e11-4ab0-26714eff244b.png)
   Ctrl + C でサーバーを停止できる

※サーバー起動時に以下の警告が出てきたら記載通りにマイグレーションを実施する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3895022/cb848d20-61bc-9c26-2bc1-ea691f6e0e2e.png)
```
D:\webapp> python webproj/manage.py migrate
```

# webアプリを作成する
作成した環境にwebアプリケーションを作成する

1. webアプリケーションの作成
   webprojディレクトリに入り、アプリケーションを作成する
   ```
   D:\webapp> cd .\webproj\
   D:\webapp\webproj> python manage.py startapp sample
   ```
   以下の構成で作成されていることを確認する
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3895022/0ede318b-b9b1-e49e-f014-c20fd95fc0f1.png)
2. viewの作成を行う
   views.pyをvscodeなどで開いて以下を入力
   ```python
   from django.http import HttpResponse

   def index(request):
       return HttpResponse("Hello, world.")
   ```
3. アプリのURLの設定を行う
   url設定ファイルを作成する
   ```
   D:\webapp\webproj\sample> code urls.py
   ```
   ```python
   from django.urls import path
   
   from . import views
   
   urlpatterns = [
       path("", views.index, name="index"),
   ]
   ```
4. プロジェクトのurl設定を行う
   ```
   D:\webapp\webproj\sample> cd ..\webproj\
   ```
   ディレクトリ構成
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3895022/88222e1f-084b-6a27-0edc-047da3e43d7d.png)
   urls.pyを編集する
   ```python
   from django.contrib import admin
   from django.urls import include, path
   
   urlpatterns = [
       path("sample/", include("sample.urls")),
       path('admin/', admin.site.urls),
   ]
   ```
5. サーバーを起動する
   ```
   D:\webapp\webproj> python manage.py runserver
   ```
   http://127.0.0.1:8000/sample/ にアクセスして以下のページが出力されればOK
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3895022/70e15e5a-5b28-79bc-ac6c-36e3ae12e233.png)

# 参考ページ
https://docs.djangoproject.com/ja/5.1/intro/tutorial01/
cscの作法 その529

# 概要
cscの作法、調べてみた。
練習問題やってみた。



# 練習問題
webbrowserを使え。

# 方針
- 画像ビューワーを作る。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/b5be7af8-1e27-711a-69d6-de8a16c621b5.png)

# サンプルコード

```
using System;
using System.Windows.Forms;
using System.Drawing;

class form1: Form {
	TextBox bo1;
	WebBrowser wb0;
	form1() {
		Text = "WebBrowser";
		ClientSize = new Size(720, 300);
		bo1 = new TextBox();
		bo1.Location = new Point(10, 10);
		bo1.Text = "data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==";
		bo1.Size = new Size(600, 20);
		Controls.Add(bo1);
		Button btn1 = new Button();
		btn1.Location = new Point(630, 10);
		btn1.Text = "run";
		btn1.Click += btn1_Click;
		Controls.AddRange(new Control[] {
			btn1
		});
		wb0 = new WebBrowser();
		wb0.Location = new Point(10, 40);
		wb0.Width = 480;
		wb0.Height = 240;
		wb0.ScriptErrorsSuppressed = true;
		Controls.AddRange(new Control[] {
			wb0
		});
	}
	void btn1_Click(object sender, System.EventArgs e) {
		wb0.DocumentText = "<HTML><BODY><img src='" + bo1.Text + "' ></BODY></HTML>";
	}
	[STAThread]
	public static void Main() {
		Application.Run(new form1());
	}
}
```


以上
cscの作法 その528

# 概要
cscの作法、調べてみた。
練習問題やってみた。

# 練習問題
webbrowserを使え。

# 方針
- ブラウザ作る。


# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/87faf7b8-35cf-609b-ac22-b33e10d73d3d.png)


# サンプルコード

```
using System;
using System.Windows.Forms;
using System.Drawing;

class form1: Form {
	TextBox bo1;
	WebBrowser wb0;
	form1() {
		Text = "WebBrowser";
		ClientSize = new Size(700, 600);
		bo1 = new TextBox();
		bo1.Location = new Point(10, 10);
		bo1.Text = "https://qiita.com";
		bo1.Size = new Size(300, 20);
		Controls.Add(bo1);
		Button btn1 = new Button();
		btn1.Location = new Point(340, 10);
		btn1.Text = "run";
		btn1.Click += btn1_Click;
		Controls.AddRange(new Control[] {
			btn1
		});
		wb0 = new WebBrowser();
		wb0.Location = new Point(10, 40);
		wb0.Width = 680;
		wb0.Height = 540;
		wb0.ScriptErrorsSuppressed = true;
		Controls.AddRange(new Control[] {
			wb0
		});
	}
	void btn1_Click(object sender, System.EventArgs e) {
		wb0.Navigate(bo1.Text);
	}
	[STAThread]
	public static void Main() {
		Application.Run(new form1());
	}
}
```


以上
RubyのアプリケーションをVercelで動かす

## 概要

Vercelで[Rubyのランタイム](https://vercel.com/docs/functions/runtimes/ruby)もサポートされているそうなので[Sinatra](https://github.com/sinatra/sinatra)で作成したTodoリストアプリを動かしてみました。

実際のコードは下記になります。


https://github.com/K-Sato1995/vercel-ruby-runtime

※本記事はあくまで試してみたレベルですのでProdでの使用等々は自身のご判断でお願いします


![todolist.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258219/745723ae-c3c6-bdb8-d93a-d7ce0088ff87.gif)



## 前提(VercelのRuby Runtime)

[VercelのRuby Runtime](https://vercel.com/docs/functions/runtimes/ruby)の説明をみると下記のようにリクエストを受け取ってレスポンスを返すとのことでした。
ので、このリクエストをSinatraのアプリケーションに渡すことで動かすようにします。

```ruby:api/index.rb
require 'cowsay'
 
Handler = Proc.new do |request, response|
  name = request.query['name'] || 'World'
 
  response.status = 200
  response['Content-Type'] = 'text/text; charset=utf-8'
  response.body = Cowsay.say("Hello #{name}", 'cow')
end
```

## Sinatraアプリケーションへリクエストを渡す

Sinatraは、Ruby on Railsと同様に[Rack](https://github.com/rack/rack)を基盤に動いているので、受け取ったrequestをrackのインターフェースに合わせてSinatraのアプリケーションに渡してあげます。

:::message
※もっと良い感じに詰められるのでしょうが、最低限動くとこまで見たかったのでこうなっています
:::

```ruby
require_relative '../app/main'  

Handler = Proc.new do |request, response|
  app = MyApp.new
  env = {
    'REQUEST_METHOD' => request.request_method,
    'PATH_INFO' => request.path,
    'QUERY_STRING' => request.query_string,
    'rack.input' => StringIO.new(request.body || "")
  }

  status, headers, body = app.call(env)

  response.status = status
  headers.each { |key, value| response[key] = value }

  response.body = body.join
end
```

↑では簡易的に必要そうなものだけ詰めましたが、[Rack](https://github.com/rack/rack)のenvに関しての詳細は下記のSpecドキュメントで確認いただけます。

https://github.com/rack/rack/blob/main/SPEC.rdoc#label-The+Environment

Sinatraのcallメソッド

https://github.com/sinatra/sinatra/blob/7a5c499f0e6099137fd1cb4ee20178af2a125d47/lib/sinatra/base.rb#L1501-L1503

参考にさせて頂いた記事

https://qiita.com/junjis0203/items/8dfd506d0f66455e589e

## `/`ベースのエンドポイントにする

[verce.json](https://vercel.com/docs/projects/project-configuration)で`/`をベースにしたエンドポイントを構築します。


```json
{
    "version": 2,
    "builds": [
      { "src": "api/index.rb", "use": "@vercel/ruby" }
    ],
    "routes": [
      { "src": "/(.*)", "dest": "/api/index.rb" }
    ]
  }
```


## アプリケーション層での処理

ここまでできれば普通のSinatraアプリと変わらないのでドキュメントを参考にGET/POSTのエンドポイントをそれぞれ実装してみました。

https://sinatrarb.com/intro.html

```ruby:app/main.rb
require 'sinatra/base'
require 'dotenv/load'
require_relative './models/todo'

class MyApp < Sinatra::Base
  get '/' do
    todos = Todo.all
  
    erb :template, locals: { todos: todos }
  end

  post '/add_todo' do
    text = params['text']
    Todo.create(text)
    erb :success
  end
end
```

## その他

次はRailsのアプリケーションを動かしてみたいです。
【C言語】C言語基本①　関数宣言　関数のプロトタイプ【低レイヤー】

低レイヤー層の勉強のためにC言語の学習を始めたので、他言語との違いなど基本的な仕様をメモ。
今回は関数の宣言。何かご指摘あれば是非お願いいたします。

# ポイント　関数宣言とプロトタイプ
まず前提として、Cでは関数を呼び出す場合、宣言済みの関数しか実行できない。<br>その為、以下の２通りの方法で宣言する。

① 呼び出す箇所より前（main関数の上など）で宣言しておく。
```c
#include <stdio.h>

// 関数の宣言
int sum(int a, int b){
    return a + b;
}

int main(void){
    // 使用部分
    int ans = sum(10, 11);
    
    printf("%d", ans);

    return 0;
}
```
②プログラムの冒頭に関数の概要＝<b>プロトタイプ</b>を宣言しておき、その後関数の詳細な定義をする。
```c
#include <stdio.h>

//関数のプロトタイプ
int sum(int, int); // 引数は(int a, int b)等でも可

int main(void){

    // 使用部分
    int ans = sum(10, 11); 
    
    printf("%d", ans);
    return 0;
}

// 関数の詳細な定義
int sum (int a, int b){
    return a + b;
}

```
<br>
それぞれのメリット・デメリット<br>
①プロトタイプ省略<br>
　　　○　プロトタイプを書かなくてよいので記述量が少ない。<br>
　　　×　関数から別の関数を呼び出す場合、その宣言の順番を気をつけないといけない。<br>
　　　　　（※ただし言語規格のバージョンやコンパイラによる模様。C99だとエラー？）<br>
<br>
②プロトタイプ記述<br>
　　　○　関数関数の宣言の順番を気にせず記述できる。<br>
　　　×　記述量が増える。<br>

シンプルなコードの場合は①で良いのかも知れませんが、基本的には②の方がよさそうです。

# その他詳細・今後の学習課題

- プロトタイプの宣言をしていない場合でも、暗黙のうちにプロトタイプが宣言されている。
(参考：https://zenn.dev/kaityo256/articles/position_of_functions )
-  ABIとISA（機械語のルール）
    - ISA：Instruction Set Architecture。機械語のルール（いわゆる「アーキテクチャ」ごとの違い）。
    - ABI：Application Binary Interface。C言語の機能を機械語でどのように実現するかの規格。
（参考：https://qiita.com/qnighy/items/be04cfe57f8874121e76 ）


# 参考文献・サイト
- 新・明解C言語入門編（柴田望洋 SBクリエイティブ　2014）
- 「自作関数を作る」苦しんで覚えるC言語様(https://9cguide.appspot.com/11-01.html)
- 「関数の定義位置により結果が変わるコード」ロボ太様(https://zenn.dev/kaityo256/articles/position_of_functions )
- 「Cの可変長引数とABIの奇妙な関係」@qnighy様（https://qiita.com/qnighy/items/be04cfe57f8874121e76%E3%80%80 ）
休憩催促通知機能を作ってみた

# 休憩催促通知

## ・はじめに
日常生活の中で仕事や家で長時間PCと睨めっこをしている人は多いだろう。長時間画面を見続けると目も疲れるし体もずっと固定されたままなので疲労が溜まり生活に支障が出てしまう。そこで私は長時間使用し続けると休憩の催促がくる機能を作成した。

## 実行画面ショット
![chacha.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3658530/a60a6a48-edfc-9b6c-ab3e-6a97de381b00.png)



## ・構成

このプロジェクトは2つのJavaファイルから構成される。

1. **sendNotification.java**: 通知を表示するためのクラス。
2. **timerPreference.java**: 指定された時間後に通知表示を発火するクラス。


## ・ファイル説明

### sendNotification.java

主な機能

- **notificationDisplay()**: 
  - システムトレイにアイコンを表示し、メッセージを通知。
  - メッセージには、休憩を促すテキストとアイコンを盛り込んだ。
  - アイコン画像は、プロジェクトのルートディレクトリにある `P1180131.jpg` 私の愛犬である。
  
- **displayImageNotification()**: 
  - 画像付きのポップアップ通知を表示。
  - ポップアップには、アイコンとメッセージが含まれる。
### ソースコード
```sendNotification.java
import java.awt.*;
import javax.swing.*;

public class sendNotification {
    // 通知を表示するための処理
    public static void notificationDisplay() {
        // SystemTrayのインスタンスを取得
        SystemTray tray = SystemTray.getSystemTray();
        // アイコンの画像を設定
        Image image = Toolkit.getDefaultToolkit().getImage("P1180131.jpg");
        // トレイアイコンを生成（リマインダーとして）
        TrayIcon trayIcon = new TrayIcon(image, "リマインダー");
        trayIcon.setImageAutoSize(true); // アイコンを自動的にリサイズ
        // システムトレイにトレイアイコンを追加
        try {
            tray.add(trayIcon);
        } catch (AWTException e) {
            System.err.println("トレイアイコンの追加に失敗しました。");
            return;
        }
        // 通知の表示
        trayIcon.displayMessage("休憩の時間です！", "画面の見過ぎですよあなた。", TrayIcon.MessageType.INFO);
        // 画像付きの通知を別のウィンドウで表示
        displayImageNotification();
        System.exit(0);
        
    }

    // 画像付きの通知を表示するメソッド
    public static void displayImageNotification() {
        // 画像を含むラベルを作成
        ImageIcon icon = new ImageIcon("P1180131.jpg"); // 画像を設定
        JLabel label = new JLabel("休憩の時間です！", icon, JLabel.CENTER); // 画像とテキストを設定

        //画像付きのメッセージを表示
        JOptionPane.showMessageDialog(null, label, "休憩催促通知", JOptionPane.INFORMATION_MESSAGE);
    }
    public static void main(String[] args) {
        // 通知を表示するメソッド呼び出し
        notificationDisplay();
    }
}
```

### timerPreference.java

このクラスは、指定された時間(タイマー)に通知を表示するためのタイマーを実装。

- **main()**:
  - 1時間(3600000秒)後に `sendNotification.notificationDisplay()` メソッドを呼び出す。

```timerPreference.java
import java.util.Timer;
import java.util.TimerTask;;

public class timerPreference {
    public static void main(String[] args) {
        Timer timer = new Timer();
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                sendNotification.notificationDisplay();
            }
        };
        timer.schedule(task, 3600000);
    }
    
}
```
  
## ・使用方法

1. プロジェクトディレクトリに自分の好きな画像をセット。


#### 実行コマンド
   
   javac sendNotification.java<br>timerPreference.java
Project Wakefieldをビルドしてみる

[前回の記事](https://qiita.com/hatano/items/aac635d6ef2f5af4e84f)ではSDKMAN!を用いてJetBrans Runtimeでjdk21を選択するとWLToolkitで動かすことができるという話をしました。

今回は実際にWakefieldのリポジトリからWLToolkitをビルドする手順をまとめました。Ubuntuでの手順になります。

まず[wakefieldのリポジトリ](https://github.com/openjdk/wakefield)をクローンしてきます。

```
% git clone https://github.com/openjdk/wakefield.git
```

ブランチとして[jdk21.0.1-wayland](https://github.com/openjdk/wakefield/tree/jdk21.0.1-wayland)を選択します。

```
% git checkout -b jdk21.0.1-wayland origin/jdk21.0.1-wayland
```

この状態でビルドするとUbuntuの場合`wayland-client.h`がなくてビルドに失敗しますので、

```
% sudo apt install libwayland-dev
```

を実行します。

そして、configure、makeと進みます。`fish`環境なので`./configure`では通りませんでした。そこで

```
% bash ./configure
```

を実施します。続いて

```
% make
```

（もしかすると`make clean`を先に実行する必要があるかもしれません。）

これで`./build/linux-x86_64-server-release/jdk`の下にjdkが構築されます。

```
% sdk install java wakefield1109 ./build/linuxx86_64-server-release/jdk
% sdk use java wakefield1109
```

とすれば準備完了です。

```
% java -version
openjdk version "21.0.1-internal" 2023-10-17
OpenJDK Runtime Environment (build 21.0.1-internal-adhoc.hatano.wakefield)
OpenJDK 64-Bit Server VM (build 21.0.1-internal-adhoc.hatano.wakefield, mixed mode)
```

と表示されればOK。

```
% java -Dawt.toolkit.name=WLToolkit components.TreeIconDemo2 &
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21571/38de3e58-ab1a-f2b3-f897-d99c80da0478.png)

例によってXwaylandの結果と比べてみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21571/b35c7bc9-8902-0b68-8670-9b5aef457c83.png)

さて、WLToolkitの完成はいつになるのでしょうね…。
ABC379回答メモ

# 0.はじめに
　停滞が続いている今日この頃望んだAtcoder。
　C問題にてこずりつつなんとか解いてDにうつったら
　Dの方がカンタンだったパターン。
　とはいえ、久々にA~Dまでとけ、レートも+39と久々にアップしました。


# 1.A - Cyclic
　入力を文字列として受け取り問題に合わせてスライスしてくっつけて表示。

　https://atcoder.jp/contests/abc379/submissions/59568414
　

# 2.B - Strawberries
　最初は今一イチゴを食べると歯がなくなるというシチュエーションが
　しっくりこず、戸惑いましたが、まぁいつもの事なので・・・。
　まず、回答用変数ansとOの連続数カウント用変数oを0で初期化。
　文字列を先頭から見ていき、以下を繰り返し
　　・"O"なら、oに1加算、それ以外ならoに0をセット
　　・oがKに達したらansに１を加算してoに0をセット
　最後にansを出力して終了

　https://atcoder.jp/contests/abc379/submissions/59573922


# 3.C -  Sowing Stones
　最初は制約大きいなと思いつつ、ささっと10分くらいで回答提出
　あまり見ないメモリエラーにTLEとさんざんな結果で、Cにしては
　色々と工夫しないといけない気配。
　【最初の考え】
　　・マスに1個ずつセットするという前提からすると
　　　単純に1つ目のマスからマスに1個残して他を次のマスに
　　　移動していくことですべてのマスを1にでき、最小移動回数となる。

　　1.リストPを値0×(N+1)で初期化、ansを0で初期化
　　2.リストA、Bを読み石の初期配置を、Pにセット
　　3.１～Nまで、iを回し以下処理
　　　-1.P[i]が0なら-1を出力して終了
　　　-2.P[i]が1以上なら以下処理
　　　　-1.P[i]-1をP[i+1]セット
　　　　-2.ansにP[i]-1を加算
　　4.最後にP[N]が1ならansを、それ以外なら-1出力して終了

　　Nが大きいと、2)でメモリーエラーとなってしまいました。
　　他にもREとなってましたが、まぁどちらにしてもダメなので試行錯誤。
　　特に、リストPを用意しないでも、次に繰り越す石を保持する方法で考えましたが
　　それでも、上記3）のような繰り返しをするとTLEになることが分かりました。

　【最終的な考え】
　　＜石の配置が条件を満たすかの確認＞
　　・初期の石配置で1マス目に石が入っていないと満たさない
　　・初期位置に石が入っているマスを順にみていき、前のマスから
　　　次のマスまでのマス数が前のマスに入っている石数より小さければ条件を満たさない。
　　・上記を満たしたうえで、初期配置の石数がマス数と一致すれば条件を満たす
　　＜石の移動数計算＞
　　・前のマスに入っている石数をＰ、前のマスから次のマスまでのマス数をｎとしたばあい
　　　（Ｐ＊ｎ）-（ｎ×（ｎ+1）/2）
　　　（前のマスから次のマスまですべての石を動かす場合の数から
　　　　1個ずつ動かす数が減る場合の減る数をマイナスする）

　さらに、最後に石が入ったマスがＮマス目の場合と、そうでない場合を分けて
　計算したりと、いろいろてこずりつつ、最後はＡＣとなりました。

　https://atcoder.jp/contests/abc379/submissions/59612244


# 4.D - Home Garden
　ちらっとみて時間かかりそうなので、Ｃより先にやることは避けましたが
　実際やってみたら13分で終わったので、先にやっとけばもう少し順位上がったかなと
　思わなくもなかったです。

　【実装】
　　1.Qをインプット
　　2.デキューをインポートし、変数qをデキューで定義
　　　qには、種を植えた日付を格納
　　3.変数Dを0で初期化
　　　Dは経過日数をセット
　　4.以下Qの数だけ繰り返し
　　　-1.リストAをインプット
　　　-2.A[0]が1の場合qにDを追加
　　　-3.A[0]が2の場合DにA[1]を加算
　　　-4.A[0]が3の場合
　　　　-1.CにA[1]をセット、flgに1をセット、ansに0をセット
　　　　-2.以下flg＝１＆ｑに値が入っている間繰り返し
　　　　　-1.Ｐにｑの左値を取り出し（一番昔に種を植えた日）
　　　　　-2.D-PがC以上の時（種を植えてから規定日数経過していた場合）ansに1加算
　　　　　-3.D-PがCより小さい時（種を植えてから規定日数経過していない場合）qの左側にPを追加
　　　　　-4.flgを0に変更
　　　　-3.ansを出力

　デキューのおかげですっきり解けました。

　https://atcoder.jp/contests/abc379/submissions/59618515


以上
Dev Containersで爆速C++環境構築

:::note info
### 要約
1. 用意するもの：VScode、Docker
2. VSCodeでDev Containers 拡張機能をインストール
3. 検索窓から、`>Dev Containers: Try...`を実行して、環境構築したい言語を選択
4. Enjoy!
:::



# はじめに

C++の学習をしていて、実行環境が必要になった。
コンテナ型を用いた環境構築には
- どのOSでも挙動を統一できる
- OS本体を汚さずに済む
- 仮想化の中では軽量
- イメージサイズが小さい

という利点があるそうなので、使ってみることにした。

※初学者なので、つたない部分があるが、そこは大目に見てほしい。

# 方法
#### 必要なソフト
- VSCode
- Docker Desktop (CEだとTry...は動かない?[*])
- (WindowsならWSL2)


1. VSCodeの拡張機能タブで、Dev Containers(またはRemote Developmentバンドル)をインストール
2. F1(検索ボックスに`>`を入れる) -> Dev Containers: Try...を実行
3. C++を選択
4. 1~2分ほどで2つのイメージががビルドされ、VSCodeからアクセスできる


# その他
### 書式
設定(Ctrl + ,)から
- Clang_format_fallback Style：好きなものを選択
- Format On Paste, Format On Save：有効

### 各種ツールのインストール
定番ツールはF1 -> DevContainers: Configure Container Features...でインストールできる
Dockfile、docker-compose.yml、devcontainers.jsonでコマンドを動かすこともできる
devcontainers.jsonでpostStartCommandを指定すると、更新するたびにビルドをしなくて済むので良いと思った
拡張機能は右クリックからdevcontainers.jsonに追加することで、イメージをビルドするときも自動でインストールされる。

### デバッグオプションの変更
```diff_javascript:tasks.json
{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Build Main",
            "type": "cppbuild",
            "command": "g++",
+            "args": [
+              "-g",
+              "${workspaceFolder}/*.cpp", 
+              "-o",
+              "${workspaceFolder}/main.out"
+            ],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        }
    ]
}
```

感想...異なるPCで同じ実行環境を用意できて、メインPCと依存関係もないので、保守性が高いと感じました。
今回は作業フォルダをすべてvolumeイメージにしてマウントする方法でしたが、ほかにもメインPCのフォルダをbindマウントする方法もあり、そちらも試してみたいです。

# 参考
複数ファイルからなるC++プログラムをVSCodeで実行する手順の備忘録
https://terumikanblog.com/vscode/

[*]: https://qiita.com/ain1084/items/6cb6d82852c91416ec0e#dev-container-%E3%81%AE%E8%BF%BD%E5%8A%A0
【Android】Obsidianで日本語が太文字にならない件の解決策

## 事象
Obsidian上で日本語を太文字にしようとしても装飾なしの状態で表示される。
アルファベット表記の場合は問題なし。
【例】
入力：
\*\*Thank you\*\*
\*\*ありがとう\*\*

表示：
**Thank You**
ありがとう

## 解決策（2024/11/10現在）
#### 1.以下のフォルダを作成する
各自で設定したObsidianフォルダ > .obsidian > snippets

#### 2.snippetsフォルダの中に適当なCSSファイルを作成する

#### 3.Obsidianアプリの"設定 > 外観 > CSSスニペット"　にある作成したCSSファイルのトグルをオンにする
![Annotium1731209979.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534182/291cd202-42cf-5c51-ee8d-1870261e2d53.jpeg)

#### 4.適当なテキストエディタで作成したCSSファイルに以下を追記する

```css
*{
--bold-modifier : 300;
}
```
AtCoder ABC 379 D - Home Garden

コンテスト中に解けなかった問題を、自分的にわかりやすいコーディングで書き直したメモです。

（追記）投稿時に制約を勘違いしてました。これ、ACにはなってるけど、本当はTLEになるべきなんじゃないかなぁ‥‥

```cpp:Main.cpp
#include <bits/stdc++.h>
using ll = long long;
using namespace std;

int main( void )
{
	// 入力
	ll Q;
	cin >> Q;

	// プライオリティキューを 2 面用意しておく
	priority_queue<ll> queA;
	priority_queue<ll> queB;
	ll switchQue = 0;

	for( ll i = 0; i < Q; ++i)
	{
		int n;
		cin >> n;

		if( n == 1)
		{
			priority_queue<ll> & nowQue = (switchQue % 2)? queA : queB;
			nowQue.push(0);
		}
		else if( n == 2)
		{
			ll T;
			cin >> T;
			priority_queue<ll> & nowQue = (switchQue % 2)? queA : queB;
			priority_queue<ll> & altQue = (switchQue % 2)? queB : queA;

			while( ! nowQue.empty())
			{
				ll tmp = nowQue.top();
				altQue.push( tmp + T );
				nowQue.pop();
			}
			++switchQue;
		}
		else
		{
			ll H;
			cin >> H;
			priority_queue<ll> & nowQue = (switchQue % 2)? queA : queB;
			ll result = 0;
			while( ! nowQue.empty())
			{
				ll tmp = nowQue.top();
				if( tmp >= H)
				{
					nowQue.pop();
					++result;
				}
				else
				{
					break;
				}
			}
			cout << result << endl;
		}
	}

	return 0;
}
```
Excelにみる計算誤差とIEEE仕様と工夫について

エクセルで次の計算式をさせると、正しくない結果を出します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374317/a9cc6416-ac0b-546d-1b42-92bf7890155e.png)


エクセル97のような古いバージョンだと、0.1 + 0.1 + 0.1 程度の書き方でも 0.3 じゃない、となっていたと思います。
この 0.3 にならないというのは、パソコンではむしろ当たり前のもので、そもそも 0.1 という数値を 0.1 として保持できない、というCPUの仕様によります。
根本的な対策はあり、decimalというのを利用するようにすることで解決できます。なぜそうしないかというと、計算するのに時間がかかるからです。
とはいっても、今の時代のCPUは速いのに、なぜかdecimalを使わないというのが世界的な謎だったりしますが・・・

さて、現代ではどうかというと、最新のExcelではIEEE仕様に準拠するというのは変わらないはずなのですが、 0.1 + 0.1 + 0.1 は 0.3 と等しい、となっています。
対策を講じたんだな、もしかしたらdecimal型にした？とも思ったのですが、念のため次のように
0.3 - 0.1 - 0.1 - 0.1 = 0
とすると、残念ながら・・・という結果でした。
計算の仕様としてはIEEE仕様に準拠したのでしょうが、なにかロジック的な工夫で誤差が表面化しないようにしたのかもしれません。


ちなみに、私もこの内部処理を１から作ったことがあるので、ごまかし方を１つ。
B列で、計算中は誤差が生じたまま計算をするのですが、計算結果が出たら、計算結果を丸める、というものです。
この例でIF文を使っているのはまさにその為です。
IF文は計算中なので、誤差があるままです。なので 0 ではない、となります。
ですが、例えば計算式を
  = 0.3 - 0.1 - 0.1 - 0.1
とすると、 0 になります。
これは、エクセルの実際の方法までは知りませんが、私は小数第15桁で丸める、とすることでほどよく、人間がOK！となる結果だったため、計算結果を丸めるようにしました。
当時、このことを伝えて、一応decimalで2分木を演算するオプションも用意したのですが、（割り算を分数として内部表記して、計算し、計算結果の分数を小数にする、というオプションも。これだと 1 / 3 * 3 が 1 になる！）結局使われませんでした・・・

double型の特有の問題なのですが、double型の保持状態を10進数で表現する、というのを作ったこともありました。
なかなか奥が深いです・・・
オブジェクト指向Cコンパイラcomelangがraspi picoで動きました。

この方法はMacBookでの方法です。

まずMacBookにPICO SDKをインストールしてください。
インストール方法は検索するかAIに聞いてください。
git cloneしてcmakeでビルド
環境変数PICO_SDK_PATHを設定するだけだったと思います。

comelangを使ったコードを転送する前に
まず普通にプロジェクトを作ってください。

CMakeLists.txt
```
cmake_minimum_required(VERSION 3.13)
include(pico_sdk_import.cmake)

project(led_project)

pico_sdk_init()

add_executable(led led2.c)

# 必要なライブラリをリンク
target_link_libraries(led pico_stdlib hardware_gpio pico_malloc)

# フラッシュ設定
pico_enable_stdio_usb(led 1)
pico_enable_stdio_uart(led 0)

pico_add_extra_outputs(led)
```

led2.c
```C
#include "pico/stdlib.h"

int main() {
    const uint LED_PIN = 25;  // PicoのオンボードLEDピン
    gpio_init(LED_PIN);
    gpio_set_dir(LED_PIN, GPIO_OUT);

    while(true) {
        gpio_put(LED_PIN, 1);  // LED ON
        sleep_ms(500);         // 500ms待機
        gpio_put(LED_PIN, 0);  // LED OFF
        sleep_ms(500);         // 500ms待機
    }

    return 0;
}
```
pico_sdk_import.cmakeがカレントディレクトリに必要みたいです。
SDKからコピーしてきてください。

```
> mkdir build && (cd build && cmake .. && make)
```

ラズパイPICOのbootableボタンを押してパソコンに接続。Mac Book AirならUSB-C <=> USB-A端子が必要です。
```
> cd build
> cp led.uf2 /Volumes/RPI-RP2
```

コピーするとLEDの点火が始まります。

いよいよcomelangを使ったコードを動かします。
pico_config_platform_headers.h
pico_config_extra_headers.h
をPICO SDKからコピーしてください。

led.c
```
#include <comelang-pico.h>

int main() {
//    stdio_usb_init();  // USB出力の初期化
    const uint LED_PIN = 25;  // PicoのオンボードLEDピン
    gpio_init(LED_PIN);
    gpio_set_dir(LED_PIN, GPIO_OUT);

    var li = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    foreach(it, li) {
        for(int i=0; i<5; i++) {
            gpio_put(LED_PIN, 1);  // LED ON
            sleep_ms(50*it);         // 50ms待機
            gpio_put(LED_PIN, 0);  // LED OFF
            sleep_ms(50*it);         // 50ms待機
        }
    }
    
    while(true) {
        gpio_put(LED_PIN, 0);  // LED OFF
    }

    return 0;
}
```

```
comelang -pico led.c
```

でコンパイルに成功すればled.c.cができます。
```
> cp led.c.c led2.c
```

もう一度コンパイルします。
```
> (rm -rf build && mkdir build && cd build && cmake .. && make)
> cd build
> cp led.uf2 /Volumes/RPI-RP2
```

今度は点火が最初は早いですが、徐々に遅くなります。

注意点は一度プロジェクトとビルドしておかないとcomelang -pico led.cが成功しない点です
ヘッダーが足りずにコンパイルに失敗すると思います。

モダンなコンパイラをpicoでも楽しんでください。
【初心者向け】時間に関するテストでハマりやすいポイントと対策


こんにちは、とまだです。

[テスト自動化あるある言いたい by T-DASH Advent Calendar 2024](https://qiita.com/advent-calendar/2024/t-dash03)、8 日目の記事をお届けします！

皆さん、テストは書いていますか？

最近、テストの自動化を進めていく中で、**時間に関するテストで思わぬハマりポイント**があることに気づきました。

今回は、時間にまつわるテストで遭遇しやすい問題と、その対策をご紹介します！

## 1. 現在時刻を使ったテストがコケる

### よくある問題

実行時の時刻に依存したテストは、以下のような問題を引き起こすことがあります。

- テストの実行タイミングでコケる
- タイムゾーンが違う環境でコケる
- たまに処理に時間がかかった時にコケる

### 対策方法

現在時刻を固定値に置き換えましょう。

明示的に時刻を指定することで、テストの安定性が向上します。

```ruby
# 良い例
it "1日後の期限でタスクが作成されること" do
  base_time = Time.new(2024, 1, 1, 12, 0, 0) # 2024/01/01 12:00:00
  travel_to base_time do # 現在時刻を固定
    task = create_tomorrow_task # 1日後のタスクを作成
    expect(task.deadline).to eq(base_time + 1.day) # 期限が1日後であることを確認
  end
end
```

## 2. 月末日のテストでハマる

### よくある問題

月末日の処理を含むテストでは、以下のような問題が起きることがあります。

- 月によって日数が違う
- うるう年の判定
- 月をまたぐ計算が複雑

「年」を指定しているのであれば大体問題はないのですが、「月末」を使っている場合は要注意です。

### 対策方法

適当な日付でいいのであれば、中間日を使います。

```ruby
# 良い例：15日を使用
let(:base_date) { Date.new(2024, 1, 15) }

# 悪い例：31日を使用
let(:base_date) { Date.new(2024, 1, 31) }
```

ただし、月末であることがロジックに絡むのであれば、境界値のテストは絶対に書くようにしましょう。

## 3. 時差が絡むテストで混乱する

### よくある問題

国際的にサービスを提供する場合、以下のような問題が発生するかもしれません。

- サーバとクライアントのタイムゾーンが違う
- 日付変更線をまたぐ処理がある
- サマータイムの影響

### 対策方法

テスト内では UTC を使用し、必要に応じてタイムゾーンを明示的に指定します。

```ruby
# 良い例
it "日本時間で正しく表示されること" do
  time = Time.utc(2024, 1, 1, 12, 0, 0) # UTC で指定
  expect(format_time(time, "Asia/Tokyo")).to eq "2024/01/01 21:00" # 日本時間で表示
end
```

もちろん、タイムゾーンによってロジックが変わる場合は、そのテストも書くようにしましょう。

## 4. 経過時間のテストが不安定になる

### よくある問題

処理時間を含むテストでは、以下のような問題が発生します。

- 実行環境によって処理時間が変わる
- 負荷状況で結果が変わる
- 微妙な時間差で失敗する

「再実行したら通った」という経験がある方も多いのではないでしょうか。

その場合には、時間の比較を見直した方がいいかもしれません。

### 対策方法

具体的な時間ではなく、相対的な比較や範囲での判定を使います。

```ruby
# 良い例
it "1分以内にジョブが完了すること" do
  start_time = Time.now # 開始時刻を記録
  perform_job # ジョブを実行
  expect(Time.now - start_time).to be < 60 # 1分以内で完了することを確認
end
```

もちろん、タイムアウトなどが絡む場合には、そのテストも書くようにしましょう。

## まとめ

時間を扱うテストで気をつけるべきポイントを見てきました。

1. 現在時刻は固定値を使う
2. 月末日は避けて中間日を使う
3. タイムゾーンは明示的に指定する
4. 経過時間は範囲で判定する

これらの点に気をつければ、より安定したテストが書けるはずです！

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

## 他にもアドベントカレンダー記事を書いています！

他にも、2024 年のアドベントカレンダーに参加しています。

以下の記事でまとめているので、よければ他の記事も読んでいただけると嬉しいです！

https://qiita.com/tomada/items/025b3745df8c484f5856
Open WebUIでChatGPTとClaudeとCerebras（Llama3.1）が使えるようにしてみた

# はじめに

Open WebUIでChatGPTとClaudeとCerebras（Llam3.1）が使える環境を立ち上げてみました。それぞれWebのコンソールがあるのでそれを使えばよいのですが、ただローカルで立ち上げてみたかったというだけです。APIだと高性能なモデルを従量課金で使えるのがいい。

# 前提条件

Dockerが動作するUbuntu上でWeb UI環境を立ち上げます。Macでも動作すると思います。

# ChatGPTのAPIキー取得

以下からAPIキーを取得する。WebUIのDockerを立ち上げるときに使う。

https://platform.openai.com/api-keys

# ClaudeのAPIキーを取得

以下からAPIキーを取得する。ClaudeのAPIキーはDockerの起動オプションではなく、Functionsから入力する。

# Cerebras（Llama3.1）のAPIキーを取得

以下からAPIキーを取得する。Cerebrasはプロセッサーの名前で、その上で走るLlama3.1が使える。非常に高速なのが特色。今は普及活動中らしく、トークンの制限はあるが無料で使える。

https://cloud.cerebras.ai

# Open WebUIのインストール

以下の「Installation for OpenAI API Usage Only」のコマンドでWebUIをインストール（Dockerを起動）する。Dockerの起動オプションで`ChatGPTのAPIキー`を使う。インストールが終わると、ブラウザに `[IPアドレス]:3000` と入れればWebUIが起動できる。

https://docs.openwebui.com/#installation-for-openai-api-usage-only

# Claude（Anthropic）のFunctionを追加してAPIキーを設定

これがちょっとわかりにくい。AnthropicはWebUIの追加ファンクションとして配布されている。以下からAnthropicをGetして保存を押す。保存を押さないと追加されないので注意。

https://openwebui.com/f/justinrahb/anthropic/

WebUIの左側のワークスペース→FunctionsにAnthropicが追加されているので、そこの歯車マークからAPIキーを入力するとClaudeが使えるようになる。

![スクリーンショット 2024-11-10 6.23.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512829/c10c57e0-87bf-3fbf-5de2-ee90dac6d81a.png)

# CerebrasのAPIキーを設定

WebUIの左下のユーザー名から`管理者パネル`→`設定`→`接続`を選ぶ。OpenAIのAPIキーはすでに入っているので、右側の`+`を押して行を追加して、左側に `https://api.cerebras.ai/v1` と入れて、右側にAPIキーを入力する。一番右のボタンを押すと接続確認ができる。

![スクリーンショット 2024-11-10 6.22.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512829/561284df-5d64-17ef-bd30-1adf2a31e2e3.png)

# モデルを使う

設定がうまくいくと、いろんなLLMモデルを選択したり、３つのLLMモデルを同時に使ったりすることができる。

![スクリーンショット 2024-11-10 6.26.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512829/202102a3-5ed3-9545-de68-56f449d5ced3.png)

# 所感

ひょっとしたら外部でこのようなサービスがあるのかもしれないが、なんとなくWebUIの使い方を理解したかったのでやってみました。すごく簡単ですね。Llama3.1は自分のテイストに合う回答をくれない。ChatGPTがやっぱり一番いいかな。Claudeはまだちょっと良さがわかってない。複雑な処理をやらせたら差がでるのかも。

ローカルでLlama3.2を動かしてみてもいいのですが、性能のいいモデルは動かせないのであまりやる気がわかない。最新版のMac miniは64GBのユニファイドメモリを乗せれば70Bは動くらしいので、手に入れたらLlama3.2オンプレミスをやってみようと思います。
「フロントエンド何も分からん」から1人で実装できるまで - モブプロのススメ


こんにちは、とまだです。

アドベントカレンダー、[開発でチャレンジして、失敗・成功したことをシェアしよう](https://qiita.com/advent-calendar/2024/engineering-careers-1)の 9 日目の記事をお届けします！

私がいまの現場に入ったとき、基本的には Ruby on Rails のバックエンド開発を担当していました。

ただ、よりリッチな UI/UX を提供するために Vue.js を使ったフロントエンド開発も必要となったものの、**全くの初心者という状況**でした。

そんな私が、**モブプログラミング（モブプロ）**を通じてフロントエンド開発を学んだ経験を共有したいと思います。

## モブプロとの出会い

当然のことながら、Vue.js のコンポーネント設計や非同期処理は全くの未経験。

正直 JavaScript すら「全然分からん」という状況からのスタートでした。

そんな中、チームリーダーから毎日 1 時間ずつのモブプロを提案されました。

## モブプロとは？

モブプロ（モブプログラミング）とは、複数のメンバーで集まって一つのコンピュータを共有し、一緒にコードを書く開発手法です。

最近ではリモートワークが増えているため、画面共有をしながら書くことも多いですね。
（実際、私はリモートでのモブプロが多かったです）

誰か 1 人がずっと書くわけではなく、15 分や 30 分ごとに交代しながら進めていくのが一般的です。

## モブプロへのイメージ

正直、最初は **「自分が分からないことを晒すのは恥ずかしい」** という気持ちが強かったです。

しかし、実際にモブプロを始めてみると否定されることなく、むしろ「分からないことを共有できる環境」が広がっていました。

**「間違ったコードを書いた時こそ、学びがある」**という考え方が身についたのも、モブプロのおかげです。

## モブプロで得られた 3 つの学び

### 1. 実務目線での考え方

自己学習では気づけなかった「実務ならではの考え方」を学べたのが、最も価値のある学びでした。

例えば、機能追加の際も「とりあえず動けばいい」という考えではなく、「将来の拡張性」「他の機能への影響」「パフォーマンスへの配慮」など、様々な観点で考える必要があります。

こういった観点は、本やオンラインリソースではなかなか学びづらいものですので、モブプロを通じて学べたことは非常に貴重です。

### 2. 設計の重要性

アプリケーションの規模が大きくなるにつれて、コードの見通しが悪くなりやすい傾向があります。

モブプロでは「考え方」を気軽にお互いに共有できるため、聞いているだけでも設計の観点を学ぶことができます。

- 処理の適切な粒度
- 共通処理の設計方針
- 保守性を意識したコードの書き方

モブのメリットは、やはり「なぜそのように設計するのか」という理由を、その場で説明してもらえることです。

後から実装結果を見ることももちろん大切ですが、単なる実装方法だけでなく、その背景にある考え方を学べたのはよかったです。

### 3. 実践的なデバッグ手法

地味なところですが、デバッグのやり方を学べるのもモブプロの魅力の一つです。

特に 1 人でデバッグするときには見落としがちな部分も、複数人で見ることで見つけやすくなります。

その際、いろんな観点だったり、デバッグツールの使い方を見聞きすることで、自分のデバッグスキルもだいぶ向上したかと思います。

これも、自分では学びにくいポイントなので、モブの良いところですね。

## まとめ：モブプロは最高の学習機会

モブプロは単なる共同作業ではありません。

実践的なコードレビュー、暗黙知の共有、設計思想の理解が同時に得られる、最高の場だと思っています。

自分も最初は臆していましたが、慣れないときこそ得られるものが大きいので、ぜひチャレンジしてみてください。

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

## 他にもアドベントカレンダー記事を書いています！

他にも、2024 年のアドベントカレンダーに参加しています。

以下の記事でまとめているので、よければ他の記事も読んでいただけると嬉しいです！

https://qiita.com/tomada/items/025b3745df8c484f5856