OmniAICreator/Qiita-1.07M huggingface dataset:
javaのラムダ式を自分なりに解釈してみた

# はじめに
ラムダ式とは、java8から追加されたプログラムの記述方式のことです。その中でよくわからない部分が少しあったので自分なりに解釈してみました。

まず最初に、この手の記事を調べるときに出てくるワード「匿名クラス」「関数型インターフェース」について説明し、そのあとラムダ式の説明をします。

# 匿名クラスとは
インターフェースの実装をせずに「クラス宣言」「インスタンス生成」を行える便利なものだと解釈します。通常はインタフェースの実装を行い、メソッドを呼び出すコードを書くので、通常と比べるとはるかに楽ですが、可読性が少し下がるような気がします。

# 関数型インターフェースとは
抽象メソッドを１つだけもつインターフェースのことを指します。メソッドをインターフェースのような扱いができるので便利です。

# ラムダ式とは
関数型インターフェースを実装したインスタンスを生成する式と言え、匿名クラスを使用するより可読性が高いものになります。イメージでいうと下記の形になります。
`インターフェース 変数 = (引数) -> {処理}`


# ラムダ式の例
上記の匿名クラスや関数型インターフェースを用いて通常の方法からラムダ式を使うまでの例をコードで確認します。

### 共通準備
<details><summary>Printer.java</summary>

```java:Printer.java
@FunctionalInterface
public interface Printer {
    void print();
}
```
</details>


<details><summary>IconPrinter.java</summary>

```java:IconPrinter.java
public class IconPrinter implements Printer{
    @Override
    public void print() {
        System.out.println("アイコンを印刷");
    }
}
```
</details>

#### 通常の場合
```java:Main.java
public class Main {
    public static void main(String[] args) {

        IconPrinter iconPrinter = new IconPrinter();
        iconPrinter.print();
    }
}
```


#### 匿名クラスを使用した場合
```java:Main.java
public class Main {
    public static void main(String[] args) {

        Printer printer = new Printer() {
            //メソッドをオーバーライド
            @Override
            public void print(){
                System.out.println("内容を印刷");
            }
        };
        printer.print();
    }
}
```

#### ラムダ式を使用した場合
```java:Main.java
public class Main {
    public static void main(String[] args) {

        Printer printer = () -> {
            System.out.println("内容を印刷");
        };
        printer.print();
    }
}
```

# メソッド参照
ラムダ式を使用せずにすでに定義済みのメソッドを、引数なしで呼び出せるのがメソッド参照です。ラムダ式より短くかけるので便利です。イメージでいうと下記の形になります。
`クラス名::メソッド名`

# 最後に
何が言いたいかというとラムダ式最高！皆さん使いましょう
AWS SAA合格体験記：アナリストの実感

## はじめに
AWS 認定ソリューションアーキテクト – アソシエイトを2023年6月に受験、合格したので合格までの学習と取得してみた感想を共有する。
私自身の状況は
* データアナリスト：データエンジニアの方をサポートしながら分析基盤の運用を行っている。
* 業務でAWSは利用しているが、インフラは領域外
## AWS SAAとは
AWSが公式に認定している資格の一つ。難易度としては下から2番目。
対象者として、AWSのサービスを使用するクラウドソリューション設計の実務経験が1年以上を想定している模様。

https://aws.amazon.com/jp/certification/certified-solutions-architect-associate/
## 学習期間
1カ月半～2カ月程度、40~50時間
大体1日1時間でUdemyの講座を進め、完了後1週間演習問題を解いた
## 学習内容
利用したのは下記二つ。

* **Udemy【SAA-C03版】これだけでOK！ AWS 認定ソリューションアーキテクト – アソシエイト試験突破講座**
https://www.udemy.com/share/101XFi3@Sx3qFAB3fXnuSK-Rvb9VMFY-kZPYaDkqNjNGFdkX32toCi1aMERudSm3_EoQosnVow==/
  Qiitaの合格体験記でよく利用されている講座だったので受講を決定。
  サービスの紹介＋ハンズオンの形式で各章ごとに小テストがあり、最後に試験想定の演習が3回分用意されている。
  目的が試験に合格することで費用をかけたくない場合はハンズオンは飛ばしても問題ない。実務での経験が十分な方も飛ばしてよいだろう。ただ、対象となるサービスが多く実務で触ったことのないものもあるため、2倍速でもざっと眺めることをお勧めする。
  試験想定の演習が本番よりも難易度が高いというコメントをいくつか見かけた。たしかに少し難しいように感じたが、演習で間違えた部分の復讐をしっかりしたことが合格につながったと感じている。

  
* **問題集サイト** 
  https://aws-exam.net/saa/saa_question.php
  無料で試験想定の問題を390問も解説付きで掲載してくれているサイト。本番試験よりやや易しい問題が多い。
  問題ごとに利用者のコメントがあるが、有益な解説もあれば少しイライラするようなものもあるのであまり読む必要はないかもしれない。
  CBT形式で知識を問う試験のため、「この単語が問題文に登場した場合このサービスが回答の選択肢に入る」といった暗記が可能。
## 合格した感想
基本的には暗記した知識を問われるので、演習でどれだけ記憶漏れを埋められるかが合否を分けると思う。一方でよく出題されるサービスは決まっていて、RDSやALBやCroudFrontなど何が問われるかの傾向を押さえていたので試験中に落ち着いて回答ができた。

社内評価のための資格取得はたいていの場合とるだけの資格となり評価に反映されたら忘れていくだけだろう。しかし、内容が網羅的かつAWSという市場価値のある領域の知識であるため、今まで取得した資格の中では最も実用性を感じたし、自身の成長も実感した。

学習・取得後の実務上での変化についても共有したい。
### よかったこと
* 自分の携わる部署以外のインフラ構成に関しておおざっぱでも使われているソリューションの理解ができるので、システムの全体像であったり、自分たちの運用しているデータ基盤の上流に何があるのかを把握しやすくなった。
* エンジニアの方との知識のギャップが埋まったため、MTGでついていけなくったり聞き流したりすることが減った。

### イマイチだったこと
* 設計に携わる業務ではないため知識以上の貢献は難しい。特にインフラの設定周りの知識はついても実践に至らない。
* 広く浅くであるため、自身の担当分野の学習としては物足りない。
## お勧めする人
* 未経験～微経験のインフラエンジニア、データエンジニア
エンジニアであれば1~2年目でも取得できるような資格だと思う。クラウドを使うインフラの保守・運用者や現場に配属されたばかりの新人でも取得すれば基礎理解としては十分な知識が得られる。また、この先の資格にステップアップしていく足掛かりとしても取得するべきだと考える。
* AWSを利用している企業のプロパー社員
ベンダーやSIerに構築・運用を依頼する立場のプロパー社員には取得をお勧めする。
* AWS環境を利用しているデータアナリスト・サイエンティスト（インフラより）
インフラに近い部署で働くアナリスト、データサイエンティストは業務上データ基盤やパイプラインに関してエンジニアと会話したり、支援することがある。
* 会社が取得を推奨している人
上記に当てはまる人はこちらにも当てはまるだろうが、資格が評価につながり費用も負担してくれる会社であれば学習を勧める。市場価値の高いクラウドについて体系的に、網羅的に知識を獲得できる。
BigQueryジョブの実行元を確認する方法

GCPの監査ログから、BigQueryジョブの実行元を確認する方法を残しておきます。

Log RouterからBigQuery向けのsinkが作成されていることを想定します。

監査ログの概要やsinkを作成する方法については、以下の公式ドキュメントを参考してください。

https://cloud.google.com/logging/docs/overview?hl=ja

https://cloud.google.com/logging/docs/export/configure_export_v2?hl=ja#overview

ログを受信する特定のデータセットをに対して、以下のクエリを実行します。
実行すると、BigQueryジョブ毎に、どこから実行されていたかが分かります。

```sql
WITH
base AS (
SELECT
  resource.labels.project_id,
  protopayload_auditlog.authenticationInfo.principalEmail AS email,
  REGEXP_EXTRACT(protopayload_auditlog.resourceName, r'^projects/[\w-]+/jobs/([\w-]+)$') as job_id,
  timestamp,
  protopayload_auditlog.requestMetadata.callerSuppliedUserAgent AS user_agent,
  protopayload_auditlog.metadataJson AS metadata_json
FROM
  `<プロジェクトID>.<データセットID>.cloudaudit_googleapis_com_data_access_*`
WHERE
  timestamp > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 7 DAY)
  AND operation.first = true
),
audit AS (
SELECT
  CASE 
    WHEN starts_with(job_id, 'scheduled_query_')
      THEN 'scheduled_query'
    WHEN starts_with(job_id, 'script_job_')
      THEN 'script_job'
    WHEN starts_with(job_id, 'bquxjob_')
      THEN 'bq user interface'
    WHEN starts_with(job_id, 'job_') AND json_value(metadata_json, '$.jobInsertion.job.jobConfig.type') = 'EXPORT'
      THEN 'BQ UI data export to Google Drive'
    WHEN starts_with(job_id, 'sheets_dataconnector_')
      THEN 'sheets_dataconnector'
    WHEN starts_with(job_id, 'job_') AND json_value(metadata_json, '$.jobInsertion.job.jobConfig.labels.requestor') = 'looker_studio'
      THEN 'looker_studio'
    WHEN starts_with(job_id, 'job_') AND user_agent LIKE 'Tableau%'
      THEN 'tableau'
    WHEN starts_with(job_id, 'job_') AND user_agent IS NOT NULL
      THEN user_agent
    WHEN regexp_contains(job_id, '^[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}$')
      THEN 'google-colab'
    ELSE 'unknown'
  END execution_source,
  json_value(metadata_json, "$.jobInsertion.job.jobConfig.queryConfig.query") AS query,
  *
FROM
  base
),
sheets_info AS (
SELECT
  job_id,
  'https://docs.google.com/spreadsheets/d/' || json_value(metadata_json, '$.firstPartyAppMetadata.sheetsMetadata.docId') as sheet_url,
  json_value(metadata_json, '$.jobInsertion.job.jobConfig.labels.sheets_trigger') AS sheets_trigger,
FROM
  base
)

SELECT
  project_id,
  email,
  timestamp,
  execution_source,
  query,
  sheet_url,
  sheets_trigger
FROM
  audit a FULL OUTER JOIN sheets_info s
    ON a.job_id = s.job_id
```
BigQueryのジョブIDは、その実行元のタイプによって決まりますので、IDからどの実行元に基づいたかを推測できます。
実行元のタイプがSpread Sheetだった場合、クエリを実行したシートの情報まで確認できます。

INFORMATION_SCHEMAからスロット消費量などを追加して、どこでスロットを消費しているのかも確認できますね
（Spread Sheet以外はurlを確認するのは難しいですが。。）

ジョブIDの分類は公式ではなく、経験に基づいていますが、もっとよい方法があったらコメントください。
ChatGPT の Advanced Data Analysis を触ってみる

## やってみたこと

Chat GPT の Advanced Data Analysis を触ってみます。
とりあえず、[金沢市のオープンデータ](https://portal-data.city.kanazawa.ishikawa.jp/)から[公衆トイレの一覧](https://catalog-data.city.kanazawa.ishikawa.jp/dataset/172014-public_toilet)（CSV）をダウンロードし、このファイルを Chat GPT に分析してもらいました。

※ Advanced Data Analysis は Chat GPT Plus の機能です。
詳しくは以下のサイトが参考になると思います。

https://generativeinfo365.com/?p=192

## 準備

Chat GPT にログインし、GPT-4 の機能を有効にします。
Chat GPT 設定にある Beta features の Advanced data analysis を有効にします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72641/174e2e78-305b-3743-75ac-0584c3f420dd.png)

これで、プロンプトにファイルアップロード用のボタンが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72641/b345fdc4-0eb9-eb39-3dd9-6418016b7967.png)

## 公衆トイレの数を求めてみる

CSVファイルをダウンロードし、以下のようにお願いしてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72641/ba8cdba0-0ef8-0d04-4c36-3b2887a85021.png)

とりあえずファイルを読み込んでくれたっぽいです。
`Show work` のボタンを押してみると、python のコードが表示されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72641/a1ebc8ab-1fca-2c78-2f21-b7a96cba8c39.png)

ちゃんと pandas で CSV を読み込んで、なんかやってますね。

男性用トイレの数を聞いてみたのですが、男性トイレだけでも4種類のデータがあるので、どのデータを使うか聞かれました。お任せしてもよかったのですが、まずはカラム名を指定してお願いしてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72641/5c861a4c-4e6d-b2cd-2188-0f5cb4828df6.png)

手元でCSVファイルを開いて確認したところ、たしかに124ありました。
これもコードを見てみると、読み込んだデータフレームをちゃんと集計しています。
（変数名もなんかそれっぽい）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72641/d32945c1-99f8-00b3-2523-d925712ba77f.png)

次に、男性と女性のどっちが多いか聞いてみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72641/31bb258a-e5ab-2b3a-9a4f-7fa8f85dcae5.png)

手元で確認すると確かに女性トイレの総数は59で、男性トイレの方が多いです。
コードはこんな感じ。最後の文はなんか面白いですね。単にどっちが多いかを求めるだけでなく、具体的な数を示すためにわざわざややこしい文を書いてくれてるように見えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72641/29935ee6-0545-f839-1a26-9e5048306912.png)

ということで、自分でコードを書かなくてもデータ分析してくれました。
この程度のことは Excel でマウスを数クリックするだけで求められますが、ちゃんと pandas でデータフレームを読み込んでくれてるので、統計量を求めるといった複雑なこともできるはずです。
select_relatedはいつ使うべき？

## 初めに
Djangoに携わっている人は、親子関係にあるテーブルの情報を扱う際に、特定の親テーブルの情報を持つ子テーブルのみ取得するということがよくあると思います。（後で具体例を用いて説明します）
その時の手法としてFilterとSelect_relatedどちらかを使うでしょうか？
明確に使い所を切り分けて使っている方はこれより先読まなくても大丈夫です（笑）

それ以外の方！
filterじゃダメなのか、どういう状況でselect_relatedを使うのか、紹介できればと思います。
まず今回使うテーブルのモデル定義をしていきます。

## モデル定義
今回はJリーグのサッカーチームとそれに所属する選手のモデルを作成しました。
```python:modesl.py
from django.db import models

class Team(models.Model):
    name = models.CharField(max_length=20)
    # J1、J2のような所属ランク、本来ならマスターテーブルで管理するが、今回は例なので文字列で管理
    rank = models.CharField(max_length=20)

class Member(models.Model):
    team = models.ForeignKey('Team', on_delete=models.CASCADE,)
    name = models.CharField(max_length=20)
    age = models.PositiveSmallIntegerField()
    salary = models.IntegerField()
```

上記のようなモデルがある時、以下の場合はどのように情報を取得しますか？

## 取得したい情報
1. J1に所属している選手のみ取得したい場合
1. J2に所属している選手とそのチーム名を取得したい場合

それぞれfilterとselect_relatedどちらを使うでしょうか？（考えてみてください。）

#### 取得したい情報①
> J1に所属している選手のみ取得したい場合
```python:main.py
qs = Member.objects.filter(team__rank="J1")
for qs_obj in qs:
    print(qs_obj.name)
```
実際にコンソール出力してみると、、、
```python:console
>>> for qs_obj in qs:
...     print(qs_obj.name)
... 
大迫 勇也
山口 蛍
宮市 亮
杉本 健勇
>>>
```
こんな感じでJ1に所属している選手を取得できました！

#### 取得したい情報②
では、次に
>  J2に所属している選手とそのチーム名を取得したい場合
```python:main.py
qs = Member.objects.select_related("team").filter(team__rank="J2")
for qs_obj in qs:
    print(f'{qs_obj.team.rank}所属:{qs_obj.team.name}  氏名:{qs_obj.name}')
```
実際にコンソール出力してみると、、、
```python:console
>>> for qs_obj in qs:
...     print(f'{qs_obj.team.rank}所属:{qs_obj.team.name}  氏名:{qs_obj.name}')
... 
J2所属:ＦＣ町田ゼルビア  氏名:アデミウソン
J2所属:ＦＣ町田ゼルビア  氏名:髙橋大悟
J2所属:清水エスパルス  氏名:権田修一
J2所属:清水エスパルス  氏名:乾貴士
```
こんな感じになります。

## 違いは？
「filterとselect_relatedの使いどころの違いは、親要素の情報も取得したいかどうか」という点にあると思います。
つまり、取得したい情報①と情報②は一見同じクエリセットですが、情報①で取得したクエリセットはTeamオブジェクトを含みません。つまり、J1のチームに所属する選手は取得できても、J1のチーム名を取得したいとなったら、再度SQLが発行されてしまうということが起こります。
一方select_relatedであれば、親要素をオブジェクトとして持つので、そのようなことは起こりません。
よって、「親要素の情報も取得したいかどうか」によってFilterか　select_relatedを使い分けると良いです！
Dataverseのリレーションシップについて備忘録

Dataverseってよくわからないですよね。
今回はDataverseについてちょっと勉強したことについて簡単にまとめていきます。


## 1:NとN:Nの関係
### 1:N
一つのテーブルに複数のテーブルがつながっている。この場合1の方が上位であり、Nの方が下位である。上位のテーブルを「プライマリテーブル」とも呼ぶ。
例)1:N=母親:子供。1人の母親に複数の兄弟がいる。テーブルの関係上母親が上位、子供が下位。
### N:N
複数のテーブルに複数のテーブルがつながっている
例)友人関係。教室の中で複数の人が複数の人と友人。

## テーブルの関連付け
* 関連付けあり
    正式なテーブル。クエリ可。
* 関連付けなし
    「つながり」とも言う。正式ではない関連付け。たとえば取引先担当者が職場外の友人であるなど、非公式だが把握しておくとよい情報。非公式なためテーブルに関連付けしない。

## ビジネスプロセス
例えば新しい営業担当者に別の担当者の取引先企業を引き継ぐときなどの、条件をつけてビジネスプロセスを自動割り当てできる。
* すべてのタスク活動を再割り当てします。
* すべてのタスクを再割り当てします。
* タスクを全く再割り当てしません。
* 現時点では、すべてのタスクを取引先企業の以前の所有者に再割り当てします。

## 継承されたアクセス権のクリーンアップ
プライマリテーブル(親テーブル)が関連テーブル(子テーブル)との間のアクセス権をクリーンアップすることができる。

## 参考文献
だいぶ嚙み砕いて記述したので、正確な情報は以下の公式ドキュメントを参考にしてください。
https://learn.microsoft.com/ja-jp/power-apps/maker/data-platform/create-edit-entity-relationships
10進数→2進数への変換(整数)

# 10進数を見たら分かる1ビット

83という数値が与えられたら、最初に分かることがあります。
それは83を2進表記したときに一番右のビットが1であるということです。

なぜ分かるかといえば、83が奇数だからです。

2進数にすると<font color="Red">その数が偶数か奇数かという情報は一番右のビットに集約されます。</font>



2進表記を10進表記にする際は、次のように計算するのはよく目にします。

1111 = 8 * 1 + 4 * 1 + 2 * 1 + 1 * 1

これはつまり、一番右以外のビットは必ず2の倍数であることを示しており、2進表記における奇数や偶数は一番右のビットが1(奇数)か0(偶数)かによって判断することができるということです。

# 10進数を2^xで割った商が偶数か奇数かで判明するビット


### 2進数のシフトとは

まずはシフトすることの意味を知る必要があります。
2進数に2を掛けると1ビット左にシフトします。

1111 → 11110

なぜかと言えば、10進数に置き換えて考えると分かりやすいのですが
10進数に10を掛けると一桁左にシフトするのはなぜ？と考えるようなもので、当たり前の現象だと納得してしまうのが早いです。

623 * 10 = 6230

気を付けるべきことは、2進数を2で割ったり10進数を10で割ったりするときに、一番右の桁が余りとして出てくるということです。

(10進)
623 / 10 = 62 あまり 3

7348 / 10 = 734 あまり 8

(2進)
1111 / 10 = 0111 あまり 0001 

101101 / 10 = 010110 あまり 000001

※2進の10は十ではなく2です
### つまり83は2進数でどうかくの？

83 = XXXXXXXXというブラックボックスが与えられたときに、83は奇数であるため、2進表記をしたときに一番右のビットが1であることは最初に述べました。


83 = XXXXXXX1

これを2で割るということは

(A) 83 / 2 = 41 あまり 1

(B) XXXXXXX1 / 10 = 0XXXXXXX あまり 00000001



というように、2進数を1ビット右にずらし、商とあまりに分けることを意味します。
(A)と(B)は10進か2進かの違いで数値は対応しています。

次に知りたいのは(B)の商の一番右の桁が0か1かということです。

つまり

83 / 2 = 41 あまり 1

の商である41が偶数であるか奇数であるかがわかれば0XXXXXXXの一番右のビットが1か0かが分かります。

41は奇数ですから、一番右のビットは1です。
これを順に繰り返していくと下のようになります。

83 / 1  = 83 あまり 0
83 / 2  = 41 あまり 1
83 / 4  = 20 あまり 3
83 / 8  = 10 あまり 3
83 / 16 = 5  あまり 3
83 / 32 = 2  あまり 19
83 / 64 = 1  あまり 19

商に着目してください。
商が偶数であるか奇数であるかが分かればいいので、商83, 41...と順番に見ていくと1100101となります。

これを反対から読んで1010011が83の二進表記になります。

2進数に置き換えると下記のようになります。
ABCDEFG / 2^0 = ABCDEFG あまり 0
ABCDEFG / 2^1 = 0ABCDEF (以下あまり略)
ABCDEFG / 2^2 = 00ABCDE
ABCDEFG / 2^3 = 000ABCD
ABCDEFG / 2^4 = 0000ABC
ABCDEFG / 2^5 = 00000AB
ABCDEFG / 2^6 = 000000A

83を2^xで割ることで2進表記をしたときにxビット右にシフトすることができます。
するとその商の偶奇を判断することで、2進表記の一番右のビットが0か1かが判断できますから、10進数から2進数へ変換することができるという仕組みになっています。

83 = ABCDEFG
41 = ABCDEF
20 = ABCDE
10 = ABCD
5 = ABC
2 = AB
1 = A

上記を見たらすべてのビットが分からなくても、最右ビットが0か1かは瞬間で分かります。

G→F→E→D→C→B→Aという順番で各桁のビットが0 or 1が判明していきます。

83 = ABCDEF1
41 = ABCDE1
20 = ABCD0
10 = ABC0
5 = AB1
2 = A0
1 = 1

よって83は2進表記で1010011。

もっと言えば、よく見る下の2進数変換方法は、2で割った余りで最右ビットを保存して、2で割った商が1ビット右シフトなので、下位の桁から順に余りとして出てきているだけです。
10進数が偶数なら2進表記をしたときに最右ビットが0,奇数なら1になるのは最初で述べました。

83 = 1010011　→ 2で割った余り → 最右ビット保存 [1]
↓1ビット右シフト
41 = 0101001 [1]
↓
20 = 0010100 [0]
↓
10 = 0001010 [0]
↓
5 = 0000101 [1]
↓
2 = 0000010 [0]
↓
1 = 0000001 [1]


当たり前ではあるものの、これが本記事で伝えたかった事項です。
Pythonのrequestsライブラリが読み込んでいるrootCA証明書の場所を確認するワンライナー

# はじめに
プロキシ環境下などにおいて、独自のrootCA証明書を読み込ませずにPythonでrequestsを行うとSSL証明書エラーが発生する。

requestsが読み込んでいる証明書に独自のrootCA証明書を追記すれば解決できるのだが、毎回読み込んでいる証明書の場所と確認方法を忘れてしまうので、自分向けの備忘として残しておく。

## 環境
Python 3.11.2

# 読み込んでいる証明書のパスを確認するワンライナー
pythonコマンドにcオプションをつけると、囲った中でコード実行ができる。
```shell
$ python -c "import requests; print(requests.certs.where())"

# /usr/local/lib/python3.11/site-packages/certifi/cacert.pem ※Linuxはこんな感じ
# C:\Users\<ユーザー名>\AppData\Local\Programs\Python\Python311\Lib\site-packages\certifi\cacert.pem ※windowsはこんな感じ
```
requestsの証明書は依存パッケージであるcertifi内のcacert.pemで管理されている。

[requestsのソース](https://github.com/psf/requests/blob/main/src/requests/certs.py)を見るとわかるが、上記コードはcertifiを呼び出しているだけだったりする。

大元は以下の[コード](https://pypi.org/project/certifi/)。

> #### Usage
> To reference the installed certificate authority (CA) bundle, you can use the built-in function:
> 
> ```py
> >>> import certifi
> 
> >>> certifi.where()
> '/usr/local/lib/python3.7/site-packages/certifi/cacert.pem'
>```

したがって、以下のようなワンライナーも可能（普通は実行しないが）。
```shell
$ python -c "import certifi; print(certifi.where())"
```

# おわりに
記事にしてみると単純にメモするだけでなくて一定根拠も調査する必要があるため、知識が拾えてよかった。

cオプションでコード実行ができることも、覚えておくと役立つ気がした。

## 参考
- [certs.py - requests github](https://github.com/psf/requests/blob/main/src/requests/certs.py)
- [certifi - PyPI](https://pypi.org/project/certifi/)
- [1. コマンドラインと環境 — Python 3.11.5 ドキュメント](https://docs.python.org/ja/3/using/cmdline.html)
AWS re:InventでAivenを紹介

<font color="Grey">*[Meet Aiven at AWS re:Invent](https://aiven.io/blog/meet-aiven-at-aws-re-invent)の翻訳です。*</font>

2022年11月25日

# AWS re:InventでAivenに会う

毎年恒例のAWS re:Inventにお越しの際は、Aivenの場所をご確認ください。

Aivenは、Amazon Web Service（AWS）の年次イベントreに参加するためにラスベガスに向かっています。reは、クラウド技術、イノベーション、情報共有に関するあらゆることが行われる「行く」業界会議であり、Aivenのキャストに最適な場所です。


AivenはAWSのパートナーとして、Apache Kafka®、OpenSearch®、Cassandra®などの最も人気のあるオープンソース・サービスをフルマネージド・サービスとして提供しています。お客様は、AWS、AWS Marketplace、または独自のAWSアカウントでこれらのサービスを実行することができます。Aivenはまた、CloudWatch、S3、Private Linkのような多数のAWSサービスとのより深い技術統合を提供します。


コムキャスト、エバーアクティブ、Pafといった当社の共同顧客は、AivenのサービスをAWS上で実行し、オープンソース技術でAWSスタックを拡張しています。


reに参加し、接続したいですか？Aivenをより深く知っていただくために、様々な方法をご用意しています。


## ブース2347までお越しください。


Aivenのフルマネージド・オープンソースサービスについて詳しくご説明いたします。専門家チームとさらに詳しく打ち合わせたい方は、[ミーティング枠のご予約](https://calendly.com/aiven-amer/reinvent?month=2022-11)をご利用ください。


## 2022年12月1日 Aiven Insights at re


木曜日午後1時からVEN - Lightning Theater 2にて、Aiven CISOのJamie Arlenが "Modern AppDev and AppSec cloud solution architecture strategy "について講演します。


ジェイミーは、オープンソースとクラウド・データの世界の交差点について、また、より多くのデータを管理しながらそこから価値を引き出すという期待には、インフラストラクチャの問題解決からビジネスの問題解決への戦略転換が必要であることについて話します。この有益な講演に参加し、目標を達成する方法について学びましょう。


## 2022年12月1日「開発者に乾杯」に参加する


Aivenのデベロッパーリレーション担当副社長であるイアン・マッシンガムが、AWSのチーフエバンジェリストであるジェフ・バー、TailscaleのDevRel担当シニアイベントマネージャーであるケイティ・リースと共に、"DevRel & コミュニティ構築のビジネスインパクト "について対談します。世界中の開発者、開発支援者、DevRelリーダー、コミュニティ・ビルダーと一緒にパネルディスカッションとブランチを楽しみましょう。イベントは午前11:00にスタートし、11:15に対談が始まります。[RSVPオンライン登録はこちらから](https://commonroomatreinvent.splashthat.com/)。


## ラスベガスでお会いしましょう！


ブースにお立ち寄りいただき、ソリューション・アーキテクチャー・チームとお話しいただいたり、イベント期間中に別の方法でAivenにお知り合いになっていただくことも可能です。Aivenのオープンソースデータプラットフォームについて、またAivenがお客様のビジネスの構築と成長にどのように貢献できるかをご紹介できることを楽しみにしております。


#### まだマネージド・データ・プラットフォームをお探しですか？

見つかりました！

[今すぐ無料トライアルにお申し込みください](https://console.aiven.io/signup)

Aivenと私たちのサービスに関する最新ニュースや、オープンソースに関する様々な情報を入手するには、[月刊ニュースレターを購読](https://aiven.io/newsletter)してください！Aivenに関する日々のニュースは、[LinkedIn](https://www.linkedin.com/company/aiven/)と[Twitter](https://twitter.com/aiven_io)のフィードでご覧いただけます。


サービスのアップデート情報を知りたい方は、[変更履歴](https://aiven.io/changelog)をご覧ください。
最速(?)最短(?) Amazon Bedrockの動かし方はこれだ

boto3は1.28.57でBedrockに対応しました。

```shell
pip install -q -U boto3
```

**bedrock** と **bedrock-runtime** があるので注意。invoke_modelはbedrock-runtime

```python
import boto3
import json

client = boto3.client('bedrock-runtime')

prompt = '''
Human: こんにちは！
Assistant:
'''

body = {
    'prompt': prompt,
    'max_tokens_to_sample': 300,
}

response = client.invoke_model(
    modelId="anthropic.claude-v2",
    body=json.dumps(body)
)

body = response['body'].readlines()

completion = json.loads(body[0].decode('utf-8'))['completion']

print(completion)
```

回答
```
 はい、こんにちは。よろしくお願いします。
```
OneLoginからSalesforce Marketing Cloudにシングルサインオン(SSO)ログインできるように設定してみた

Salesforce Marketing CloudへのログインをOneLoginからボタンを押すだけでログインできるようシングルサインオン設定をしましたので残しておきます。

## 設定の流れ
1. Salesforce Marketing Cloud（以下SSO）のメタデータの取得
2. OneLoginにSMCのメタデータを設定する
3. OneLoginのメタデータを取得する
4. SMCにOneLoginのメタデータを設定する
5. SMCのSSO設定を有効化する
6. ユーザ単位でSSO設定を有効化する
7. ログイン確認


## SMC側のメタデータの取得

### SSOの有効化設定がされてるか確認

複数ビジネスユニット(以下BU)を契約している場合は親BUで確認する。

##### 確認方法
[セットアップ] > [管理] > [データ管理] > [キー管理] > [作成]
有効化されている場合は [SSO メタデータ] というラジオボタンが表示される。
![スクリーンショット 2023-09-28 18.05.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87351/cb1fa189-21bc-4801-28b7-24bb02474602.png)

表示されない場合は、SSO が有効になっていない可能性があるのでサポートに問い合わせをして有効化してもらう必要があります。


### SAML メタデータの取得

#### 取得方法
[セットアップ] > [設定] > [セキュリティ] > [セキュリティ設定] > [シングルサインオン設定] > [SSO SAML メタデータ] (ボタン)
![スクリーンショット 2023-09-28 18.20.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87351/f8ed863a-581a-3466-d86d-a63b822c1d08.png)

メタデータのダウンロードボタンを押下するとXMLが表示されるのでコピーしてテキストエディタなどに貼っておくといいと思います。




## OneLoginにSMCのメタデータを設定する

以下に従ってOneLoginにテキストエディタにメモしたメタデータを設定する。
https://help.salesforce.com/s/articleView?id=000389134&type=1


## OneLoginのメタデータを取得する

OneLoginの[管理] > [Applications] > [作成したアプリケーション（SMC）] > [右上のセレクトボックス] > [SAML Metadata]

上記よりXMLをダウンロードする


## SMCにOneLoginのメタデータを設定する

[セットアップ] > [管理] > [データ管理] > [キー管理] > [作成]

#### 設定項目

▼Key Type
SSOメタデータ
 
▼SSO メタデータ
「メタデータの貼り付け」にチェック

▼メタデータの貼り付け
OneLoginのメタデータの<EntityDescriptor>タグから全てを貼り付ける


上記を設定し「保存」する


## SMCのSSO設定を有効化する

[セットアップ] > [設定] > [セキュリティ] > [セキュリティ設定] > [シングルサインオン設定] > [SSO を有効化] で設定を選択またはオンにして [保存] を選択


## ユーザ単位でSSO設定を有効化する

[セットアップ] > [ユーザー] > [ユーザー] に移動して、SSOでログインしたいユーザを選択する。
[SSO を有効化] オプションを選択して、IDP 側で設定された[フェデレーションID](https://www.onelogin.com/jp-ja/learn/federated-identity)を設定する。

#### 注意点
SSOでログインする場合、通常のログイン（ID/PASSWORDを入力）をすることが出来なくなります

## ログインの確認
OneLoginからログインできるか確認してみます。

OneLoginの画面から設定したアプリケーションを選択します。
![スクリーンショット 2023-09-29 4.19.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87351/8cc6c60b-6e51-3e64-c762-34e404617b3a.png)

SMCにログイン出来れば成功です。
![スクリーンショット 2023-09-29 4.23.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87351/87fb03d1-e4e5-4651-d1f4-61e265198d41.png)
ガード節について

# はじめに
現在、railsを使う現場で働いてますが、コードレビューでうけた指摘を定着し、記憶に残すために投稿します！

# 【結論】ガード節を使った書き方

**要件**
ある特定のユーザー名`param[:name]`が渡される。
* `users`テーブルに情報がある場合
さらに`purchases`テーブルを検索し、当該ユーザーの購入記録を取得する。
* `users`テーブルに情報がない場合
処理を終了する。

**ガード節を使わない書き方**
```ruby
def index
    if param[:name].present?
        @user = User.find_by(user_name: param[:name])
        if @user.present?
            @purchases = Purchase.find_by(user_id: @user.id)
            if @purchases.present?
                # 購入記録がある場合の処理
            else
                # 購入記録がない場合の処理
            end
        else
            return
        end
    end
end
```

**ガード節を使う書き方**
※ 学習のため、あえて`if`と`unless`どちらも使っています。
```ruby
def index
    return if param[:name].blank?

    @user = User.find_by(user_name: param[:name])
    return unless @user.present?

    @purchases = Purchase.find_by(user_id: @user.id)
    if @purchases.present?
        # 購入記録がある場合の処理
    else
        # 購入記録がない場合の処理
    end
end
```

# メリット
上記の例でいうと、メインの処理となるのはユーザーの購入データの取得と結果に応じた処理の部分。
エラーなどを防ぐためにパラメータやデータの存在の有無を確認する処理をはさむことは多いがこれらはメインの処理でないし、データが存在しない場合は先の処理を行わない仕様となるはずである。

ガード節を用いて早期リターンを行うことで
* 不要な処理を行うことがなくなる。しかもそれが視覚的に伝わる。 
* ifの重ねがけによるネストが軽減される。

# 参考
https://zenn.dev/adverdest/articles/16a698200fd872
https://zenn.dev/kingdom0927/articles/2b9d8ec1becf8b
【React】リストや配列からレンダリングされる要素に記述するkeyについて

:::note
Reactでは、リストや配列からレンダリングされる要素には一意の Key が必要。
Key は、どの要素が変更、追加もしくは削除されたのかを React が識別するのに役立つ。配列内の項目に安定した識別性を与えるため、それぞれの項目に key を与えるべき。
:::

#### 修正前
下記のようなnumbers という配列を受け取って要素のリストを出力するコードを実行すると、「**リスト項目には key を与えるべきだ**」という警告を受け取る。

```typescript
function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <li>{number}</li>
  );
  return (
    <ul>{listItems}</ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<NumberList numbers={numbers} />);
```


#### 修正後

* 兄弟間でその項目を一意に特定できるような文字列を key として選ぶのが最良の方法
* グローバルに一意である必要はない
* レンダーされる要素に安定した ID がない場合、最終手段として項目のインデックスを使う(非推奨)
    * なぜ非推奨？
    * 要素の並び順が変更される可能性がある場合、パフォーマンスに悪い影響を与え、コンポーネントの状態に問題を起こす可能性があるため。（明示的に key を指定しない場合、React はインデックスを key のデフォルト値として使う）

```typescript
function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <li key={number.toString()}>
      {number}
    </li>
  );
  return (
    <ul>{listItems}</ul>
  );
}
```


---

参考リンク

https://ja.legacy.reactjs.org/docs/lists-and-keys.html
Amazon BedrockがGAしたので遊んでみる(粗製乱造)

# 何の記事？
AWS上で複数の生成AIのモデルが利用できるサービスであるBedrockがGAしてので、触ってみる

# Amazon Bedrockについてはこちら
https://aws.amazon.com/jp/about-aws/whats-new/2023/09/amazon-bedrock-generally-available/


# 手順

- AWSのコンソールからBedrockを検索 (おぉ出てくる！) 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573632/1be59ec4-528b-5152-5603-832b8175f578.png)

- 利用するリージョンを選択する
  しばらくしたら東京リージョンも出そうだが、とりあえずバージニア北部を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573632/9a5de29e-409e-a46e-9a8d-4a151378efa7.png)

- Get startedを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573632/c076eeee-82a8-533c-dc14-3946e306f90a.png)

- モデルの利用のためのアクセス申請を行う必要があるので、Mange model accessを押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573632/0d2fa4f6-8013-1946-829a-169c0979c3d3.png)

- モデル選択画面。申請したいモデルにチェックを入れて、Editを押下
- 今回は日本語対応のTextモデルであるClaudeを申請する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573632/f6936db3-0b8d-d495-3fa1-e753d96ef150.png)

- スクショを取り忘れたが、企業名、URLなどを入力し、個人情報とか含む？とか利用目的を入力して申請を行う

- しばらくするとAccess grantedになるので、利用できるようになる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573632/737d0a66-65f6-385c-f13b-c9cd54746b54.png)

- 画面左のメニューのPlayGrundから、利用したいユースケースを選択
  今回は、とりあえずChatを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573632/b1105b8a-f40b-2bc0-4c9f-f08a002855bb.png)

- モデルを選択する
　先ほど申請したAnthropicのCluade を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573632/92113702-19fc-07d1-98dc-d55bd1ac1726.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573632/57ce5775-9bab-218c-f780-7ef9c5ca3891.png)

- チャットできた！！
  まぁ、GPT-４とかに比べると精度は落ちるのかもしれないが会話する分には問題ない
　当たり前だが、学習後に世の中に出力された最新情報は拾えない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573632/e248b240-1cf8-8f31-2367-ccfb3ed7cb8f.png)

- Stable diffusionもつかえた
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573632/76ca53e4-2571-aeb2-7cd5-676e634d31f9.png)


# 感想
まぁ、後発ではあるがAWSで業務構築している企業が生成AIをやってみるのにはいい気がする
VPC内部からVPC endpoint経由でAPI叩けるならばかなり強い気がする

複数のユースケースが1か所のコンソールにまとまるのも便利
[SQLServer] パフォーマンス検証をする際に気を付けること

## はじめに
SQLServerを使用した業務でパフォーマンス検証をする機会が増えてきたため、その際に意識していたことを備忘として記事にまとめます。

## 実行中クエリの確認
測定対象のクエリを実行する際に、裏で別のクエリが動いていた場合、SQLServerは並列処理として各クエリに対してメモリの領域を確保して処理します。
そのため、単独で実行した場合と並列で実行した場合で処理速度に差が出る場合があります。

パフォーマンスを測定する際は、バックアップや定常処理などが実行されないタイミングの確認をしたり、環境を占有して測定するために各所への調整を実施したりなど、単独での処理時間を計測できる環境を整えておきましょう。

逆に、実際の稼働環境で並列処理が行われている場合、単独で計測してしまうと実際の処理時間と異なるため、同じ環境を再現するために裏の処理を動かすなど調整が必要になるため注意しましょう。

``` sql:実行中クエリ確認
SELECT
  sqltext.TEXT,
  req.session_id,
  req.status,
  req.command,
  req.cpu_time,
  req.total_elapsed_time
FROM
  sys.dm_exec_requests req
CROSS APPLY
  sys.dm_exec_sql_text(sql_handle) AS sqltext
```

実行中のクエリを停止したい場合は、上記の実行結果から取得したsession_idを指定してKILLコマンドを実行すれば停止が可能です。
※停止しても問題ないことは確認してください

```sql:クエリの停止(KILL)
KILL {session_id}
```

## キャッシュ
SQLServerは実行されたクエリのキャッシュを保持しており、そのキャッシュを使用し実行されたクエリの実行計画を作成します。
そのため、別のキャッシュが登録されている環境でクエリを実行しても、同じパフォーマンスの結果にはならない可能性があり、実際の環境で測定する必要があります。

しかし、実際の環境でパフォーマンス測定できる機会は稀だと思います。
確認したいパフォーマンスの値とは異なりますが、最も悪い時のパフォーマンスを測定して比較するという意味で、キャッシュをクリアした状態でパフォーマンスを測定することが多いです。

```sql:キャッシュクリア
DBCC DROPCLEANBUFFERS  -- データバッファキャッシュのクリア
DBCC FREEPROCCACHE     -- メモリキャッシュのクリア
```

パフォーマンスを測定する前には必ずキャッシュをクリアするようにして、一定の値を測定して比較するようにしましょう。

:::note warn
本番環境でキャッシュをクリアしてしまうと、定常的に動作しているクエリのパフォーマンスを悪化させてしまう危険があります。
キャッシュをクリアしても問題ない環境であることを確認したうえで実施をお願いします。
:::

## 統計情報

#### 統計情報の作成

SQLServerにおける統計情報とは、テーブルの中でどのような値がどのような頻度で存在しているかをまとめた情報のことを指します。
この情報を使用して、SQLServerが最適なクエリの実行プランを算出します。(*1)
(*1)：https://learn.microsoft.com/ja-jp/sql/relational-databases/statistics/statistics

統計情報はテーブルの列ごとに作成されます。
SQL Serverは初期設定で統計情報の自動作成がONになっているため、ストアドプロシージャやビューでテーブルの項目を参照した時に、自動的に統計情報が作成されます。
明示的に作成する場合は、以下のコマンドを実行してください。

```sql:統計情報の作成
CREATE STATISTICS statistics_name
    ON { database_name.schema_name.table_name | schema_name.table_name | table_name }
```

1回目のクエリ実行時に参照列の統計情報が存在していない場合は、クエリが始まる前に統計情報の自動作成処理が開始されて時間を要する場合があります。
パフォーマンスを測定する場合は、2回目以降で統計情報が作成されてから実行することをお勧めします。

#### 統計情報の更新

統計情報は常時更新されているわけではないため、テーブルに対してデータの変更処理が実行されるにつれて、統計情報と実際のデータに乖離が発生していき、パフォーマンスの悪化につながります。

更新も作成と同じように、SQLServerの初期設定で自動更新がONになっています。
更新のタイミングとしては、色々条件があり一概には言えないようですが、約20%のデータが更新された時とされています。
※私が関わったクエリでは20%以下でも更新されていたため、参考程度としてください。

そのため、基本的には手を加える必要はないですが、処理の度に更新されてしまうというケースでは、統計情報の更新がかかることによって逆に遅くなってしまうということもあると思います。
その場合は、統計情報の自動更新をオフにして、定期的に手動で更新するなどを検討してください。

```sql:統計情報の更新
UPDATE STATISTICS [ schema_name . ] table_name 
```

## 実行想定環境との環境差異の明確化

実際とは異なるの環境でパフォーマンス検証を行う場合、性能や状況にどれだけの差があるかを事前に把握しておく必要があります。
性能の低い環境ではパフォーマンスが悪く見えても実際の環境では影響がなかったり、本番環境のインデックスはテスト環境と比べて断片化が進んでいたりと、洗い出しを行わなくては正常の判断ができません。

確認すべきポイントの一例を以下にまとめます。
・サーバースペック
　- メモリ
　- CPU
・ネットワーク帯域速度
・インデックスの断片化状況
・統計情報の更新状況
・クエリキャッシュの有無
・裏で動いているクエリ
WSL を使って Blazor WebAssembly で開発した話

:::note
この記事は、昔に別のサイト[^qlog]で書いた内容のミラーです。
:::

[^qlog]: Qlog に投稿 (現在は閉鎖) (当時の URL: https://lemon73.qlog.dev/items/bc1888475e5d43f19043a847fbfb9732/)

## この記事について
C# の Blazor WebAssembly の開発を Visual Studio なしで行う方法についての備忘録です。
パソコンスペックが低くて Visual Studio の動きが遅すぎるので代替として。

### 自分の環境
- OS: Windows10 22H2
- 仮想: WSL2

#### WSL2 内の OS
```shell
cat /etc/os-release
> PRETTY NAME="Debian GNU/Linux 11 (bullseye)"
```
今回は WSL がすでにインストールされている前提で話を進めます。

### .NET SDK のダウンロード
コンソールで行います。
方法は Microsoft 公式に書いてあります。
[Debian 版](https://learn.microsoft.com/ja-jp/dotnet/core/install/linux-debian)

#### Microsoft の認証キーをダウンロードして照合
```shell
wget https://packages.microsoft.com/config/debian/11/packages-microsoft-prod.deb -O packages- microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
rm packages-microsoft-prod.deb
```

#### .NET8.0 SDK のインストール
```shell
sudo apt-get update && \ sudo apt-get install -y dotnet-sdk-8.0
```

### Blazor wasm プロジェクトを作成
**参考記事:**

https://qiita.com/nt-7/items/97c0bc75e3afe9e02997

好きなディレクトリまで `cd` コマンドで移動します。
デフォルトのプロジェクトを作ります。
```shell
dotnet new blazorwasm -o 好きなプロジェクト名
```
プロジェクトファイル内に移動します。
```shell
cd 好きなプロジェクト名
dotnet watch run
```
起動後にいろいろ出てきますが、`https://localhost:xxxx` という文字があるので、それをブラウザのアドレス欄で検索すると起動できます。

## 最後に
Blazor は最高。

## 追記
.NET8 で Blazor Wasm と Blazor Server を統合する Static-Server Side Rendering (SSR) の [Blazor United](https://learn.microsoft.com/ja-jp/aspnet/core/blazor/fundamentals/) というものが出たらしいです。
よくわからないけどすごそうですね。
【Rails】Active Storageのバリデーション

## Gemをインストールする

`active_storage_validations`をインストールします。

https://github.com/igorkasyanchuk/active_storage_validations

```rb:Gemfile
gem 'active_storage_validations'

# :dimension　または　:aspect_ratioを使用する場合には以下のいずれかを併せてインストールします。
gem 'mini_magick', '>= 4.9.5'
gem 'ruby-vips', '>= 2.1.0'

```

```terminal:ターミナル
bundle install 
```

## バリデーションを設定する

モデルにバリデーションを記述します。

```app/models/user.rb
class User < ApplicationRecord
  has_one_attached :avatar

  validates :avatar, content_type: { in: %w[image/jpeg image/png] }, size: { less_than_or_equal_to: 2.megabytes }
end
```

上記の場合にはjpegおよびpngのファイルで2MB以下のものを許可します。
様々な SNS の RSS を取得しよう!

:::note
こちらの文章は、昔に別のサイト[^qlog]で公開した内容のミラーです。
:::

[^qlog]: Qlog に投稿 (現在は閉鎖) (当時の URL: https://lemon73.qlog.dev/items/3c2056c0df6f459591a252bd7e70c558/)

# RSS とは
>RSS は、ニュースやブログなど各種のウェブサイトの更新情報を配信するための文書フォーマットの総称である。
(参考: https://ja.wikipedia.org/wiki/RSS)

<img src="https://stat.qlog.app/media/article/image/7949071a72dc40fb87fb6dce1d3f1b7d.jpg" width=10%>

↑ブログや SNS などでこのマークを見たことはありますか?

こちらは、好きなニュースやブログ、SNS の人のコメントだけを集めて通知してほしい場合などで使います。
様々な SNS がこの RSS に対応しているのですが、これの入手方法が SNS によって異なるので、この文章ではそれをまとめていきます。
ブログ系などは全体の RSS などもありますが、今回は特定のユーザーの RSS 取得に着目します。
(RSS の利用方法については他の方の文章をご利用ください)

## Blog系
### Qiita
バージョン: Atom
![qlog](https://stat.qlog.app/media/article/image/58cc317556a246ab864e56ccfa913acb.png)
または
```
https://qiita.com/ユーザ名/feed
```
(ユーザ名…@xxxxの`xxxx`の部分)

### Zenn
バージョン: RSS2.0/(Atom?)
![qlog](https://stat.qlog.app/media/article/image/e66a34ecd4ea4c00962e387518d913f8.png)
または
```
https://zenn.dev/ユーザ名/feed
```
(ユーザ名…@xxxxのxxxxの部分)

### Note
バージョン: RSS2.0/(Atom?)
![qlog](https://stat.qlog.app/media/article/image/7a160a1cfe724d7e9031c6479ccb1db7.png)
または
```
https://note.com/ユーザ名/rss
```
(ユーザ名…@xxxxの`xxxx`の部分)

## Git系
(SNS じゃないw)
コミットごとに通知が来るのでうざいです。
登録しないほうがいいです。

### GitHub
バージョン: Atom
```
https://github.com/ユーザ名.atom
```
(ユーザ名…@xxxxの`xxxx`の部分)

### GitLab
バージョン: Atom
![qlog](https://stat.qlog.app/media/article/image/2362b99fbd6e4d6aa03194bfb5a72fd4.png)
または
```
https://gitlab.com/ユーザ名.atom
```
(ユーザ名…@xxxxの`xxxx`の部分)

## 動画系SNS
### YouTube
バージョン: Atom
YouTube は若干面倒です。

https://www.youtube.com/channel/UCNiEtjncyYOxSsZ-6BFCNUA
https://www.youtube.com/@lemon73
両方とも同じチャンネルを指していて、上が昔からのチャンネル表記、下が近年追加された新しいチャンネル表記です。
昔からの古いチャンネル表記でのリンクが分かる場合は RSS の取得が可能です。
([こちら](https://ilr.jp/tech/485/)を利用すると新しいチャンネル表記から昔のチャンネル表記に変換できます。)

```
https://www.youtube.com/feeds/videos.xml?channel_id=チャンネルID
```
例)
`https://www.youtube.com/channel/UCNiEtjncyYOxSsZ-6BFCNUA`
このチャンネルの RSS を取得する場合、`UCNiEtjncyYOxSsZ-6BFCNUA` の部分がチャンネル ID になります。
なので、`https://www.youtube.com/feeds/videos.xml?channel_id=UCNiEtjncyYOxSsZ-6BFCNUA` がこのチャンネルのRSSのリンクです。

### ニコニコ
バージョン: RSS2.0/Atom
![qlog](https://stat.qlog.app/media/article/image/212ba37412014b958f7800cdcf80a240.png)
ユーザーの ID を記録します。

RSS2.0
```
https://www.nicovideo.jp/user/ユーザーID/video?rss=2.0
```
Atom
```
https://www.nicovideo.jp/user/ユーザーID/video?rss=atom
```

## チャット系
### mstdn.jp(Mastodon)
バージョン: RSS2.0
```
https://mstdn.jp/@ユーザー名.rss
```
(ユーザー名…`@xxxx`)

### Fedibird(Mastodon)
バージョン: RSS2.0
```
https://fedibird.com/@ユーザー名.rss
```
(ユーザー名…`@xxxx`)

### Misskey(Misskey.io)
バージョン: Atom
![qlog](https://stat.qlog.app/media/article/image/aa91906c61a249038be9c9ddd14a1d4c.png)
または
```
https://misskey.io/@ユーザー名.atom
```
(ユーザー名…`@xxxx`)

## その他
### Reddit
バージョン: Atom
```
https://www.reddit.com/user/ユーザー名.rss
```
(ユーザ名…@xxxxの`xxxx`の部分)

### Pinterest
バージョン: RSS2.0
```
https://www.pinterest.jp/ユーザー名/feed.rss/
```
(ユーザ名…@xxxxの`xxxx`の部分)

## 最後に
RSS のバージョン問題が結構面倒…
ソフトウェアとか自作サイトでこの RSS データを使おうとすると、RSS2.0 と Atom で別の処理にしなきゃいけないので、若干面倒なんですよね。
RSS リーダーとかを使う際はバージョン関係なく読み取れると思うので、ぜひ気軽に利用してみてください。

その他の SNS は気が向いたら追加します。
Visual Studio CodeでPythonのIntelliSenseが遅い

# IntelliSenseが遅すぎる...
通常、pythonのソースコードを開くと、コードがハイライトされ、F12で定義参照などに行くことができる。しかし、全然コードがハイライトされず、F12を押しても定義に飛べない！これの解決に苦労したので、備忘録として残しておく。

# 考えられる原因
便宜上vscodeで開いているフォルダをrootとする。機械学習を行っていたのでroot/dataフォルダの配下に何十万というファイルが存在していた。原因は明らかにこいつだろと思っていたので、このdataフォルダを除外する方法はないかと模索した。
# python.analysis.excludeに設定の追加
はじめにpython.analysis.excludeにdataフォルダを追加してみた。しかし、効果は得られなかった。ちなみに,python.analysis.excludeとは、ショートカットキー「Ctrl+,」でsettingsを開き、検索バーに「python exclude」と入力して出てくる設定項目である。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3121536/7e855626-1524-fde1-089f-185714819756.png)

# pyrightconfig.jsonの追加
いろいろ調べるとPythonのIntelisenseは拡張機能であるPylanceが関係しているようである。Pylanceのログがないかなと探していたらログを見つけることができた。
Vscode画面の[パネル](https://izumi-zenkou.com/the-component-name-vscode-basic-screen/)のタブをOUTPUTを選択し、その右側にあるプルダウンリストをPython Language Serverを選択することで、Pylanceのログを確認することができた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3121536/2f6589fa-e98b-8141-d759-0ffaaabe24f0.png)
そこで、ログを見てみると気になるErrorが表示がされていた。
```
2023-09-28 13:29:04.631 [info] [Error - 1:29:04 PM] (1527144) Enumeration of workspace source files is taking longer than 10 seconds.
This may be because:
* You have opened your home directory or entire hard drive as a workspace
* Your workspace contains a very large number of directories and files
* Your workspace contains a symlink to a directory with many files
* Your workspace is remote, and file enumeration is slow
To reduce this time, open a workspace directory with fewer files or add a pyrightconfig.json configuration file with an "exclude" section to exclude subdirectories from your workspace. For more details, refer to https://github.com/microsoft/pyright/blob/main/docs/configuration.md.
```
なんか時間かかってるからエラーがでているらしい。しかも、ファイルがたくさんあることが原因の可能性があるとあった。pyrightconfig.jsonを編集することで、dataを除外できるてきな雰囲気があるので、早速[https://github.com/microsoft/pyright/blob/main/docs/configuration.md](https://github.com/microsoft/pyright/blob/main/docs/configuration.md)を参照してみた。すると、ルートフォルダの下にpyrightconfig.jsonが生成される的なことが書いてあった。しかし、rootフォルダを確認してみても生成はされていない。そこで、「Ctrl+N」で新しいファイルを作成し、pyrightconfig.jsonという名前にしておいてみた。
```
root
  ├data
  ├pyrightconfig.json
```
ファイルの中身は以下のようにした。
```
{
    "exclude":"data"
}
```
すると、上ででていたエラーが解消され、すぐにIntelisenseが効くようになった。
ちなみに、ログにも
```
2023-09-28 13:38:44.416 [info] [Info  - 1:38:44 PM] (1529385) Loading configuration file at /[パス]/root/pyrightconfig.json
```
のように、読み込んでいる雰囲気の出力がされていた。
# 結論
pyrightconfig.jsonでexcludeを指定すれば、余分なファイルを分析させずにすむ。
2023: Week 38 - Sustainable Development Goals / Preppin' Data / Tableau Prep

# Challenge Preppin'Data 2023:Week 38

## 概要

持続可能な開発目標 (SDGs) に関するもので、元のデータを見てみると、Tableau Desktopで集計しずらいデータのため、Requirementに従い、データを加工します。

Requirement
1. SDG の見出しが色のインジケーターと矢印の 2 つの列にまたがって結合されているため、矢印を含むフィールドの名前を変更して、どの目標に関連付けられているかが明確にする
2. データを再形成して、国ごとに SDG ごとに 1 行が存在し、同じ行に色のインジケーターと矢印に関する情報が含まれるようにする
3. カラーインジケーターフィールドの名前を「SDG Value」に変更する
4. Goalsフィールドの名前を「SDG Trend」に変更する
5. 「SDG Value」フィールドを以下のとおり更新する
Green - Goal Achieved
Yellow - Challenges Remaining
Orange - Significant Challenges
Red - Major Challenges
Grey - Insufficient

6. 「SDG Trend」フィールドを以下のとおり更新する
↑ - On Track
➚ - Moderately Increasing
→ - Stagnating
↓ - Decreasing

## 問題のページ（英語）※ここからデータをダウンロード
https://preppindata.blogspot.com/2023/09/2023-week-38-sustainable-development.html

## 出題者の回答のページ（英語）※動画あり
https://preppindata.blogspot.com/2023/09/2023-week-38-solution.html

## 自分の解決法
1. データ取り込み
データを取り込みます。取込の際に、インタープリターにチェックを入れます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531257/39c2064f-7157-c0d0-6b25-77112e33573b.png)

インタープリターにチェックを入れると、結合されたヘッダーの後半の列が前半の列にインデックスを付けた名称にすることができ、後続の作業をする場合に便利です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531257/40fd7947-c1e7-c4e6-dcc5-811b49d8559d.png)

2. ValueとTrendの値をPivotにします。
最初に、すべての SDG ヘッダー (1 なし) をピボットする項目に取り込みます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531257/f00d40f7-5e0e-1fe6-9ecf-83558c99ba46.png)
次に、Pivotの列を＋ボタンで追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531257/2044eba5-e854-73aa-fbc7-c4a52fe6b752.png)
最後に、SDGヘッダー（1あり）をピボット項目に取り込みます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531257/3df9bff7-fb6d-c3d4-7fa2-6eb7341cce24.png)

3．ピボット項目のそれぞれのヘッダーを修正します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531257/39bfbc44-2416-27ff-c873-5b5a39d5f60b.png)
フィールド名を、以下のとおり変更します。

4. 値の内容を上書きします。今回は項目をダブルクリックして直接修正をしていきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531257/d2c00f08-0739-12ac-0e3f-9b875401cfc4.png)

5. 出力
最後に、出力先やファイル名を指定したら完成です。

## 今回の感想
Pivotで２つまでできるのは感動です！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531257/08c9f7e2-f27b-aa4d-2381-901de02991eb.png)
Djangoでデータベースを正規化する方法

Djangoを使っているエンジニアの方、
趣味で使っている方、
始めたばかりの皆さんこんにちは！

私はDjangoを使って開発するのが好きな２２歳のkazukiniiyamaと言います。

今日は、
DjangoでDB設計するときに、
正規化とは何ぞやとなる人が一定数いると思います。

そんな方たちの力に少しでもなれたらと思って調べた情報をまとめてます。

もし間違いや指摘、修正の必要がありそうな場合はどんどん言ってください！

ただただ感想を言ってくれるのもうれしいですので、コメント待っています。

### DBの正規化とは

DBの正規化とは、
データの重複を避けるために、
データベースを構造化するプロセスのことを指します。
### 正規化の簡単なステップ

**第1正規形 (1NF)**:

各列が一意の値を持つようにデータテーブルを構造化します。

Djangoにおいてそれは、

**各モデルフィールドを一意に設定する**ことです

**第2正規形 (2NF)**:

すべての非キー列が主キーに完全に依存するようにします。
Djangoにおいてそれは、

**ForeignKeyやOneToOneFieldを使用してモデル間の関連の定義を設定する**ことです。
**第3正規形 (3NF)**:

非キー列が他の非キー列に依存しないようにします。
Djangoにおいてそれは、
**モデルを分割して依存関係を排除すること**です。

これがざっと堅苦しい正規化の説明です。
ここまで読んでくれた方、ありがとうございます。

それでは最後にコード例を用いてサラっとおさらいしましょう！

### Djangoでの正規化の例

これは未正規化のモデルの例です。

```python
from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=100)
    address = models.CharField(max_length=255)
    city = models.CharField(max_length=100)
    phone = models.CharField(max_length=15)
    course_name = models.CharField(max_length=100)
    course_fee = models.IntegerField()
```

上記のモデルでは、人とコースの情報が1つのモデルに混在しています。

正規化されたモデルだとこんな感じです。

```python
from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=100)
    address = models.CharField(max_length=255)
    city = models.CharField(max_length=100)
    phone = models.CharField(max_length=15)

class Course(models.Model):
    name = models.CharField(max_length=100)
    fee = models.IntegerField()

class Enrollment(models.Model):
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
    course = models.ForeignKey(Course, on_delete=models.CASCADE)

```
見てわかる通り上記の例では、Person、Course、およびEnrollmentの3つのモデルにデータを正規化して分割しています。これにより、データの重複が減少し、データの整合性が向上します。

### まとめ
Djangoにおけるデータベースの正規化は、データの重複を減らし、整合性を保つために重要です。モデルの設計時に正規化の原則に従って、適切にモデルとリレーションシップを構築することで、効率的で管理しやすいデータベースを構築できます。

終わり。

この記事を通して、
Djangoの仕組みを少しでも理解いただければ幸いです。
あと、フォローされたらもっと頑張ります！
フォローしてくださいな！
Laravel + Vite でCRUDを使うアプリケーションを作る(環境構築編+α)

## 前提
スキルアップするために個人開発し、その手順を残していこうと考えている記事です。PHPは少しできる程度でTypeScriptは初心者です。

## 環境づくり
Dockerを使って導入していきましょう。
以下の記事を参考に導入していきます。

https://zenn.dev/eguchi244_dev/articles/laravel-vue-docker-introduction-20230828

私の場合m1Macなのでm1用のコンテナ(?)をダウンロードするように設定してあげましょう

```
services:
  db:
    platform: linux/x86_64 <-ここを追加します
    image: mysql:5.7.36
    container_name: "mysql_test"

```
あとは、特にすごくわかりやすく手順等書かれているため、問題なく環境を構築することができました。

今回のアプリケーションの構成?基本的な考えを書いておこうと思います。

```
.src
├── app
|   ├──http
|   |   ├──Controllers
|   |   └──Requests
|   ├── Models
│   ├── Services
│   └── Rules

```

## 構成
上記のようなバックエンドの処理の構成にしています。
コントローラーでは、データの処理はせず、受け渡しのみを行います。（理由としては、コントローラに何もかもを書くと非常に長く読みにくいものになってしまう可能性があるため。）
リクエストでは受け取ったデータにバリデーションを適用します。
モデルでは DBとのやりとりを行います。今回のアプリケーションではEloquantを使わず、クエリビルダもしくはSQLを使用し、データのやり取りを行いたいと思います。（理由はSQL力の向上のため）
Serviceではコントローラーから来たデータの処理や整形、モデルからきたデータの処理など、主な処理をここで行います。
Ruleではバリデーション時に複雑なルールを作成するとき(例えば、存在確認する際に複数テーブルを結合したりしてデフォルトのバリデーションルールでは適応できない時）にここにファイルを作成し、リクエストに引用します。

具体的な処理の流れは以下のようになります。
POST時
フロントから来たデータ→リクエスト（ここでバリデーションを適用）→コントローラ→サービス→モデル→サービス→コントローラ→フロントへ渡すデータ
というふうになります。

次回からは具体的なアプリケーションを作成していきたいとおもいます（が何を作るかは考えていません。よくあるTODOアプリケーションとかにユーザー機能つけて管理者とかつけて複雑にするのかなあ？いいアイデアはないので多分よくあるものを作ります）。
炎上案件での経験を元に再度ベストプラクティスについて考えてみた


# はじめに
自身のトラブル案件の経験を元に今あるシステムはどうあるべきなのかを検討し、その経験をウェビナーで講演しました。このようなトラブルを経験する方が今後少なくなる為にも、私の実体験をまとめておきます。

# きっかけ
既に運用中のシステムで、ある日スパイクアクセスがあった事で、本来対応できるはずのアクセス数が対応できずにシステムがダウンするという障害がありました。
これだけ聞くとよくある話じゃんと思う方もいるかもしれませんが。
よくある話の中でも色々経験できたのでまとめておきます。

# システム構成図
よくあるWeb三層構造のシステム構成図です。
フロントにロードバランサーがあり、Web/APサーバはAutoScaling構成で、バックエンドにDBを持っています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198480/81920a4e-7b80-e927-a1be-ab21de7eaee5.png)

# トラブった原因
主な原因としてはDBのバージョン依存のバグでした。
Aurora MySQL v2.11.1 の利を利用していたのですが、このバージョンには接続高騰時にaborted Connection とりエラーとなってしまう問題を孕んでおりました。これによってスパイクアクセス時にEC2→DB間の接続がうまくいかず、結果としてEC2の負荷が高騰、LBのヘルスチェックに失敗するのでAutoScalingのループという無限ループに陥ってしまいました。
https://docs.aws.amazon.com/AmazonRDS/latest/AuroraMySQLReleaseNotes/AuroraMySQL.Updates.2111.html


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198480/3c3a4008-690a-40cc-3967-2d9e0484590f.png)

# どう立ち直ったのか
ヘルスチェックが要因となりAutoScalingの無限ループになっていたのでヘルスチェックを解除したところAutoScalingのループは止まりユーザからのリクエストが処理され始めました。
ちなみにお浚いですが、AutoScalingにはヘルスチェックタイプが3つあります。
このシステムにおいてはElasitc Load Balancingのヘルスチェックを採用しておりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198480/44fe6e12-293f-10ee-dc9d-c290396849cf.png)

# ここでまた問題発生
トラブルの原因究明において何よりも重要なのは**ログ**ですが、問題だったのはこのシステムログがほとんど取れてなかったので、AWSサポートに調査依頼を投げるにも数少ない状況証拠を投げていくしかなくなってしまいました。。
泣きっ面に蜂とはまさにこのことですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198480/9a3db146-bf3d-9a47-68b9-33026b5ffa6c.png)

# 学んだ事
運用系の言葉で「オブザーバビリティ（可観測性）」という言葉をよく耳にしますが、まさにこれって重要で例えリアルタイムに観測はできなくとも、後から追える状態の仕組みを導入しておく事は改めて必要だと今回のような障害を通して学びなおしました。その上でAWSで今回のシステムに対してオブザーバビリティのアプローチをするのであればどのような事が重要なのかをまとめたので書きたいと思います。

### AuroScaling(EC2)
EC2においてはアプローチ手法は多々ありますが、有名どこで攻めるとまずはCloudWatch Agentを入れる方法。その他であればライフサイクルフックを入れてTerminate時にログを退避しておく方法。リアルタイムを求めるのであればKinesis Agentかfluentd(td-agent)入れておくアプローチがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198480/715ef828-95fa-e850-9bd0-7f9612aab0c9.png)


### Aurora
Auroraは改めて調べていてビックリしたのですが、こんなに取れるログがあります。
その中でも主にAWSサポートとやり取りをしていて、これはマストで有効化したほうがいいというログは赤字にしてます。　
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198480/73d31523-6b18-63e2-2eef-43064c95617e.png)

# まとめ

AWS Well-Architected Flamework の信頼性の柱にもある通り、障害は起こしたくなくても起きてしまうものです。（Design for Failur）問題はそこからどう調査し、ユーザビリティを失わないように早急に復旧できるかにかかっているので、その為の仕組みをシステムに組み込んでおく事が何よりも重要です。
また、どこが原因か分からない時は、自分のDBやOSのリリースノートを確認し、重大なバグがないかチェックする癖をつけておくことも大事だと今回の障害を体験して学びました。このメモが誰かの役に立てば幸いです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198480/0cb8b3f3-75d3-19d2-3bcb-80ccca46d261.png)


# 講演資料
ウェビナーで登壇した際の資料まとめておりますので、興味がありましたらご参照ください。

- 動画
https://www.fsi.co.jp/aws/event/aws_summit2023_seminar03.html

- 資料
https://www.fsi.co.jp/aws/pdf/aws_summit2023_seminar03.pdf
【プラクティス紹介】1分でさらっと分かる「プロダクトゴール」

## プラクティス名
プロダクトゴール

## プラクティスの目的・狙い
* プロダクトビジョンの実現に向けて最優先で達成すべきことを具体化する
* スクラムチームとステークホルダーのゴールを１つにする（期待の統一）

## どんな時に使うか
* スクラムでは必須（スプリント0などで定義）
* プロジェクト開始時など、当面のゴールを明確化したい時
* 前のプロダクトゴールを達成（または破棄）し、次のゴールを定める時

## 実施手順
1. POは今回の開発で達成したい目標を誰にでも分かる短いステートメントにまとめる
1. スクラムチームとステークホルダーにプロダクトゴールを説明し、合意する
1. 開発中は常に参照できる場所に掲示し、意識する
1. 開発中に状況変化や学びによって、目指すべき場所が変わってきたら適宜、見直す


## アレンジ例
* 定型フォーマットに沿ってプロダクトゴールを定義する（例：エレベータピッチ）

## アンチパターン
* プロダクトゴールに複数の目標が含まれている（→原則、ゴールは1度に1つ）
* 一度決めたプロダクトゴールをスコープ定義とみなし、変えようとしない
* プロダクトバックログの内容を抽象化して、プロダクトゴールを導き出そうとする
（→正しい落とし込みの順番は、プロダクトビジョン＞プロダクトゴール＞プロダクトバックログ）

## 参考情報
[公式スクラムガイド(2020年日本語版)](https://scrumguides.org/docs/scrumguide/v2020/2020-Scrum-Guide-Japanese.pdf)

プロダクトゴールについてはサーバントワークス株式会社の長沢氏の解説が濃密です。
[こちらのレポート](https://dev.classmethod.jp/articles/report-rsgt2022-nagasawa-tomoharu-product-goal/)が詳細に書かれていてオススメです。


## こぼれ話（私的コメント）
スクラムガイド2020の改訂時、「プロダクトゴール」という名称にすることに関係者の中でも賛否両論があったそうです。たしかにプロダクトが存続する限り、進化し続けると考えると、どこかの時点で達成してしまう「ゴール」という言い方はそぐわないのかもしれません。まぁ、呼び方はどうあれ、関係者の目線を１つにまとめるツールとしての有用性は揺らがないので、必ず定義はするのですが。
ただBacklogとかツールを使ってPBL管理している場合、わりと書きどころに困るんですよね。プロダクトゴール用に別にタスクカード切ったりして、どうにかこうにか載せるのですが、みんなはどうしてるんでしょう？

最後に、プロダクトビジョン/プロダクトゴール/スプリントゴールの違いについて、下記にまとめておきます。

### プロダクトビジョン
* 最上位の概念（基本コンセプト）
* プロダクトの方向性や目的を定義したもの、最終的な理想形
* スクラムガイドの中には登場しない（が、実質的に採用しているチームは多い）
* 長期的なゴール（数年以上）

### プロダクトゴール
* プロダクトビジョンを達成するための踏み石（マイルストン）
* 当面の開発で実現したいことを定義したもの（プロジェクトゴールと同じ場合もある）
* スクラムではプロダクトバックログに対する確約（コミットメント）の位置づけ
* 中期的なゴール（数ヶ月）

### スプリントゴール
* プロダクトゴールを達成するための踏み石（マイルストン）
* スプリントにおける唯一の目的
* スクラムではスプリントバックログに対する確約（コミットメント）の位置づけ
* 短期的なゴール（1～4週間）


　[アジャイルプラクティス一覧へ戻る](https://qiita.com/kakashi_h5/items/20584998c5ca4594b9ea)
【プラクティス紹介】1分でさらっと分かる「プロダクトビジョン」

## プラクティス名
プロダクトビジョン

## プラクティスの目的・狙い
* プロダクトの方向性や目的を明確にする

## どんな時に使うか
* そのプロダクトによって最終的にどんな世界がもたらされるのかがイメージできない時

## 実施手順
1. ビジョンを定める上で判断材料となる情報を集める（顧客ニーズ/市場分析データなど）
1. プロダクトを通してユーザに提供したい価値（目指す状態）を短いステートメントにまとめる
1. ビジョンが組織の文化や価値観、ビジネス戦略にも沿っているか確認する

例えばQiitaさんの場合「エンジニアを最高に幸せにする」というビジョンを掲げています。
これはあくまでもビジョンなので、具体的に何がどうなったら目標を達成したことになるのか、といったゴールとしては機能しませんが、「誰を」「どんな状態に」したいのかという方向性は明確に示してくれます。ビジョンは向かうべき方向さえ示していれば、永久に達成できないような理想でも構いません。

よいビジョンは行動指針/判断基準として機能します。例えば記事の内容がQiitaに相応しいか、是非を問う場合「この記事はエンジニアを幸せにするか？」が基準となります。同じようにプロダクトに対する施策がトレードオフの関係にある場合も、ビジョンに照らし合わせて考えることで関係者間で合意しやすくなります。

## アレンジ例
* ビジョンに基づき、KGI/KPI/NSMなどの具体的な目標を定める

## アンチパターン
* ビジョンが長期的視点に立っていない（直近の目標になっている）
* ビジョンが抽象的すぎて判断基準にならない

## 参考情報

https://product-managers-club.jp/blog/post/product-vision-point

http://agile.blog.jp/agile_scrum/14974920.html

## こぼれ話（私的コメント）
スクラムガイドには「プロダクトビジョン」という言葉は出てきません。代わりに「プロダクトゴール」という概念が2020年版から追加されました。CSM研修では「プロダクトビジョン」と「プロダクトゴール」はほぼ同じものだと習いましたが、これはスクラムガイドの世界では「プロダクトゴール」が最上位の概念だからでしょう。一般的には「プロダクトゴール」の上位概念に「プロダクトビジョン」を置き、両者を階層化して区別する考え方が主流のようです。「プロダクトゴール」と「プロダクトビジョン」の違いについては、[別の記事](https://qiita.com/kakashi_h5/items/42f3ac38477abbac380d)にまとめています。

　[アジャイルプラクティス一覧へ戻る](https://qiita.com/kakashi_h5/items/20584998c5ca4594b9ea)