OmniAICreator/Qiita-1.07M huggingface dataset:
【Python】命名規則と変数名

PEP 8（Python Enhancement Proposal 8）はPythonのコードスタイルガイドで、読みやすく一貫性のあるコードを書くための指針を提供しています。以下に、主要な命名規則と良い変数名の付け方を説明します。
# 変数名と関数名
変数名と関数名は、小文字のみを使用し、単語間はアンダースコア（_）で区切ります。これをスネークケースと呼びます。
```python
# 良い例
user_name = "Alice"
total_count = 42
calculate_average = lambda x, y: (x + y) / 2

# 悪い例
UserName = "Bob"  # クラス名のような大文字始まりは避ける
totalCount = 100  # キャメルケースは避ける
```
# 定数
定数は全て大文字で、単語間はアンダースコアで区切ります。
```python
MAX_CONNECTIONS = 1000
DEFAULT_TIMEOUT = 30
PI = 3.14159
```
# クラス名
クラス名はキャメルケース（各単語の先頭を大文字）を使用します。
```python
class UserProfile:
    pass

class DatabaseConnection:
    pass
```
# メソッド名
メソッド名は関数名と同じく、スネークケースを使用します。
```python
class Car:
    def start_engine(self):
        pass
    
    def apply_brakes(self):
        pass
```
# プライベート変数やメソッド
クラス内でのみ使用する予定の変数やメソッドは、名前の前にアンダースコアを1つ付けます。
```python
class BankAccount:
    def __init__(self):
        self._balance = 0  # プライベート変数
    
    def _update_balance(self):  # プライベートメソッド
        pass
```
# 特殊メソッド（マジックメソッド）
特殊メソッドは前後にダブルアンダースコアを付けます。
```python
class CustomList:
    def __init__(self):
        self.data = []
    
    def __len__(self):
        return len(self.data)
```
# 良い変数名の付け方
変数名は短すぎず、長すぎず、その変数の役割を明確に表すものが良いです。
```python
# 良い例
user_age = 25
is_active = True
items_count = len(items)

# 悪い例
a = 25  # 意味が不明確
is_it_active_or_not = True  # 長すぎる
cnt = len(items)  # 略語は避ける
```
# イテレータ変数
短いループでは、`i`, `j`, `k`などの単一文字の変数名を使用することも一般的ですが、長いループや複雑な処理では、より意味のある名前を使用します。
```python
# 短いループの例
for i in range(3):
    print(i)

# 長いループや複雑な処理の例
for user in active_users:
    process_user_data(user)
```
# ブール変数
ブール変数には、`is_`, `has_`, `can_`などのプレフィックスをつけると、その変数が真偽値を表していることが明確になります。
```python
is_logged_in = True
has_permission = False
can_edit = check_user_rights(user)
```
これらの規則に従うことで、コードの可読性が向上し、他の開発者（将来の自分も含めて）がコードを理解しやすくなります。

最後に、実際のコード例を見てみましょう。
```python
class LibraryBook:
    MAX_CHECKOUT_DAYS = 14

    def __init__(self, title, author):
        self.title = title
        self.author = author
        self._is_checked_out = False
        self._checkout_date = None

    def check_out(self):
        if not self._is_checked_out:
            self._is_checked_out = True
            self._checkout_date = self._get_current_date()
            return True
        return False

    def return_book(self):
        if self._is_checked_out:
            self._is_checked_out = False
            self._checkout_date = None
            return True
        return False

    def _get_current_date(self):
        # 実際の実装ではdatetimeモジュールを使用するでしょう
        pass

    def is_overdue(self):
        if not self._is_checked_out:
            return False
        days_checked_out = self._calculate_days_checked_out()
        return days_checked_out > self.MAX_CHECKOUT_DAYS

    def _calculate_days_checked_out(self):
        # 実際の実装では日付の差分を計算するでしょう
        pass
```
このコード例では、PEP 8に準拠した命名規則を使用しています。クラス名、メソッド名、変数名がそれぞれの規則に従っており、各名前からその役割が推測できるようになっています。
これらの規則を意識しながらコードを書くことで、より読みやすく、メンテナンスしやすいPythonプログラムを作成することができます。
######
参考)　[東京工業大学情報理工学院 Python早見表](https://chokkan.github.io/python/index.html)
ITパスポート データの抽出と論理演算

・論理演算
真（true）と偽（false）の２通りの値の間で行われる演算

・論理和（OR）
二つの入力値のうち、少なくとも一方が１ならば、出力値は１
・論理積（AND）
二つの入力値の両方が１ならば、出力値は１
・否定（NOT）
入力値が１ならば出力値は０、入力値が０ならば出力値は１
・排他的論理和（XOR）
二つの入力値が異なれば、出力値は１

・ワイルドカード
不特定の文字や文字列を表す特殊文字
%、*など
０文字以上の任意の文字
?、_など
１文字の任意の文字

例　都道府県名の抽出
山%　山で始まる都道府県名　山形、山梨、山口
??山　任意の２文字で始まり、山で終わる都道府県名　和歌山
Groq: Julia で、PostgreSQL のテーブルを Dataframe に読み込む方法

[Groq](https://groq.com/)に次の問を出しました。

```text
Julia で、PostgreSQL のテーブルを Dataframe に読み込む方法
```

3つのプログラムが提示されましたが、どれも存在しないと思われるパッケージを使っていました。

一番、正解に近いプログラムを修正しました。

## 結果を修正したプログラム

```jl:groq.jl
#! /snap/bin/julia

using DataFrames
# using PostgreSQL
using LibPQ

# PostgreSQL 接続情報
host = "localhost"
port = 5432
username = "scott"
password = "tiger123"
database = "city"

# 接続
# conn = PostgreSQL.connect(host, port, username, password, database)
conn = LibPQ.Connection("postgresql://scott:tiger123@localhost/city")

# テーブル名
table_name = "cities"

# Dataframe に読み込む
# df = DataFrame(PostgreSQL.query(conn, "SELECT * FROM $table_name"))
df = DataFrame(LibPQ.execute(conn, "SELECT * FROM $table_name"))

println(df)
```

## 実行結果

```text
$ ./groq.jl 
9×4 DataFrame
 Row │ id       name     population  date_mod   
     │ String?  String?  Int32?      Date       
─────┼──────────────────────────────────────────
   1 │ t3461    広島          25176  2003-09-24
   2 │ t3462    福山          47935  2003-05-15
   3 │ t3463    東広島        28654  2003-02-08
   4 │ t3464    呉            83152  2003-10-09
   5 │ t3465    尾道          42791  2003-08-04
   6 │ t3466    竹原          35687  2003-01-21
   7 │ t3467    三次          81296  2003-07-23
   8 │ t3468    大竹          21764  2003-10-26
   9 │ t3469    府中          75423  2003-12-15
   ```
【3minで読める】pyenv, venv, pyenv-virtualenvの使い分け、これ見ればok！！

## pyhonの環境管理
### はじめに
pythonを使い始めるとき、どう初めて良いか悩んだことはないでしょうか？
初め多くの方はローカルでpythonを動かすことでしょう。しかし、そんなとき
**「このプログラムではpythonのバージョンとして動かない.....。」**
**「pythonのライブラリを綺麗に管理したいなー」**
と色々悩みが出てきます。
私も初めは全てローカルで動かしていたことから、あれこっちのコードは動くのに、こっちは動かない、原因はpythonのバージョン？じゃあどうすればいいんだー？と悩みました。仮想環境？バージョン管理？なんだそれという方に是非読んでいただきたいです。
そんな方々に見ていただけると嬉しいです！
本記事は**知識編**になりますので、実装編を見たい場合は、次の記事をご参照ください！

## pythonの環境管理にはなにがあるの？（仮想環境構築・バージョン管理）
pythonの環境管理には大きく3つ種類があります。
- venv
- pyenv
- pyenv-virtualenv

## 各環境管理の概要とメリットデメリット
**1. pyenv**
- 概要
pyenvは複数のpythonバージョン管理をするためのツールです。特定のプロジェクトやディレクトリに対して、それぞれのpythonバージョンを簡単に切り替えが可能になります。
あなたが駆け出しDSであり、DSの練習として、いくつかの参考書のコードを実装するとき、実装本にはよく **「このコードはpython3.xxを想定しています」** と書かれているのを見たことないでしょうか？
また別の実装本では別のバージョンが書いてあり、ローカルで動かそうとしたとき、動かなかったという経験がありませんか？
そのような時にpyenvを用いて実装本ごとにpythonバージョンを変えることができるということです。
- メリット
    1. PCにインストールしている複数のpythonバージョンを簡単に切り替えることができる
    2. グローバルなpythonバージョンやディレクトリ(プロジェクト)ごとに露＾かるなpythonバージンを設定できる
    3. 後で説明するpyenv-virtualenv機能を拡張できること
- デメリット
    1. 依存関係の管理が難しい点です。**pyenv**自体は依存関係の管理を勝手にしてくれるわけではないので、別途仮想環境系と組み合わせる必要があります

**2. venv**
- 概要
venvはpythonにヒョ王順で組み込まれ散る仮想環境管理のツールです。プロジェクトごとにpythonの環境を構築し、依存官営を管理可能です。上記のpyenvはあくまで、pythonのバージョンを一つのpython環境で使い分けるでしたが、venvはそもそ仮想で、pythonの環境を複数作成してpythonを管理するということになります。
- メリット
    1. pythonに標準で付属しているため、何か追加のインストール等の手間がない
    2. 操作もシンプルで使いやすく、簡単にプロジェクトごとの環境を管理・作成できる
- デメリット
    1. pythonのバージョン管理が難しい。venvは特定のpythonバージョンを指定出来にため、異なるpythonバージョンを利用する場合は、事前にそのバージョンのpythonをインストールしておかなければいけない

**3. pyenv-virtualenv**
- 概要
pyenv-virtualenvはpyeuvのプラグインでpyenvを使用して、インストールしたpythonごとに仮想環境を作成・管理できるツールです。
- メリット
    1. pyenvと統合されているため、pythonバージョンと仮想環境の両方を一元管理となっており、便利です
- デメリット
    1. 単体のvenvと比較すると設定等が少し複雑なため、煩わしさがある

## まとめ
筆者のおすすめは、若干複雑ではあるもののpyenv-vituarlenvで環境を管理することです。これからDSに目指す方や、練習としてpythonに触れる方でも、必ずバージョン管理やライブラリの管理等の壁にはぶつかります！あとでやっておけばよかったーとなることが出てくるでしょう。最初は手間に感じるかもしれませんが、ぜひ初めこそ少し時間をかけて土台を作ってみてはいかがでしょうか？
【Java SE11 Silver】取得に向けて

## はじめに
先日、簿記3級を取得し、次は何の勉強をしようか考えていました。英語や仕事とは関係のない趣味に時間をかけたい気持ちもありましたが、ずっとやらなければと思いながら取り組めていなかったJavaの勉強をすることに決めました。
ですので、この記事は合格体験記ならぬ合格へ向けた宣言の記事になります（と、自分を奮い立たせる、、）

## なぜ Java Silverなのか？
1. 開発に対する苦手意識を払拭するため
1. 次の案件がJava関連になる可能性が高いため
1. 今後どんなポジションを目指すにしても、開発言語を理解しておくことは大事なことであるため

## スケジュール
ゆったり余裕を持ちたいので７月～１０月の４か月間で合格する予定。
合格に必要な時間が１００時間だとすると、１か月２５時間。１日１時間と考えると少々しんどい笑。土日で頑張るつもりだ。


## 勉強方法
勉強方法には自分のこだわりがあるのだが、テキストだけの勉強だけじゃなく実際にコードを書きたい。頭の中にある知識としてだけじゃなく、身体で覚えることも大事にしたい。

７月　
YouTubeでJava基礎が学べる動画を見る
↓
８月
Java Sillverのテキストで勉強
↓
９月～１０月
問題集とテキストで勉強

ざっくりこんなイメージ。
合格（もしくは不合格）した暁には、合格体験記を書きたいと思います。
Visual Studio 2022 C＃ 表の使い方　dataGridView

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423803/4d2b1420-91ce-3e08-c9d6-91494c064240.png)

```
    ・dataGridView の基本的な設定
            // -start- DataGridView 基本設定 
            //行が自動的に作成されないようにする
            dataGridView1.AllowUserToAddRows = false;

            // 行ヘッダーを非表示にする これを入れないと一番左側に余計なマーク列が入ってしまう
            dataGridView1.RowHeadersVisible = false;

            //ヘッダーとすべてのセルの内容に合わせて、列の幅・行の高さを自動調整する これを入れないと横側に余白ができてしまう
            dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;

            // 全行削除
            //dataGridView1.Rows.Clear();
            //dataGridView1.Columns.Clear();

            // -end- DataGridView 基本設定 
```
Maven compile Error "cannot access class ..."

# 実現したいこと
Maven Webアプリケーションプロジェクトを異なる環境に移動し、`mvn clean package` でビルド

# エラーメッセージ
```console:Console
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project yout-project: 
Fatal error compiling: java.lang.IllegalAccessError: 
class lombok.javac.apt.LombokProcessor (in unnamed module @0x21c75084) cannot access class 
com.sun.tools.javac.processing.JavacProcessingEnvironment (in module jdk.compiler) 
because module jdk.compiler does not export com.sun.tools.javac.processing to unnamed module @0x21c75084
```
### 日本語での要約
Lombok へのアクセス失敗によるコンパイルエラー

# 原因
Maven プロジェクトを異なる環境に移動した結果、
Java と Lombok のバージョン不一致が発生したため

# 解決方法
1. Lombok を Java に合わせる（Java を現状維持したい場合）
    - pom.xml で Lombok のバージョンが明示的に指定されていなかったため、追記する
    ```xml:pom.xml
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.30</version> <!-- 追加 -->
      <scope>provided</scope>
    </dependency>
    ```
    .
    
1. Java を Lombok に合わせる（Lombok を現状維持したい場合）
    - 現在の Lombok のバージョンを使用できる Java に変更する

# 環境
Java 17.0.9
Eclipse IDE for Enterprise Java and Web Developers (includes Incubating components) Version: 2023-12 (4.30.0)
Apache Maven/未調査
Aurora PostgreSQL のパスワードを Secrets Mangaer でローテーションさせる際にはまったこと

Aurora PostgreSQL のパスワードを Secrets Mangaer でローテーションさせる際にはまったことをご紹介します。

## 想定の構成

今回は以下のような構成を想定しています。

![スクリーンショット 2024-06-29 15.25.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074001/27d9c359-e009-2bf3-e1e8-d3efd0eb3a3c.png)

ECS から Aurora PostgreSQL にアクセスするためのユーザ名やパスワードなどの認証情報を Secrets Manager に格納しています。また、認証情報は Lambda でローテーションさせます。

## はまったこと

PostgreSQL の接続 URL は"postgresql://【ユーザ名】:【パスワード】@【ホスト名】:【ポート番号】/【データベース名】"という形式です。PostgreSQL のパスワードに[パーセントコーディングの必要な文字](https://developer.mozilla.org/en-US/docs/Glossary/Percent-encoding)が含まれている場合、そのまま接続 URL に埋め込むとエラーになります。そのため、パスワードをパーセントコーディングする処理をどこかで実装する必要があります。

## 解決法

Secrets Mangaer で認証情報をローテーションさせている場合は、生成するパスワードにパーセントコーディングが必要な文字を含めないようにします。
具体的には Lambda で実装されているローテーション関数の環境変数「EXCLUDE_CHARACTERS」の値を以下のように設定します。

```
EXCLUDE_CHARACTERS=":/?#[]@!$&'()*+,;=%"
```

## 余談

最初はパーセントコーディングする処理を実装する方法を検討していましたが、本記事で紹介した方法だと簡単に実装できました。
社内でテスト駆動開発の体験会を開催したお話【振り返り編】

# はじめに
こちらの記事の続きです！
<font color="Red">
アンケート結果も載せています！
</font>

https://qiita.com/does_not_exist/items/7277556f9e44f106d27a

# 開催後の振り返り

- シンプルなお題にして良かった

当初考えていたお題は「アプリの機能改修をテスト駆動開発で体験してみよう」でしたが、環境構築の時間や参加者のスキルレベルなどを考慮した際に、テスト駆動開発とは関係ない場面で混乱させてしまいそうだと思ったためシンプルなお題にしました。それが良かったのかアンケート結果では好評でした。<font color="Blue">実際に予定時間内で参加者全員がお題を解き終えました。</font>

<br>

- もう少し準備期間を取りたかった

<font color="Blue">せめて前日くらいには告知してワクワクを感じてもらいたかったです。</font>実際は当日の朝に内容告知・環境構築依頼をしました。
それにも関わらず参加者のほぼ全員が体験会開催前に環境構築してくれました！時間がとれなかった参加者も、体験会中に設けていた時間内で構築することができていました。

<br>

- 各自ハンズオンも良かったが次回はモブプロでも開催してみたい

今回は各自ハンズオンしてもらい質問があれば受け付ける、というスタイルで開催しました。これには意図があり、<font color="Blue">各自の思考スピードで手を動かしてみてほしいという狙いがありました。</font> 私の場合、何か新しいことをやってみる時は自分の思考スピードで取り組みたいという考えからこのような形式をとってみました。
とはいえ終始黙っているわけではなく、要所でテスト駆動開発の流れのおさらいや進捗確認、時間管理、裏話などの雑談を挟みました。次回は参加者間で会話しながら体験してもらうモブプロ形式も視野に入れています。また違った気づきがあるかもしれません。

<br>

- 参加者からレスポンスがあると嬉しい

体験会中に裏話をしている際にレスポンスがあると嬉しかったです。~~嬉しすぎて語りすぎてしまわないようにセーブしました~~


<br>

- 思っていたよりフィードバックをもらえた

アンケート結果を見ると大多数の参加者から文章ベースでも回答いただけて驚きました。ありがとうございます。



# おわりに

急遽の開催となりましたがやってみて良かったです。
周囲の温度感や各自が感じていることを知る機会となりました。
この経験を次に生かしてテスト駆動開発を広めていきたいです。
Windows PowerShellでポートを使用しているプロセスを特定し、終了する方法

## PowerShellでポートを使用しているプロセスを特定し、終了する方法

### はじめに
開発者やシステム管理者は、時折特定のポートが既に使用されているためにアプリケーションを起動できないことがあります。ここでは、PowerShellを使用して、特定のポートを使用しているプロセスを特定し、それを終了する手順を説明します。

### 手順1: PowerShellを管理者として起動
まず、PowerShellを管理者として起動します。これにより、システムレベルのコマンドを実行する権限が付与されます。

### 手順2: 特定のポートを使用しているプロセスを特定する
次に、`Get-NetTCPConnection`コマンドレットを使用して特定のポートを使用しているプロセスを特定します。例えば、ポート8080を使用しているプロセスを特定する場合、以下のコマンドを実行します。

```powershell
$port = 8080
$processInfo = Get-NetTCPConnection -LocalPort $port | Select-Object OwningProcess
```

### 手順3: プロセスIDを取得する
特定のポートを使用しているプロセスのID（PID）を取得します。

```powershell
$pid = $processInfo.OwningProcess
```

### 手順4: プロセスの詳細を確認する（オプション）
プロセスの詳細を確認するために、`Get-Process`コマンドレットを使用します。

```powershell
$processDetails = Get-Process -Id $pid
$processDetails
```

これにより、プロセス名や起動時間などの詳細情報を確認できます。

### 手順5: プロセスを終了する
`Stop-Process`コマンドレットを使用して、特定のプロセスを終了します。

```powershell
Stop-Process -Id $pid -Force
```

### まとめ
これで、PowerShellを使用して特定のポートを使用しているプロセスを特定し、それを終了する方法が完了しました。以下に、これらの手順をまとめたスクリプトを示します。

```powershell
# PowerShellスクリプト: ポートを使用しているプロセスを特定し、終了する

# 使用したいポート番号を設定
$port = 8080

# ポートを使用しているプロセスの情報を取得
$processInfo = Get-NetTCPConnection -LocalPort $port | Select-Object OwningProcess

# プロセスIDを取得
$pid = $processInfo.OwningProcess

# プロセスの詳細を確認（オプション）
$processDetails = Get-Process -Id $pid
$processDetails

# プロセスを終了
Stop-Process -Id $pid -Force

# 終了メッセージ
Write-Output "ポート $port を使用していたプロセス (PID: $pid) を終了しました。"
```
Tableau-傾向線について

## はじめに
今回はTableauの機能「傾向線」について少し考察と一歩踏み込んだ内容についてまとめていきたい

## きっかけ
DataSaber技術課題ord5のQ4について

>問4
顧客ごとの数量と利益の分布をみたとき、数量が多いときに利益が上がりやすい傾向にあるカテゴリ・地域の組み合わせはどれですか？
なお、R-2乗やP値は考慮しなくてよいです。

回答としては、シンプル（詳細は割愛）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346827/2dd8031f-880e-a917-3f76-c214048b7a54.png)

解答としては、これで問題ありませんがもう一歩踏み込んで考えてみて「R-2乗やP値は考慮しなくてよいです。」ここを考慮した場合どのような分析・解析結果が得られるのか見てみました。（今回はとりあえず、P値だけ）

※補足※
>ここで、（昨今X上でかなり話題になっていましたが、）P値とは
統計的仮設検定における帰無仮説が正しいと仮定した場合に、今回手元にあるデータが発生する確率
意味わからない場合は、検定前に定めて有意水準（＝分析者が定める基準、標準で5%と設定する場合が多い）と比べて大きいか小さいかを気にしておけばよく、小さければ最初の仮定が間違っている（＝棄却）という判断をする統計学におけるデータに基づく一つの判断基準です

## やってみた
結果はこちらです。
九州における家具のP値は<0.0001→ほぼ0
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346827/38fb13a4-111c-6d7d-e176-bd10e18af20a.png)

一方、中部における家具のP値は0.111903>0.05、有意水準を超える
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346827/648557df-6902-38f3-e8d2-0b1ff63986f3.png)

単純に何も考えず傾向線を引いてもその、傾向線の引き方（線形回帰）が正しくひかれたものかは一つP値という指標を見て判断する必要がある。
ただ、今回のように見るべき次元が増えすべてカーソルを合わせて一つ一つ見るのが面倒な場合にViz上でぱっと可視化できるようにする方法をここでは説明する

右クリック＞傾向線＞傾向モデルの説明
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346827/b81d4842-7128-8031-b124-48cf3dd95e03.png)

各個々の傾向線についてP値が一覧で取得することができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346827/26df7a5a-870d-cfe3-66a5-1ed331660778.png)

これをデータとして、Tableauデータベースに追加（方法は割愛）
（自分の場合は、面倒だが一度Excelに起こし成型してから、Tableauへ読み込ませてカラム名によるマージを実施）
P値が0.05以上（棄却できない）か以下（棄却）と色分けてして表示することで分析者として適切な傾向線の引き方を提示することができる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346827/f60f4e0b-ad6e-9636-9299-e58b4cee8bce.png)

## 最後に
実際の分析をする際は本当に適切な傾向線が引けているのかというところまで見てみるといいと思う。
UIの基礎

# 1. 概要
現在、フロントエンジニアとして、意図したUI設計ができるようにデザイン部分の基礎を学んでいます。

お次
[UIの基礎(2)](https://qiita.com/saburo555/items/c773cf0e92bd93206b95)
[UIの基礎(3)](https://qiita.com/saburo555/items/2d993e25179f85aba2e3)
[UIの基礎(4)](https://qiita.com/saburo555/items/8426c243d14efca1f5a5)

# 2. デザインとユーザー体験の基礎

## 2.1. デザインの本質

デザインは単なる装飾ではなく、「目的に応じた設計」と定義できる。これは問題解決や価値創造のプロセスを含む。

- デザインパターン：効果的な設計手法の集積
- アートとの違い：
  - アート：個人の表現と感情喚起が主目的
  - デザイン：機能性と問題解決が中心

## 2.2. UI（ユーザーインターフェース）とUX（ユーザーエクスペリエンス）

- UI：人間とシステムの接点。操作性と視覚的要素の最適化が目標。
- UX：サービス利用全体を通じてのユーザー体験。主観的評価が重要。

:::note warn
UIの改善はUXの向上に寄与しうるが、必ずしも直結しません。例えば、認証方式の変更（パスワードから生体認証へ）など、UIの枠を超えた改善が必要な場合もあります。
:::


# 3. デバイス特性とデザイン

## 3.1. 入力方法の影響

各デバイスの特性：

1. PC（マウス/キーボード）
   - 精密な操作が可能
   - ホバー機能を活用できる

2. スマートフォン（タッチスクリーン）
   - 多様なジェスチャー入力
   - ホバー機能なし
   - タッチ操作に適したサイズ設計が必要

3. テレビ（リモコン）
   - 直接選択できない
   - フォーカス表示が重要
   - 操作の連続性を考慮したレイアウトが必要

フォーカス表現の工夫：
- 複数の視覚的要素（枠線、色変更、サイズ変更、アニメーション）の組み合わせが効果的

![フォーカス表示の例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2889120/f3ac9457-ca68-3033-8b56-7d62ffcdf2c9.png)
出典：[Amazon デザインとユーザーエクスペリエンス（UX）に関するガイドライン](https://developer.amazon.com/ja/docs/fire-tv/design-and-user-experience-guidelines.html#focus-and-selection)

# 4. プラットフォームの特性

## 4.1. Webサイトとネイティブアプリの比較

Webサイトの特徴：
- 利点：
  - 開発の容易さ
  - クロスプラットフォーム互換性
  - インストール不要の手軽さ
- 課題：
  - 高度なインタラクションの制限
  - パフォーマンスの制約

ネイティブアプリの特徴：
- 利点：
  - 高いパフォーマンス
  - デバイス機能の完全活用
  - オフライン機能
- 課題：
  - プラットフォーム別開発の必要性
  - インストールの手間

プラットフォーム間のUI差異：

![Android vs iOS UI 例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2889120/8ca1dd47-231c-e51b-b49d-13a3a3603338.png)
出典：[AndroidとiOSにおけるUIの違いを知ろう!!](https://sinap.jp/blog/archive/1939/)

各プラットフォームのデザインガイドラインに従うことで、ユーザーにとって馴染みやすいインターフェースを提供できます。

# 5. まとめ
今回は[UIデザインの教科書](https://amzn.asia/d/0eIl5v7W)の1~3章の途中を掻い摘んで、アウトプットしてみました。
インプットしたことを意識しながら、UIに反映できるように、記憶しておこうと思います。
また、続編も書いていきます！！

## シリーズ
今：[UIの基礎](https://qiita.com/saburo555/items/d4871ad805fdd70be966)
[UIの基礎(2)](https://qiita.com/saburo555/items/c773cf0e92bd93206b95)
[UIの基礎(3)](https://qiita.com/saburo555/items/2d993e25179f85aba2e3)
[UIの基礎(4)](https://qiita.com/saburo555/items/8426c243d14efca1f5a5)
【チートシート】HTMLタグ自分用まとめ

## はじめに

最近、便利なHTMLタグをいくつか見つけたので、
いっそ基礎的なタグから駆け出しエンジニアの私が自分なりにまとめてみる。

### この記事の概要・意図

- HTMLタグの基本から便利なものまで概ね分かる。
- きっかけ程度になればいいな思うのでざっくりの記載。
- 良さそうなのをピックアップして単体で調べて使用していただければと。

### この記事の対象者

- HTML初心者
- 簡単なチートシートを探している人
- 便利なタグを知りたい人

## HTMLタグ一覧

| No. | タグ | 簡単な説明 |
|:-:|:-:|:-:|
| **基礎** |  |  |
|  | **基本レイアウト** |  |
| 1 | head | 制御情報を記入・Webページ上に公開されない |
| 2 | title | タイトルバーや検索エンジンの結果として表示 |
| 3 | meta | テキストの文字コードや概要 |
| 4 | link | 別の文書ファイルとの関係を指定 |
| 5 | script | スクリプトファイルを指定 |
| 6 | body | ページ上に表示する内容を記述 |
| 7 | header | webページに表示するおもに上部に表示されるコンテンツを宣言 |
| 8 | main | webページに表示するメインコンテンツを宣言 |
| 9 | footer |  webページに表示するおもに下部に表示されるコンテンツを宣言 |
|  | **タグ** |  |
| 10 | h1~h6 | 見出し・ブロック要素 |
| 11 | p | 段落・ブロック要素 |
| 12 | a | リンク・インライン要素 |
| 13 | img | 画像ファイルを埋め込む |
| 14 | video | 動画ファイルを埋め込む |
| 15 | div | 要素をグループ化・ブロック要素 |
| 16 | span | 要素をグループ化・インライン要素 |
| 17 | br | 改行 |
| 18 | small | 著作権や注釈を表示 |
| 19 | blockquote | 他サイト引用する時・ブロック要素 |
|  | **ナビゲーション** |  |
| 20 | nav | ナビゲーションの作成を宣言 |
| 21 | ul | 「・」の箇条書きリストを宣言 |
| 22 | ol | 数字で順序のリストを宣言 |
| 23 | li | 各項目をくくる |
|  | **表・テーブル** |  |
| 24 | table | 表の作成を宣言 |
| 25 | tr | 表における行 |
| 26 | th | 表における見出し |
| 27 | td | 表におけるデータ |
|  | **フォーム** |  |
| 28 | form | フォームの作成を宣言 |
| 29 | input | 入力欄・インライン要素 |
| 30 | textarea | 複数行の入力欄・インラインブロック要素 |
| 31 | select | 選択肢の作成を宣言 |
| 32 | option | 選択肢 |
| 33 | button | ボタンを作成 |
|  | **説明** |  |
| 34 | dl | 説明リストを宣言 |
| 35 | dt | 説明リストのタイトル |
| 36 | dd | 説明リストの内容 |
|  | **意味のある・要素をグループ化** |  |
| 37 | article | 要素をセクションでまとめる・単体で完結している必要あり |
| 38 | section | 要素をセクションでまとめる・見出しタグを含める必要あり |
| 39 | aside | サイドバー・補足・主題とは関係が薄い |
|  | **参考文献** |  |
| 40 | figure | 自己完結型のコンテンツを宣言・参考文献の画像や図表 |
| 41 | figcaption | figureのキャプションや説明を定義 |
|  | **コメント** |  |
| 42 | ```<!- ->``` | Webページに表示されない・メモ |
| **簡単で便利** |  |  |
| 43 | dialog | jsと合わせてダイアログやモーダルが楽に実装できる |
| 44 | details | HTMLのみでアコーディオンを作成できる・宣言 |
| 45 | summary | detailsタグのタイトル・要約 |
| 46 | progress | 進行率のバーを表示・似たものでmeterタグがある |
| 47 | datalist | 選択肢であるoptionをリアルタイム検索 |


## 参考資料

https://techmania.jp/blog/html-tag/#outline__3

https://blog.codecamp.jp/html-tags

https://rightcode.co.jp/blogs/35286


## 最後に

最近JavaScriptでモーダルを実装していましたが、なかなかめんどくさいなと思い。
調べたらdialogタグがあり試しに実装してみたら、あらまあ簡単！にモーダルが実装できました。
他にも便利なタグがあるんじゃないか、、、？
またいっそ自分なりにまとめてみようというのが経緯です。
HTMLのタグは探せばまだまだ出てくるが、とりあえず自分がすぐ見返せる用です。
ただ、ついでに誰かの役に立てばなぁ～と思ってます！
間違っているとこあったらごめんなさい！！！

初投稿なもんで、今後文章力や記事のレイアウトは改善・精進していきます！
NFCを使ってみる

# はじめに
FeliCaの読み書きを行ってみたいと思いNXP社のPN5180を購入しました。
PN5180を使用するために行ったことを忘備のためにまとめました。

# 使用機器
PN5180 NFC RFセンサーモジュール

:::note info
使用機器について
PN5180 NFC RFセンサーモジュールはAmazonで購入しました。
PN5180とはSPI通信を使用してデータの送受信を行います。
PN5180はスレーブとなります。
マスターにはSTM社のNUCLEOボードを使用しました。
:::

# 接続
マスター（ここではNUCLEOボード）とPN5180 NFC RFセンサーモジュールは下記のように接続します。

![接続](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148400/17b763a3-2ada-e4db-19b6-95378dcdfe36.png)

SPI通信について
クロック：7Mbit/sまで
モード0：CPOL=0, CPHA=0

|SPI通信関連の端子||
|:--|:--|
|MOSI|マスター出力|
|MISO|マスター入力|
|SCK|クロック|
|NSS|チップセレクト アクティブLOW|

BUSY
PN5180がデータの処理中で、マスターからデータを受信できないことを示します。
データを送信する前にBUSYがLOW（アイドル）になっていることを確認する必要があります。

RST（RESET_N）
リセット端子になります。
HIGHにすることでPN5180のリセットが解除されます。

REQ（DWL_REQ）
PN5180のファームウェアを更新するときに使用します。
ファームウェアのダウンロードは行わないのでLOWとします。

:::note info
電源（3.3V）とGNDはNUCLEOボードに接続しました。
:::

# 動作確認
動作確認として、PN5180のバージョン情報を読み出しました。
+ Die idenfifier
+ Product Version
+ Firmware Version
+ EEPROM Version

バージョン情報はPN5180のEEPROMに保存されています。バージョン情報の構成は、
PN5180のデータシート　11.5.2 EEPROM
より、下表のようになっています。
|バージョン情報|データサイズ|
|:--|:--|
|Die identifier|16バイト|
|Product Version|2バイト|
|Firmware Version|2バイト|
|EEPROM Version|2バイト|

データの読み出し手順は下記のフローのようになります。

![バージョン情報](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148400/c4ac27b2-1aba-b4e9-6b8a-6d26b1dd8037.png)

PN5180のデータシート　11.4.3.3 Host Interface Command List
より、EEPROMからバージョン情報を読み出すには下表の3バイトのコマンドを送信します。

|データ||
|:--|:--|
|0x07|コマンド（READ_EEPROM）|
|0x00|EEPROMの読み出し開始アドレス|
|0x16|EEPROMから読み出すデータ数|

READ_EEPROMコマンドでアドレス0x00番地から22バイトのデータを読み出すことを伝えたので、22バイトのデータを読み出します。下表のバージョン情報を取得することができました。

|バージョン情報|受信データ|
|:--|:--|
|Die identifier|0x00 0x00 0x00 0x00 0x00 0x01 0x76 0x0A 0x23 0x14 0x3A 0x56 0x64 0x56 0x20 0x55|
|Product Version|0x05 0x03|
|Firmware Version|0x05 0x03|
|EEPROM Version|0x00 0x91|

受信データを見るとファームウェアバージョンは3.5でした。

# 参考
PN5180のデータシート
[NXP](https://www.nxp.jp/products/rfid-nfc/nfc-hf/nfc-readers/full-nfc-forum-compliant-frontend-ic:PN5180)
PN5180A0XX_C3_C4.pdf

# 編集後記
PN5180のファームウェアバージョンを取得することができましたが、ファームウェアバージョンが3.5となっており古いようです。
次は最新のファームウェアにアップデートすることを目標にしたいと思います。
【Ruby】そのassert_raisesの使い方、本当に合ってる？ - assert_raisesでエラーメッセージをテストする方法

## はじめに
以下のテストで次の2点をテストしようとしています
- 特定の条件でraiseが発生しているか
- エラーメッセージが正しく出力されているか

このテストの何が悪いか皆さんは分かりますか？
```sample_code.rb
class SampleCode
  def self.animal_check(animal)
    raise '猫はアレルギーだからダメ' if animal == 'cat'

    raise '犬は可愛すぎるからダメ' if animal == 'dog'

    pp '他の動物は許す'
  end
end
```

```test.rb
  test '猫はアレルギーだからraise' do
    assert_raises(RuntimeError, '猫はアレルギーだからダメ') do
      SampleCode.animal_check('cat')
    end
  end
```
とあるプロジェクトのテストコードを眺めていたところ、陥りがちなあるミスを発見したので戒めとして記事にしようと思います。
では、なぜこのテストコードが悪いかについて解説していきます。

## このテストの何がいけないのか？
答えは`assert_raises`の使い方です。
実は以下のようにコードをいじってもこのテストは通ってしまいます。
```test.rb
  test '猫はアレルギーだからraise' do
    assert_raises(RuntimeError, 'どんなエラーメッセージでも落ちないよ〜') do
      SampleCode.animal_check('cat')
    end
  end
```
## assert_raisesの解説
assert_raisesが具体的にどんな挙動をするかを見ていきましょう。
assert関連のメソッドが定義されている`assertions.rb`には、以下のように`assert_raises`が定義されています。
```assertions.rb

    def assert_raises *exp
      flunk "assert_raises requires a block to capture errors." unless
        block_given?

      # assert_raisesの最後の引数が文字列の場合は、それをテストの失敗メッセージとする。
      msg = "#{exp.pop}.\n" if String === exp.last
      exp << StandardError if exp.empty?

      begin
        yield
      rescue *exp => e
        pass
        return e
      rescue Minitest::Assertion
        raise
      rescue SignalException, SystemExit
        raise
      rescue Exception => e
        flunk proc {
          exception_details(e, "#{msg}#{mu_pp(exp)} exception expected, not")
        }
      end

      exp = exp.first if exp.size == 1

      flunk "#{msg}#{mu_pp(exp)} expected but nothing was raised."
    end
```
上記コードを見ながら、初めに出したテストコードの何が悪かったかを解説していきます。
```test.rb
  test '猫はアレルギーだからraise' do
    assert_raises(RuntimeError, '猫はアレルギーだからダメ') do 
      SampleCode.animal_check('cat')
    end
  end
```
`assertions.rb`のコードを見れば、第二引数の「猫はアレルギーだからダメ」はRuntimeErrorが発生しなかった際にテストの失敗メッセージとして表示されるということがわかりますね。
つまり、このテストコードでやっているのは、RuntimeErrorのエラーメッセージとして「猫はアレルギーだからダメ」が出力されるテストではないのです。

実際にやっていることは以下の2つなのです。
- RuntimeErrorになればテスト成功
- テスト失敗時には「猫はアレルギーだからダメ」をテストの失敗メッセージとして出力する

## どうすればエラーメッセージをテストできるの？
以下のようにすればエラーメッセージのテストが可能となります。
```test.rb
test '猫の場合はraise' do
    exception = assert_raises(RuntimeError) do
      SampleCode.animal_check('cat')
    end
    assert_equal('猫はアレルギーだからダメ', exception.error_message)
end
```
Scala 3でScalaCheckのArbitraryを自動導出：ケースクラス、列挙型、直和型に対応

# 概要

ScalaCheckはScalaのプロパティベーステストライブラリで、テストデータの自動生成にArbitraryというクラスを使います。
しかし、複雑な構造を持つオブジェクトに対してArbitraryを手動で定義するのは面倒です。
この記事では、Scala 3のコンパイル時リフレクションを活用して、任意のオブジェクトに対する`Arbitrary`を自動生成する方法を紹介します。

# ScalaCheckとArbitrary

ScalaCheckでは、`Arbitrary[T]`を提供することで、型`T`の値をランダムに生成できます。
例えば、`Arbitrary[Int]`はランダムな整数を生成し、`Arbitrary[String]`はランダムな文字列を生成します。

# 自動導出の仕組み

Scala 3のコンパイル時リフレクション機能を使うと、ケースクラスや列挙型（enum）などの構造を解析し、それに基づいて`Arbitrary`インスタンスを自動生成できます。

```scala
import org.scalacheck.Arbitrary
import org.scalacheck.Gen

import scala.compiletime.{erasedValue, error, summonFrom, summonInline}
import scala.deriving.*

trait LowPriorityScalaCheckDerive {
  given arbitraryProduct[T](using mirror: Mirror.ProductOf[T], arbitrary: Arbitrary[mirror.MirroredElemTypes]): Arbitrary[T] = Arbitrary {
    arbitrary.arbitrary.map { (v: mirror.MirroredElemTypes) =>
      mirror.fromProduct(v)
    }
  }
}

object ScalaCheckDerive extends LowPriorityScalaCheckDerive {
  inline def summonGens[T, Elems <: Tuple]: List[Gen[T]] =
    inline erasedValue[Elems] match
      case _: (elem *: elems) =>
        summonInline[Arbitrary[elem]].arbitrary.asInstanceOf[Gen[T]] :: summonGens[T, elems]
      case _: EmptyTuple =>
        Nil

  inline given arbitrarySum[A](using mirror: Mirror.SumOf[A]): Arbitrary[A] =
    Arbitrary(Gen.sequence[List[A], A](summonGens[A, mirror.MirroredElemTypes]).flatMap(Gen.oneOf))

  given arbitraryCaseObject[T](using v: ValueOf[T]): Arbitrary[T] =
    Arbitrary(Gen.const(v.value))
}

object ClientApp extends App {
  import ScalaCheckDerive.given

  sealed trait OS
  case object Windows extends OS
  case object MacOS extends OS
  case class UnknownOS(name: String) extends OS
  case class Device(name: String, os: OS)

  println(Arbitrary.arbitrary[Device].sample) // 例: Some(Device(쇭띋⎗䗜燴䭛淌￰舂렴銴쟳熬䞆嶱ⶫ녫簭勺뇘ዮ琿鵟胵㏻鮩箛먁İ᱙岢옯ᰐ䌐ꦞ,Windows))
}
```

# 解説

1.  **`LowPriorityScalaCheckDerive`:**
    *   優先度の低い`given`を定義するためのトレイトです。
    *   `arbitraryProduct`は、`Mirror.ProductOf[T]`（case classのミラー）と`Arbitrary[mirror.MirroredElemTypes]`（case classの各フィールドの型の`Arbitrary`）が与えられた場合に、`Arbitrary[T]`を生成します。
2.  **`ScalaCheckDerive`:**
    *   `LowPriorityScalaCheckDerive`を継承し、追加の`given`を定義します。
    *   `summonGens`は、直和型（sealed trait）の各ケースクラス/オブジェクトに対応する`Gen[T]`のリストを生成します。
    *   `arbitrarySum`は、`Mirror.SumOf[A]`（直和型のミラー）が与えられた場合に、`Arbitrary[A]`を生成します。
    *   `arbitraryCaseObject`は、case objectに対応する`Arbitrary[T]`を生成します。
3.  **`ClientApp`:**
    *   `ScalaCheckDerive.given`をインポートすることで、`ScalaCheckDerive`で定義された`given`を利用できるようにします。
    *   `Arbitrary.arbitrary[Device]`を呼び出すと、`Device`型の値をランダムに生成できます。

# 注意点

* このコードは、case class、case object、sealed trait、enumなどの基本的な型に対しては自動的に`Arbitrary`を導出できますが、より複雑な型や再帰的な型に対しては対応できない場合があります。
* 再帰的な型や複雑な依存関係を持つ型に対しては、手動で`Arbitrary`インスタンスを定義する必要があります。

# まとめ

Scala 3のコンパイル時リフレクション機能を活用することで、多くのケースで`Arbitrary`インスタンスを手動で定義する手間を省くことができます。これにより、プロパティベーステストの作成がより簡単になります。

# 参考

https://qiita.com/tobita_yoshiki/items/e400a40d885332c552a9

https://qiita.com/tobita_yoshiki/items/2fce8ce693668aebcd5b
【2024マラソン12】HHKB studio x 左手テンキーで数値入力が爆速になった

# 何の記事？
HHKB公式が左手テンキーを推していたので、憧れの左手テンキーができるようにキーマップを変更しました。

https://x.com/pfu_hhkb/status/1768468954257993854?s=46&t=DUJLbot82x9HRSAYY3YT2w

# 誰向け？ どんな役にたつ？

- 左手でのテンキー入力に興味がある人
- 数字入力を行いながら右手で書類チェックなど別の作業をしたい人
- HHKB studio持ちで数字入力の頻度が高い人
- 通常の数字キーだと入力が大変な人

# あらすじ
本職は総務経理のため、テンキーを使った数字入力がついて回ります。
そのため、HHKBを使い始めた時にFn2キーを押すと、右手のファーストポジションでテンキーのように入力できるよう設定しました。

ただ、テンキーを使って数字を入力している時って、そもそも参照元の数字が書かれた書類が手元にあることが多く。
すると、右手で書類チェックをしつつ、左手で入力できたら楽なのになぁ……となるわけです。
キーボードをHHKBに変える前から、左手入力をする用のテンキーがあればなぁと思っていました。

今回、HHKB公式がXにて左手テンキーについて発信しているのをみてそれを思い出し、早速設定して使ってみることにしました。

# キーマップ
#### 初期設定
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/964152/68a8bafc-9cb9-d2ee-163b-e62d7cbbab1d.png" width=300>

右手でテンキー入力する時と同じ配置を、左手のホームポジションに持ってきました。

余談ですが、Fn2キーの位置が両手親指で押しやすい位置にあることを利用して、Fn2+数字キーでタスクバーのアプリを起動&切替できるようにもしています。

#### 安定するまでのカンペを作成
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/964152/9657d1c5-ed44-14f0-3ca1-aa471417443d.png" width=300>

左手でテンキー入力をしたことがいままでなかったので、記号などわからなくなった時ようにカンペを作り、PCモニターの下に貼り付けて使いました。

#### 追加設定
左手だけでカーソル移動もしたくなったので、Fn1+Fに「↓」、Fn1+Bに「↑」を割り当てました。
左手のみで数字を入力しつつ、入力箇所の微移動も左手で行う編成です。

余談ですが、vimerの為、hjklでも移動できるように割り当てています。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/964152/bc11ec96-90d7-d20b-1288-d9fbe03d7cf1.png" width=300>

# 入力スタイル
#### アームレスト必須
左手部分のみの小型アームレストがあると、左手オンリーで疲れることなく入力を続けられます。
私は裏紙を重ね合わせて作りましたが、購入する場合は[公式の持ち歩きできるタイプ](https://www.amazon.co.jp/バード電子-セパレート型ウッドパームレスト-WP-90-WN/dp/B08NPNX1GF/ref=mp_s_a_1_11?adgrpid=138886949193&dib=eyJ2IjoiMSJ9.o13unrN2Nl7HeP6w3rZGj--Ll6Tc5jc5AeZTc0KKkOwfC1w9nw_THJrgbgrSUB1iee0dAYCzHn7fi3MbdDGqZim8YGSAeUCWBKCSk9WP6fyGUfOCQhTPcBN_c2vacLN2vS_H174Q7EpvgurwAgfFvhapahQOsQ1vUbTYRZLYdiBVisFsbtXbpab0c219DG0ybubRUD1DPZxwS703eDENfw.ptyNEfg2Gw5OlMkGeotiPTUDGjSCOS5nAESkw0l5NoI&dib_tag=se&hvadid=651308434742&hvdev=m&hvqmt=e&hvtargid=kwd-918322110680&hydadcr=11535_13428658&keywords=パームレスト+hhkb&linkCode=plm&qid=1719640487&sr=8-11)がおすすめです。

#### 指サックも必要
右手オンリーで伝票をめくりながら入力していくので、右手は指サックがないと辛いです。
私はタイピングに影響が少ないリングタイプのものを使っています。

下記のメクリンは安価で色の主張も弱く、指のサイズに合わせた展開もあるのでオススメです。
1個数ヶ月〜一年位保つので、1袋で4,5年は戦えます。

https://www.amazon.co.jp/コクヨ-リング型紙めくり-メクリン-ブルー-メク-522TB/dp/B0012RAGGI/ref=mp_s_a_1_5?adgrpid=152403103437&dib=eyJ2IjoiMSJ9.T55wZcPPf9bz5jvGlEv7ZstB-y6NmVE-FgLCWHNl6qLoumCdjz87ISFbT8stX8Bo-ls45NDd4i4o5EWrpmEGKgmLc0cdvU6FDu0NHFkVmKzgf2utWjbuTm9M79fhjRYCj5kIfUlPIy3wrTaXk_3Exa9t_KPxwqhwnvK0k3nl5bnndSck_iqFP8FJEyOcylKMLY8dwKjEikW5F8LkS9WcDw.2Y2iikOQsQUU3yhMpjkvurB3oJV3XUUKNYIYDuuLjPU&dib_tag=se&hvadid=669830804288&hvdev=m&hvqmt=e&hvtargid=kwd-1433341437511&hydadcr=25620_13564954&keywords=コクヨ+紙めくり+メクリン&linkCode=plm&qid=1719640766&sr=8-5

# 結果
慣れてからは効率も上がり、なによりも入力ストレスが格段に減りました。
今までは一通り入力した後で伝票とチェックして確定……とやっていたのが、入力直後にチェックし、入力完了したら確定！……とできるようになったので、とてもスムーズに入力できるようになりました。この辺りはテンキー備え付けキーボード民の頃には味わえなかった爽快感です。
また、右手でマウスを操作しつつ、左手で入力という選択肢が増えたことで、Excelの入力なども捗っています。キーマップ変更最高……！

# 隠れた推しポイント
HHKB **studio**を使ってる人にだけわかるんですが、Fn2キーという、キーボード中心のキーの位置が絶妙なんですね。
このキーが右手左手問わず親指で楽に押せる位置にあり、テンキーは親指を使わなくてもほぼ入力できるので、相性が抜群でした。
studio持ちで数字入力が多めの人にはぜひ試してみて欲しいキーマップです。
プルリクを彩るLGTMOONの紹介

## LGTMoonとは？
https://lgtmoon.herokuapp.com/
LGTMoonは、シンプルなインターフェースを持つWebアプリで、キーワードを入力するだけでLGTM画像を生成できます。
キーワードから画像を検索したり、自身でアップロードすることも可能です。

![スクリーンショット 2024-06-29 14.57.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3803835/d67d9095-c5de-97a8-6098-761bbb481f6e.png)

実際に以下の画像のようにレビューの際に使用してみたください！
![スクリーンショット 2024-06-29 15.00.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3803835/07657de7-90a1-784a-dff8-2392dab144ae.png)

僕のおすすめは激昂したイージャンです。ラージャンの躍動感とLGTMの意でラージャンからイージャンになっていてとても秀逸です。
![LGTM_イージャン.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3803835/190473f8-f85f-aa03-3da2-a2935d2017a3.jpeg)

## まとめ
LGTMoonは、コードレビューを楽しくし、効率化してくれます。エンジニアの方々はぜひ一度試してみてください！
ScalaCheckでEnumの値を自動生成する

# 概要

Scala 3から導入されたEnumは、列挙型を表現するための機能です。
ScalaCheckを使って、Enumの値を自動生成する方法を解説します。

# Enumとは？

Enumは、Scala 3で導入された列挙型を定義するための新しい方法です。
従来のsealed traitとcase objectの組み合わせよりも簡潔に、型安全な列挙型を定義できます。

```scala
enum Item:
  case Pen, Eraser, Note
```

# ScalaCheckでのEnumの自動生成

ScalaCheckは、プロパティベーステストのための強力なライブラリです。ScalaCheckの`Arbitrary`型クラスを使って、Enumの値を自動生成してみましょう。

```scala
import org.scalacheck.Arbitrary
import org.scalacheck.Gen

import scala.compiletime.{erasedValue, error, summonFrom, summonInline}
import scala.deriving.*

object ScalaCheckSumType extends App {
  inline def summonGens[T, Elems <: Tuple]: List[Gen[T]] =
    inline erasedValue[Elems] match
      case _: (elem *: elems) =>
        summonInline[Arbitrary[elem]].arbitrary.asInstanceOf[Gen[T]] :: summonGens[T, elems]
      case _: EmptyTuple =>
        Nil

  inline given arbitrarySum[A](using mirror: Mirror.SumOf[A]): Arbitrary[A] =
    Arbitrary(Gen.sequence[List[A], A](summonGens[A, mirror.MirroredElemTypes]).flatMap(Gen.oneOf))

  given arbitraryCaseObject[T](using v: ValueOf[T]): Arbitrary[T] =
    Arbitrary(Gen.const(v.value))

  enum Item:
    case Pen, Eraser, Note
  println(Arbitrary.arbitrary[Item].sample) // => Some(Pen) or Some(Eraser) or Some(Note)

  sealed trait Color
  case object Blue extends Color
  case object Green extends Color
  println(Arbitrary.arbitrary[Color].sample) // => Some(Blue) or Some(Green)
}
```

# 解説

1.  **`summonGens`:**
    *   この関数は、Enumまたはsealed traitの各ケースに対応する`Gen[T]`のリストを生成します。
    *   コンパイル時リフレクションを使って、Enumまたはsealed traitの構造を解析し、各ケースに対して再帰的に`Gen[T]`を生成します。
2.  **`arbitrarySum`:**
    *   この`given`は、`Mirror.SumOf[A]`のインスタンスが与えられた場合に、`Arbitrary[A]`のインスタンスを生成します。
    *   `summonGens`を使って、Enumまたはsealed traitの各ケースに対応する`Gen[T]`のリストを生成します。
    *   `Gen.sequence`と`Gen.oneOf`を使って、生成された`Gen[T]`のリストからランダムに1つを選び、`Arbitrary[A]`を生成します。
3.  **`arbitraryCaseObject`:**
    *   この`given`は、`ValueOf[T]`のインスタンスが与えられた場合に、`Arbitrary[T]`のインスタンスを生成します。
    *   `Gen.const`を使って、常に同じ値を生成する`Arbitrary[T]`を生成します。これは、case objectに対応する`Arbitrary[T]`を生成するために使用されます。

# まとめ

この記事では、ScalaCheckを使ってEnumの値を自動生成する方法を紹介しました。
DKIMで電子証明書を採用しなかった理由

# はじめに
　DKIMとは，メールの送信者の認証とメッセージの改ざんの検出を行う仕組みです。この記事では「DKIMにおける検証方式として，電子証明書ではなく，なぜDNSを採用したのか」という疑問に対する調査結果を紹介します。なお，DKIMの仕組みや最近話題に取り上げられることが多い背景は，この記事では扱いません。

# 結論
　結論を先に述べると，電子証明書という新たなインフラがメール送受信の仕組みに関与することに起因する混乱を避けるためです。

# 電子証明書
　電子証明書は，認証局によって発行された証明書で，公開鍵を含みます。第三者（認証局）から発行してもらう電子証明書によって公開鍵を証明し，ひいては暗号鍵の正当な持ち主であることを保証する仕組みです。認証局が関与することから，電子証明書を利用した暗号化や署名は（秘密鍵を正しく扱う場合においては）機密性や完全性を担保するために有効な仕組みです。
　したがって，DKIMに電子証明書を適用して送信メールを認証する方式は優れたアイデアです。しかし，DKIMでは電子証明書ではなく，DNSのレコードに公開鍵を公開する方式を使っています。

# RFCによると
 DKIMの概要は，[RFC5585](https://tex2e.github.io/rfc-translater/html/rfc5585.html)に規定されています。このドキュメントでは以下のように述べられています（[1.2. Prior Work](https://tex2e.github.io/rfc-translater/html/rfc5585.html#1-2--Prior-Work)より引用)。

> Further, DKIM's key management is provided by adding information records to the existing Domain Name System (DNS) [RFC1034], rather than requiring deployment of a new query infrastructure. This approach has significant operational advantages. First, it avoids the considerable barrier of creating a new global infrastructure; hence, it leverages a global base of administrative experience and highly reliable distributed operation. Second, the technical aspect of the DNS is already known to be efficient. Any new service would have to undergo a period of gradual maturation, with potentially problematic early-stage behaviors. By (re-)using the DNS, DKIM avoids these growing pains.

意訳してみました。
> 　DKIMの鍵管理では、新しいクエリインフラストラクチャの展開（訳注：電子証明書を採用したPKIなど？）を要求するのではなく、既存のDNSにレコードを追加することにより提供されます。このアプローチは運用上の利点があります。
> 　1点目は，新しいグローバル基盤を構築する（訳注：メール基盤の再構築？）という障壁を避けることができます。そのため、グローバルな運営経験と信頼性の高い分散運営を基盤としています（訳注：すでに存在するメール基盤を活用できる？）。
> 　2点目は、DNSの技術的側面はすでに効率的であることが知られています。どのような新しいサービスであっても、初期段階での動作に問題が生じる可能性があり、徐々に成熟していく期間を経なければならないけません。DNSを（再）利用することで、DKIMはこうした成長の痛みを回避することができます。


# RFCの解釈
　RFCを解釈すると，次の2点が挙げられます。
 - 今までうまく動いていた仕組みはそのまま活用した方が良い（この仕組みにはDNSも含まれると解釈できます）
 - DNSを活用することで，導入初期のトラブルを押さえることができる
  
　つまり，DKIMの導入にあたっては，新しい仕組み（電子証明書）の導入ではなく枯れた技術（DNS）をできるだけ活用しながら，移行時の混乱を避けたい，ということのようです。

# まとめ
　メールのようにインターネット全体で分散・協調して動く仕組みを，ある日一斉に新しい仕組みに切り替えることはできません。新旧のシステムがあちこちで混在し，徐々に新しい仕組みに集約されていきます。プロトコルを設計する側（IETF）としては，相互運用性に加え，混在期間中・移行期間中に混乱を招かないような配慮も必要だったのでしょう。実際，DNSを使ったDKIMであっても，GoogleがGmailに適用することで大混乱したのは記憶に新しいところです（Googleは悪者ではない）。DKIMに電子証明書を導入したとすると，これ以上の混乱が起きることは想像に難くありません。
　このような混乱を最小限に抑えるために，DKIMではDNSのレコードを採用したようです。


# その他
　「SMTPSやPOP3S，IMAP4Sでは以前から電子証明書（サーバ証明書）を使ってるのでは？」というツッコミもあろうかと思います。確かにこれらのプロトコルでは電子証明書を利用します。ただ，これらのプロトコルは下位層（トランスポート層相当）のTLSで電子証明書を利用しているだけで，その上位層であるメール送受信の仕組みに直接関与しているわけではありません。
　また，私見ですがOpenSSLといったTLSライブラリを使わずに済むといった利点もあると考えます。TLSライブラリではX.509の証明書検証に関する脆弱性が見つかることがあり（最近だとCVE-2022-3602、CVE-2022-3786など），これらの脆弱性を悪用すると，受信側のメールサーバに悪影響を与えることも考えられます。電子証明書を使わなければ，TLSライブラリの脆弱性の影響を避けることができます。
　その他に，電子証明書を使わない理由として，電子証明書のコストや処理負荷を理由として説明しているサイトも見受けられました。しかしながら，RFCにはコストや処理負荷を理由として電子証明書を採用しなかった，という記載は私には見つけられませんでした（もしかしたらどこかにあるかもしれませんが，その場合には是非教えてください）。以降は私見です。確かに電子証明書の費用や，電子証明書の処理に伴う処理負荷は，導入する側からしてみると考慮が必要な事項ではあります。ただ，HTTPSでの普及の実績を踏まえると，メール送受信に関してだけコストや処理負荷があるので除外というのは，標準化においては考えづらいと考えます。


# 参考文献
https://www.nic.ad.jp/ja/basics/terms/dkim.html
https://tex2e.github.io/rfc-translater/html/rfc5585.html
ScalaCheckでProduct型の値を自動生成する

# 概要

この記事では、ScalaCheckを用いてプロダクト型の値を自動生成する方法を示します。

# ScalaCheckとは？

ScalaCheckは、プロパティベースのテストを支援するScalaのライブラリで、与えられた性質（プロパティ）がプログラムのある条件を満たすことを検証するために使用されます。
これにより、ランダムなデータ生成を用いて広範な入力値をテストできます。

# プロダクト型の自動生成

以下は、ScalaCheckを使ってプロダクト型（ケースクラスなど）の値を自動生成する方法を示すサンプルプログラムです：

```scala
import org.scalacheck.Arbitrary
import scala.deriving.*

object Main extends App {

  // プロダクト型の任意の値を生成するgivenインスタンスを定義
  given arbitraryProduct[T <: Product](using mirror: Mirror.ProductOf[T], 
                                        arbitrary: Arbitrary[mirror.MirroredElemTypes]): Arbitrary[T] = Arbitrary {
    arbitrary.arbitrary.map { (v: mirror.MirroredElemTypes) =>
      mirror.fromProduct(v)
    }
  }
  
  // 例: いくつかのケースクラスを定義
  trait Data
  case class Hoge(v: Int, s: String, fuga: Fuga) extends Data
  case class Fuga(boolean: Boolean)

  // 使用例: Hogeの任意のインスタンスを生成して出力する
  println(Arbitrary.arbitrary[Hoge].sample) // 標準出力例: Some(Hoge(-2147483648,鯃᠗춊ퟑ㗂ﰆ㣘⣟뮈홎⮚耩⼳◧୲௵䀫뻞眊ꢑ鹍,Fuga(false)))
}
```

# 解説

### (1) arbitraryProduct
**`arbitraryProduct`の`given`インスタンス**: このインスタンスはScala 3で導入された新しい機能を利用して定義されています。これには以下のパラメータが必要です：
    - `mirror`: `T`型のプロダクトのコンパイル時ミラーを表します。
    - `arbitrary`: `T`型の各要素型に対する`Arbitrary`インスタンスを提供します。

`Arbitrary`ブロック内で、`arbitrary.arbitrary`は`T`型の要素型のタプルを生成します(`v: mirror.MirroredElemTypes`)。そして、`mirror.fromProduct(v)`はこれらの値を使用して`T`型のインスタンスを構築します。

### (2) arbitraryProductの引数arbitraryについて

一見、`Arbitrary[mirror.MirroredElemTypes]`が手に入らなさそうに思えるかもしれないですが、
ScalaCheckでは標準で`Arbitrary[タプル]`が利用可能なので問題ありません。

```scala
scala> Arbitrary.arbitrary[(Int, String, Boolean)]
val res0: org.scalacheck.Gen[(Int, String, Boolean)] = org.scalacheck.Gen$$anon$7@30cb489a
```

### (3) 例としてのケースクラス (`Hoge`と`Fuga`)

これらは実世界のシナリオでよく見られるネストされたケースクラスの例を示しています。

### (4) 使用例

最後に、`Hoge`の任意のインスタンスを生成し、その結果を出力しています。このインスタンスには、`Fuga`のようなネストされた型を持つフィールドのランダムな値が自動的に設定されます。
【CakePHP5】GitHubのPush時にPHPUnitでテストする

# はじめに

こんにちは、エンジニアのkeitaMaxです。

今回は前回作成したPHPUnitをGitHubActionsでGitHub上でテストできるようにしようと思います。

前回

https://qiita.com/keitaMax/items/7327c83cea938fe124f9

# GitHubActionsのymlファイルを作成

GitHubActionsを作成します。

以前Laravelで作成したものを参考にしようと思います。

https://qiita.com/keitaMax/items/bbfecbdb73322b53bb4c

```yml:phpunit.yml
name: phpunit

on: [pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: ./src
    steps:
      - uses: actions/checkout@v2
      - name: docker-compose up
        run: |
          docker-compose up -d
      - name: composer install
        run: |
          docker compose exec app composer install
      - name: phpunit
        run: |
          docker compose exec app composer test

```

# GitにPushしてGitHubで実行する

GitHubにPushすると以下のように実行されます。

![スクリーンショット 2024-06-29 15.13.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715123/e5e23f7b-a86d-edac-e1af-6d166be11887.png)


そして処理が終わると、下のように全てにチェックがつきます。

![スクリーンショット 2024-06-29 15.15.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715123/3ae2ec81-afbc-8cf5-f878-66edb1974a43.png)



# 失敗させてみる

ちゃんと動いているかを確認するためにわざとPHPUnitのテストを失敗させてみます。

失敗するようにコードを修正しPushすると、以下のように失敗しているので、正しくテストが実行できていることが確認できました。


![スクリーンショット 2024-06-29 15.11.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715123/4b6f4083-8a20-cd46-aad7-e0b70b3e832a.png)


# おわりに

この記事での質問や、間違っている、もっといい方法があるといったご意見などありましたらご指摘していただけると幸いです。

最後まで読んでいただきありがとうございました！
EFをSQLと併用するには

EntityFrameworkを使いつつ、SQLを書くという都合のいいことができないかなぁと夢想しているとサポートされていたので学習録📓

:::note info
FromSql()とLinqが併用可能
※EFCore7以前ならFromSqlInterpolated()をつかう
:::

# FromSql()の例
## 単純なselect
```C#
var blogs = context.Blogs
    .FromSql($"SELECT * FROM dbo.Blogs")
    .ToList();
```

## Where
```C#
var param = "Taro"
var blogs = context.Blogs
    .FromSql($"SELECT * FROM dbo.Blogs WHERE USER = {param}")
    .ToList();
```
この書き方でSQLInjection大丈夫なんか、と思いますが自動でSQLParameterに展開してくれるそうです。すごいですね


# EFのメソッドと組み合わせ

## whereをLinqで指定
```diff_c_sharp
var param = "Taro"
var blogs = context.Blogs
    .FromSql($"SELECT * FROM dbo.Blogs")
+   .Where(x => x.User == param)
    .ToList();
```

上記の仕組みを使ってSQL内で関数を使い、フィルタ結果をプログラム内にて使用することでパフォーマンス改善に役立てないか目論見中…
状態変数をスプレッド構文を使用し更新する

# はじめに

配列やオブジェトの値を簡単に展開できるスプレッド構文について勉強したので、備忘録も兼ねて本記事を作成しています。


# スプレッド構文とは？

スプレッド構文とは、配列やオブジェクトの要素を展開するための構文です。
三つのドット `...` を使用し配列やオブジェクトを`...array` 、 `...object` を展開します。
`push`などの破壊的な変更を加えることなく、新しい要素の作成を行うことができ便利です。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Spread_syntax

# サンプル 
配列とオブジェクトの場合でスプレッド構文を使ってみます。

### 配列の場合

```javascript
const array1 = [1, 2, 3];
const array2 = [...array1, 4, 5];
console.log(array2); // [1, 2, 3, 4, 5]
```

### オブジェクトの場合

```javascript
const obj1 = { key1: 'hoge1', key2: 'hoge2' };
const obj2 = { ...obj1, key3: 'hoge3' };
console.log(obj2); // { key1: 'hoge1', key2: 'hoge2', key3: 'hoge3' }
```

# スプレッド構文を使った状態変数の更新

下記の例では `useState` フックでオブジェクトを作成し、`updateUser` 関数でプロパティ名と更新後の値を受け取り、状態変数 `user` を更新します。
この関数ではスプレッド構文を利用して、既存の状態を維持しながら指定されたプロパティだけを更新します。

```tsx:App.tsx
import { useState } from "react";
import './App.css'

interface User {
  name: string;
  sports: string;
  food: string;
}

const UserProfile = () => {
  const [user, setUser] = useState<User>({
    name: 'hogeName',
    sports: 'baseball',
    food: 'apple'
  });

  const updateUser = (key: keyof User, value: string) => {
    setUser(prevUser => ({
      ...prevUser,
      [key]: value
    }));
  };

  return (
    <div className="main">
      <h1>{user.name}</h1>
      <h1>{user.sports}</h1>
      <h1>{user.food}</h1>
      <button onClick={() => updateUser('name', 'TAROU')}>名前更新</button>
      <button onClick={() => updateUser('sports', 'soccer')}>スポーツ更新</button>
      <button onClick={() => updateUser('food', 'onigiri')}>好きな食べ物更新</button>
    </div>
  );
}

export default UserProfile;
```

<details><summary>App.css</summary>

```css:App.css
body {
  padding: 0;
  margin: 0;
  width: 100%;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
}

.main {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

button {
  margin: 10px 0;
}
```

</details>


# 動作確認

サーバを立ち上げて動作を確認します。

```
npm run dev
```

![download.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1247619/546b47e5-85e1-2fd4-fe65-d73b71bd3826.gif)



# 参考

https://zenn.dev/axpensive/articles/6f35d3da03044f

https://ama-tech.hatenablog.com/react-spread-syntax

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Spread_syntax
［DataSaberへの道②］

## はじめに
2回目の投稿となります。技術課題(ord1～10）がすべて終了いたしました。
今回はそれぞれのordで気になったポイント、難しかったポイントについてまとめていきたいと思います。

### 総評
・KTチャンネル(https://www.youtube.com/playlist?list=PLR1ulf4cyh2lTnNKO1m3_VGgKRLczHOgO)
を隈なくみながら回答にたどり着くまでに1ヵ月半ほどかかりました。一発でクリアできたものもあれば、鬼門ord4については7回ほどかかりました、、、

### ord1
・シンプルかつ基本的な内容が詰まっているもの
・Tableau初心者研修を実施する際、ここからスタートするには十分すぎる材料がそろっている印象

### ord2
・ダッシュボードを作成する上での基本の基
・Preattentive Attributesをはじめとする、Tableauにおける大原則が学べる
・Saberを目指していない人にとっても、ord1・2だけで研修するのでもかなり学びは多い

### ord3
・ord1＋応用的な立ち位置
・ブレッドチャートが印象的（個人的に好き）

### ord4
・鬼門
・本当に細かい言葉の違いで正解／不正解、が分かれるパート
・”これはやっちゃいかんだろう”をできるだけ正確に見つけ出せるかがポイント

### ord5
・ord3に引き続き応用的な立ち位置
・割と基本的な話がメインであり、ここまでできればおおむねtableauは触れるようになった。

### ord6
・ここまでは知識とか正解不正解が割と明確だった印象だが、ord6はかなり自分で考える部分が多くなる
・かなり実践的でvizの良し悪しを見る基本的な目を養えた
・これはやっちゃいけないなが見えてくる

### ord7
・正直ここまで考えなければならないのか、と最初は思ったが”使いこなす”レベルまで行くには必要な知見
・実務でのデータ分析等においてもこのあたりはかなり重要であり、過去自分自身もtableauで分析をしたときにここを知っていればだいぶパフォーマンスが変わっていたなと思う部分があった。
（個人的には結構楽しかった、）

### ord8,9
・関門LOD計算理解大変、、
・２～３回やらないと覚えきれない印象だったが、実業務でがっつり分析をするならここまで求められるレベル感であった

### ord10
・これもやってはいけないをいかに見つけ出せるかが重要
・問題自体は難しくない

## 最後に
技術課題はDataSaberを受験せずとも本当に学べるコンテンツが多い。自分自身もかなり成長できた。
社内等で研修をする際、非常に有用なものがそろっていることは間違いないと感じた。
約一か月でAI-102に合格した話

## はじめに
AI-102のバウチャーを入手したことをきっかけに受験し、合格したので対策方法と所感を残しておきたいと思います。

## AI-102とは
Microsoft Azureの資格です。
正式名称はAzure AI Engineer Associateです。
詳しくはこちらの公式サイトを確認してもらうと良いと思います。

https://learn.microsoft.com/ja-jp/credentials/certifications/azure-ai-engineer//?practice-assessment-type=certification  

## 受験のきっかけ
Microsoft Learn Cloud Skills Challengeで無料のMicrosoft認定資格試験の受験資格を獲得したため  

https://learn.microsoft.com/ja-jp/training/challenges?id=da09d3ca-a2bb-47dc-ba42-bea77b386a3d&ocid=aisc24_cloudskillschallenge_email_cnl

## 試験対策を始める前の前提状態
 * AWSを業務で使用(AWS SAA,SOA取得済み)  
 * Azureは未経験  
 * 昨年AI-900合格済  
 * Microsoft Learn Cloud Skills Challengeで試験範囲のMicrosoft Learnを一部学習（途中期限近かったので飛ばしました）  

## 受験結果
問題数：51問  
試験時間：140分  

結果：751点でなんとか合格できました。  


以下使用したドキュメントや問題集です。  

## 使用した参考書
①Microsoft公式AI-102の試験要綱ページ内の試験の準備の欄にある「Designing and Implementing a Microsoft Azure AI Solution」
https://learn.microsoft.com/ja-jp/training/courses/ai-102t00/  

②Microsoft公式AI-102の試験要綱ページ内「無料の実践評価を受ける」で受けることができる模擬試験  

③WhizlabsのAI-102の模擬試験のみ  
https://www.whizlabs.com/microsoft-azure-certification-ai-102/  

②の公式サイトの模擬試験は1問ごとに答え合わせができるので隙間時間に気軽に対策ができて良かったです。  
ただし、公式サイトの模擬試験の注意点として以下がありました。  

 * 公式サイトの模擬試験は解答に誤りがあるものがある  
 * 問題文や解答の選択肢の内容が英語から訳したためかわかりづらい  
なので周回し、  
解説を読んでもよく分からなかった場合は①のコースの読みなおしや、解説の箇所に貼られているリンクの公式ドキュメントを読むという流れを繰り返しました。  
私は試験まで2週間の時点で、模擬試験は安定して8割正解している状態でしたが、模擬試験の難易度よりも本試験の難易度の方が高いという情報を目にし、不安になったので③のWhizlabsを利用しました。
 
続いて、試験まで2週間迫った時に利用し始めた③のWhizlabsの模擬試験ですが、本試験と難易度は同じ程度だったと思います。  
ただし、模擬試験によくあるような、同じもしくは似た問題は出ませんでした。  
また、③のWhizlabsの不便だった点として以下があります。  

 * 問題文や解説が読みづらい  
 * 解答に誤りがあることがある  
 * 時々問題を解いている途中でエラーになってしまいやりなおしになってしまうことがある  
 
Whizlabsの場合は言語の選択ができるので、画面の翻訳やDeepLを使用せずに解くことができるのですが、訳さなくてもよいサービス名や機能を訳されていることがあるので、少し読みづらさがありました。  
また、Whizlabsの模擬試験は最終問題を除き一問ごとに解答が確認できるようになっているのですが、公式サイトの模擬試験同様に解答が間違っているものや、詳しい解説が無い問題が多かったです。  
また、問題を解いている途中でエラーになってしまうことが多かったです。  

色々不満を記述してしまいましたが、本試験に近い難易度だったことや、Udemyの問題集と異なり一問ごとに解答を確認できる点、各問題の解答に公式ドキュメントの問題内容に関連したリンクが貼られていて、解答の理由や関連知識の内容について調べやすかった点から考えると利用する価値は充分あると思います。  


## 所感
### 受験環境について
テストセンターで受験したので自宅環境の場合は分からないですが(おそらく同じはず)、  
去年AI-900を受験した時と比較して試験画面が非常に使いやすくなっていて驚きました。  

個人的に使いやすくて良かった機能は以下です。  
 * 画面のモードがダークモードが選択できるようになっていた    
 * 日本語と英語の切り替えがメニューバーからできた    
 * 回答状況や進捗状況もメニューバーから確認できるようになっていた  
 * Microsoft Learnもメニューバーから開けるようになっており、画面の半分をMicrosoft Learn、もう半分を試験画面というように使用することができた  
 
### 試験について
具体的な問題の内容は伝えられないですが、一部見直しができない問題があったので注意が必要だと思いました。  
ただし、全ての問題でMicrosoft Learnを使用することができたので、見直しができない問題であってもしっかり調べて解くことができました。  
実際に試験が始まるまでは、Microsoft Learnを使用できるのか疑っていたのですが、本当に使用できたので良かったです。  
反省点としては、後でMicrosoftLearnで調べようと思い急いで解いて、残り40分は見直しの時間にできたのですが、結局時間が足りず半分しか見直しができなかったことです。  
Microsoft Learnの検索画面から欲しい情報を調べる技術も必要だなと思いました。  

ここまで試験を受けた所感を記載しましたが、対策としては、公式の模擬試験もwhizlabsの模擬試験も何周も解くことと、わからないところを無くすこと、公式ドキュメントをしっかり読むことが重要だと思います。  
また、Microsoft Learnの検索技術も身に着けられるともっと良いと思います。  


最後に、AI-102の受験を検討している方の参考になれば幸いです。  

## 参考

https://learn.microsoft.com/ja-jp/credentials/certifications/azure-ai-engineer//?practice-assessment-type=certification  

https://www.whizlabs.com/microsoft-azure-certification-ai-102/