OmniAICreator/Qiita-1.07M huggingface dataset:
クラス名を分かりやすくしたい

# はじめに
今回は私がCSSのクラスの命名規則であるPRECSSについて学んだことを少し書こうと思います.

# なぜ学ぼうと思ったのか
webサイトを作る際,CSSの書く量が増えてくるとかなりややこしくなってくるのを何とかしたいと思ったからです.特に,時間を空けていざ修正作業に入った時にどのクラス名がどこを表しているのかに時間をとられては作業も全然進みません.

# クラス名を適当にするとどうなるか
まず,駄目なコードの例として私が初めてHTML,CSSを触った時に作った自己紹介サイトのコードの一部を以下に示します.
```
<div class="myprofile">
        <div class="name">
            <h2>〇〇〇〇</h2>
            <img src="〇〇〇〇.jpg" alt="" width="700px" height="120px">
                <div class="name2 namename">
                    <img src="〇〇〇〇.jpg" alt="" width="300px" height="780px">
                     <div class="name3 namename">
                        <div>
                            <p>〇〇〇〇大学　<br>〇〇〇〇学部　〇回生</p>
                            <img src="〇〇〇〇.jpg" alt="" width="600px" height="300px">
                        </div>
                        <div class="birthday">
                            <p>生年月日<br>〇〇〇〇年 〇〇月 〇〇日</p>
                            <img src="〇〇〇〇.jpg" alt="" width="600px" height="300px">
                        </div>
                    </div>
                </div>
        </div>
</div>
```
今見返してみるとなかなかにやばいクラス名をつけていることがわかりますね.このようなクラス名だと,CSSを書いているときや後々コードを修正するときにかなり苦労することになることが目に見えています.

# CSSの命名規則-PRECSS-
CSSの命名規則はいろいろ種類があるのですが今回はPRECSSという命名規則を紹介したいと思います.PRECSSの特徴としてクラス名に2文字の接頭辞をつけることが挙げられます.また,CSSを役割別に6つのグループに分割し,それぞれに対して規則を設けているという特徴があります.

# PRECSSの例
今回は一例としてPRECSSの[公式ドキュメント](https://precss.io/ja/)にあるコードを引用したいと思います.
```
<div class="bl_card">
  <figure class="bl_card_imgWrapper">
    <img alt="Dummy Image" src="//placehold.jp/E13626/fff/1280x718.png?text=Card 1">
  </figure>
  <div class="bl_card_body">
    <h3 class="bl_card_ttl">TITLE HERE</h3>
    <p class="bl_card_txt"> ... </p>
  </div>
  <!-- /.bl_card_body -->
</div>
<!-- /.bl_card -->
```
このコードを見るとどのクラス名にも接頭辞として`bl`という二文字の接頭辞が使用されていることがわかります.これはblockの略で複数の子要素を塊として集めたモジュールのことです.今回の例だとカードという一つの塊をブロックモジュールとしています.また,クラス名をアンダーバーでつなげる,複数の単語の場合はローワーキャメルケースを用いるなどの特徴がみてわかりますね.これにより,どこにネストされているのかもすぐに理解することができます.

# コメントについて
余談として,divの終了タグの後にコメントが挿入されていることがわかります.これによりdivの終了タグがどの開始タグと対応しているのか一目で見てわかります.これを書くのは面倒くさいように見えますが実は`|c`を用いて簡単に書くことができます.例えば,
```
div.example|c
```
こう書いた後にENTERキーを押すと,
```
<div class="example"></div>
<!-- /.example -->
```
のように展開して書くことができます.

# まとめ
今回はPRECSSについて一部だけですが簡単に紹介しました.気になった方はぜひ[公式ドキュメント](https://precss.io/ja/)を確認してみてください.拙い文章でしたが最後まで読んでいただきありがとうございました.

# 参考文献
https://precss.io/ja/
Reactの条件付きレンダリング使用時の注意

# 概要 
Reactの条件付きレンダリングの注意すべきパターンについてメモです。

# 真のパターン
左の値がtrueの場合は何かしらのコンポーネントを返すという想定です。
条件付きレンダリングの上にはtrueになる理由を記載しています

```tsx
// 真偽値でtrueのため
{true && <Component />} 

// 0以外のため
{20 && <Component />}

// 空文字ではないため
{"string" && <Component />}

// 空のオブジェクトはtrue
{{} && <Component />}

// 空の配列もtrue
{[] && <Component />}

// 関数は空でもtrue
{(() => {}) && <Component />}


```
上記のパターンでは全て`<Component />`が返ります。


# 偽のパターン
```tsx
// 何もレンダリングされない
{null && <Component />}

// 何もレンダリングされない
{undefined && <Component />}

// 何もレンダリングされない
{false && <Component />}

```

ここまでは大体予想通りですね

```tsx
// NaNをレンダリングする
{NaN && <Component />}

// 0をレンダリングする
{0 && <Component />}

//0をレンダリングする
{-0 && <Component />}

//　何もレンダリングされない
{"" && <Component />}
```
上記の場合はどうでしょうか？

**NaNの場合**
NaNでは何もレンダリングされないわけではなく、NaNがreturnされます。なのでサーバーから何かしらの値を受け取った後に`Number()`関数を使用して数値に変換できない場合はNaNが画面上に表示されてしまいます。

**0、-0の場合**
0がfalsyな値なのは知っている人も多いかと思いますが、条件付きレンダリングで使用した場合の振る舞いは0がreturnされてしまいます。扱いには注意が必要な値で`!!0`などを使用して真偽値に変換する必要がありそうです。

**""の場合**
この式は実際には空の文字列を返していますが、React（またはJSX）では空の文字列は何もレンダリングされないため、画面上には何も表示されません。

# 論理 && 演算子の注意点
> falsy な値を返した場合、&& の後の要素の評価はスキップされますが、falsy な値そのものは返されるということに注意してください。以下の例では` <div>0</div>` がレンダーメソッドから返されます。
```tsx
render() {
  const count = 0;
  return (
    <div>
      {count && <h1>Messages: {count}</h1>}
    </div>
  );
}
```
上記は公式からの引用です。確かにfalsyの場合はfalsyな値自体が返されています。
論理 && 演算子では<INS>左の値がtrueの場合に右の値が返されるだけではなく、左の値がfalseの場合は左の値が返されるということですね。</INS>

https://ja.legacy.reactjs.org/docs/conditional-rendering.html
# まとめ
NaNや0の扱いが思わぬバグに繋がる可能性がありそうなので注意して使用していこうと思います。
tauriとNext.jsを使ってポケモンの管理ツールを作ってみた

### 作ったもの
ポケモンの努力値や個体値、レベルなどが保存できるツール

https://github.com/tkwest3143/poke-doc

### 作った動機
まず前提として、今、猛烈にポケモンの過去作をやり直しています（主にDSや3DSででたもの）
なのですが、剣盾やSVでポケモンの育成がとてもやりやすくなったことで、以前はやってなかった個体値や努力値を考えて育成をするようになりました。
過去作のものには簡単にいま稼いだ努力値を確認するのが容易ではないので簡単に記録できるアプリを作っちゃおうという思いのもと、RustやNext.jsの勉強のためアプリを作りました。

### 使ったAPIなど
[pokeapi](https://pokeapi.co/)を主に使用してステータス情報やポケモンの情報を取得しました

### いったん完成したもの
- セーブデータごとにシリーズやポケモンを登録できます
![001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3367262/e7eff67d-f3c6-ab8c-3a3c-1c6949f2f8a4.png)
- こんな感じで入力して保存できます
![002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3367262/c4cc4bd8-f71f-5c62-1152-4bba789448c9.png)

### 感想
- Next.jsは静的のエクスポート設定をしなければいけなかったので動的ルーティングが使えなかったのは不便だった
- tauriで作成したAPIを利用する場合importを`@tauri-apps/api/tauri`のinvokeを使用する必要があるが`@tauri-apps/api`にも同様の関数があるのでこっちを利用した場合、実行時にはエラーにならないがビルド時にエラーになるので詰まった
- rustを初めて触ってみてTypescriptとは違っていてとても楽しかった
Reactコンポーネント

## 商品リストページ開発の実践
### イメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193270/40984f28-381f-59a6-37a1-b4c660e8d2fa.png)


### 使用データ

```javascript
const productList = [
  {id: 'E01', title: '商品1', inStock: false},
  {id: 'E02', title: '商品2', inStock: true},
  {id: 'E03', title: '商品3', inStock: false}
]
```

### mapの使用
```tsx
{productList.map(product => {
  const {id, title, inStock} = product
  return (
    <div key={id} className='list-item'>
      <strong>{title}</strong>
      &nbsp;
      {inStock ? <span style={{color: 'green', marginLeft: '20px'}}>在庫あり</span> : <span style={{color: 'gray', marginLeft: '20px'}}>在庫なし</span>}
      &nbsp;
      <button onClick={() => {edit(id)}} style={{border: '1px solid #00000', marginLeft: '20px'}}>商品編集</button>
    </div>
  )
})}
```


## コンポーネントの分割
### React すべてがコンポーネントです
React apps are made out of components. A component is a piece of the UI (user interface) that has its own logic and appearance. A component can be as small as a button, or as large as an entire page.

- React では UI をコンポーネントで構築します。
- コンポーネントの分割は、特に大規模なソフトウェアにとってコードの組織化と保守性に役立ちます。
- JSX では、コンポーネントのタグは大文字で始める必要があります。
- React16以降、Reactは関数コンポーネントの使用を公式に推奨しています。

### コンポーネントの利点
- UI の構造を整理するためにコンポーネントをネストさせることは、HTML と同様、学習コストが低い
- コンポーネントの分割は、コードのメンテナンスと複数人での共同開発を容易にする。
- 共通コンポーネント（またはサードパーティー製コンポーネント）の封装により、コードの再利用が可能で、開発効率が向上する
AWS Certified Database – Specialty 試験 (DBS-C01)を受けてみた

AWS Certified Database – Specialty 試験 (DBS-C01)を受験し、合格出来ましたのでその際の雑記となります

## これまでのAWS認定受験歴など
秋のIPA DB試験後に一念発起して春先までの12冠を目指しており、今のところ約2週間おきの受験ペースが維持できています🤗
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3617151/29eeb497-e181-49c6-c20b-399a66e57f30.png)


## 今回の試験結果
手ごたえに対して点数がかなり高かったため、2択まで絞り込んだ後の運が良かった、また誤答の多くが採点対象外の問題だったのではないかと考えています
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3617151/ec121904-8ba8-edb8-b6d5-175095177be9.png)


## 学習法など
- 学習時間・期間
    - 11/18～12/03の期間中、平日は1~3h、祝休日には4~6h程度の学習をしていました
- 教材など
    - 書籍：要点整理から攻略する『AWS認定 データベース-専門知識』 (Compass Booksシリーズ) Kindle版
        - 全体像・概要を掴むことを意識して最初に2日程度で読み終えました、細部で詰まっても一旦先に進む形で読み進めました
    - Udemy講座: [NEW] Ultimate AWS Certified Database Specialty 2023
        - 同じく細部よりも全体像・概要を掴むことを意識して倍速再生で3日程度で視聴を終えました
    - Blackbelt: こちらは最初から読むというよりも、理解が浅いと感じたサービス・オプション等に遭遇した際に都度読みに来るようなイメージで活用していました
    - 問題集: AWS WEB問題集で学習しよう
        - Blackbelt、書籍、Udemy講座等で分からない部分を調べつつ、残りの時間は主にこちらに充てていました

## 前日の過ごし方など
今回の試験予約は14:45開始、そして予約しているテストセンターへは家から約30分という好条件でした。そのため当日朝7時位まで学習⇒13時過ぎに起床⇒テストセンターへといった流れも十分可能となってきます
DBSに関しては以下の性質があると踏んでいたため、今回は朝まで学習スタイルでチャレンジしてみました
- 短文で単一の知識を知っているかどうかを問うような問題が多く、SAPのような長文＋複数知識を基に考え込む必要があるような問題が少ない
- 恐らく試験時間は余りそう
    - ⇒寝不足や生活リズムの乱れによる思考力低下よりも知識強化の方がメリットが大きい
- 個人的にですが学習後に寝るというフェーズを挟まないと試験中に引き出せるレベルまで記憶が定着しないと感じているため、当日朝起きてからの学習ではなく朝方まで学習してから寝るといった形態をとりました(もちろん十分に期間を取って計画的に学習を進めて、前日はぐっすり眠る事が一番ですが...)
- テストセンターで指定されている身分証明書(運転免許証＋健康保険証など)を必ず用意してから就寝します

## 当日の過ごし方など
- 身分証明書を改めて3度見くらいしてから家を出ます
- 私がいつも利用させていただいているテストセンターでは以下のような方針となっていますので試験前・試験中はこちらを意識・活用していきます
    - 途中での飲食不可
    - 途中でお手洗いに行くことは可能(ただし離席中も試験時間のカウントは進み続ける)
- DBSでは3時間をフルで使うことはなさそうと予想していましたので、開始前に少し多めの水(+カフェイン)を飲んでおき、ポモドーロ法のような形で30分おきに1~2分くらいあえてボーっとしたり目を閉じて頭を休める、そして試験中に1~2回お手洗いに行くといった方針で解き進めていきました(今回は見直しを含めて2時間ほどで試験を終了することが出来ました)
- 各席に防音用のイヤーマフが設置されており装着するととても集中できるのですが、集中の度合いが深くなりすぎて試験時間の半ばで疲れてしまうという印象を個人的に受けたため適宜付け外しをしていました

## 感想など
初の専門分野受験ということもあり大分身構えていたのですが合格出来て良かったです！その名称や試験範囲の通りかなりDBに偏った出題がされており、今後の個人/案件開発にてDBと向き合う際に役立ちそうな知見も多く得られたかと感じます。
個人的な体感難易度としては自身のスキルセットがBE寄りであり、またAWS外でもIPAのDB試験を受けてみたり(恐らく不合格です...😢)と比較的DBには抵抗感が少なかったこともあり以下のように感じました
- CLF < DVA < SAA < SOA=DBS < DOP < SAP
Okta - Applications - template apps

# はじめに

今回はテンプレートアプリについて記載していきます。
結構使います。

# テンプレートアプリ
特にSWAアプリにおいて、画面の作りによってCreate App IntegrationやBrows App Catalog(OIN)から作成できない、作成してもまともに動作しないものもあります。

そういったアプリについてはBrowse App Catalogからテンプレートアプリを選択して作成することで対応できることがあります。
今回は以下のテンプレートについて記載します。
- Template Plugin App
- Template Plugin App 3 Fields
- Template Two Page Plugin App
- Template Basic Auth App]
- Template Frame Plugin App
- Bookmark App

# Template Plugin App
ログイン画面にID/PW入力欄とログインボタンがある場合に使用します。
ちょうどOktaのログイン画面みたいな感じです。
- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350435/e5ad76ef-217f-0eaa-ec65-7ef545c18a4b.png)

アプリ作成時には以下の項目を設定する必要があります。
- Login URL
- Username field
- Password field
- Login button
- Checkbox
    - Checkboxは設定必須ではありません。
    - 設定することでチェックを入れられるようになります。

# Template Plugin App 3 Fields
ID/PWに加えて会社コードなど追加項目が存在している場合に使用します。
例えば以下のような画面です。
- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350435/54a1e013-0a37-b72e-19c0-e90846ec7acd.png)

アプリ作成時には以下の項目を設定する必要があります。
- Login URL
- Username field
- Password field
- Extra field selector
    - 追加項目のCSS Selectorを指定します。
- Extra field value
    - 追加項目の値を指定します。
    - 例の画面だと企業IDの値を入力します。
- Login button

# Template Two Page Plugin App
IDを入力して次の画面に遷移し、パスワードを入力してログインするように2つの画面に分かれている場合に使用します。
Googleのログイン画面みたいな感じです。
- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350435/cb9fde3f-3609-6a75-3092-0413f31092a4.png)
- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350435/9f1f7d97-3b22-cffc-d534-49f5aa3ee8bf.png)

アプリ作成時には以下の項目を設定する必要があります。
- Login URL
- Password page URL
- Username field
- Next button
- Password field
- Submit button

# Template Basic Auth App
Basic認証の画面の場合に使用します。
サンプル画面ないかなーと思いましたが心当たりがなかったので割愛。
アプリ作成時には以下の項目を設定する必要があります。
- URL
    - ログイン画面のURL
- Auth URL
    - Basic認証のURL

# Template Frame Plugin App
ログイン画面がiframeに埋め込まれている場合に使用します。
こちらも心当たりがなかったのでサンプル画面は割愛。
アプリ作成時には以下の項目を設定する必要があります。
- Login URL
- Frame URL
- Username field
- Password 
- Login button

# Bookmark App
URLをOktaアプリとして作成します。
例えばログインが必要ない社内のポータルサイトなどを登録しておくとOktaから簡単にアクセスできるようになるので便利です。
アプリ作成時には以下の項目を設定する必要があります。
- URL

Bookmark AppにはSAMLでの使い道もあります。
それは、SP-Initiatedにしか対応していないサービスの場合に有効な方法があります。
SP-Initiatedの場合、サービスのURLからログインする必要がありますが、そのログインURLをBookmark AppとしてOktaに登録しておくことで、疑似的にIdP-Initiatedのようにログインすることができるようになります。
これによって、Oktaのダッシュボード/ブラウザプラグインにアプリを集約することができます。

# CSS Selectorの指定
じゃぁどうやって各ユーザーフィールドを指定するのか。
Copy CSS SelectorというChrome拡張を使うと右クリックで値を取得できるのでお勧めです。
自分で確認して設定したい方はChromeの開発者ツールを使って確認してください。

# さいごに
いろいろなログイン画面をOktaに登録してみると使い方がわかってくると思います。
社内開発のWeb画面なども登録できるのでぜひやってみてください。
未経験エンジニアが入社して取り組んだ課題と初めてのタスク

こんばんは。おでこと申します🍢

アドベントカレンダー3日目です🎄
ソロ完走を目指しています！！
まだまだ道のりは長いですね…

私は2023年9月1日にフロントエンドエンジニアとして自社開発のSaaS企業に入社しました。
未経験独学で、薬剤師からの転職です。
詳しくはこちらをご覧ください。
[未経験独学で自社開発企業へ〜薬剤師からのエンジニア転職記〜](https://qiita.com/odendayoko/items/f616b2f1952897a9af5d)

本日は入社してから、取り組んだ課題と初めてのタスクの内容について書きます。
未経験でWEBアプリケーションエンジニアを志している方の参考になれば嬉しいです。

## 初日
私の会社はフル出勤です。
まずPCを支給されました。
デバイスはMacBookPro M2です。
新しくMacを開封するのってめちゃめちゃワクワクしますよね✨

初日はオリエンテーションとPCのセットアップ、社内ルールの説明を受けました。

メンターさんが1人ついてくださることになり、その方とデスクの席も隣でした。
いつでもすぐに質問できる環境が整っていました。

## 1週目　ラーニング
2日目から1週間のラーニングに入りました。
入社前から共有されていたカリキュラムに沿って進めていきます。
事前に進めてはいましたが、正直全くわからず不安でしかなかったので、復習をしつつ、進めていきました。
以下が課題として取り組んだ教材です。
- [JavaScript Primer](https://jsprimer.net/)
- [りあクト！](https://oukayuka.booth.pm/items/2368045)
- [モダンJavaScriptの基礎から始める挫折しないためのReact入門](https://www.udemy.com/course/modern_javascipt_react_beginner/)

### [JavaScript Primer](https://jsprimer.net/)
[第一部: 基本文法](https://jsprimer.net/basic/)を読むという課題でした。
私はRubyしか触れたことがなかったので、JavaScriptの文法を学ぶところからのスタートでした。
しかし、この書籍は正直全く面白くなかったので、さらっと読み飛ばしました😇

現在は実務でわからないコードが出てきた時に、索引から調べて辞書的に使っています。

### [りあクト！](https://oukayuka.booth.pm/items/2368045)
基本的には3巻全て読むことが課題でした。
一部、社内で使用していない技術に関しては飛ばして良いと言われました。

この書籍めちゃくちゃ難しいです。
入社前にも読んだ初見では、何を書いているのか全くわからず…
再度読みましたが、やっぱりわかりませんでした。

ここで時間をかけても仕方がないということで、理解することを諦めました！
時にはメンターさんに講義のような形で説明を受けながら、とりあえず読み切りました。

### [モダンJavaScriptの基礎から始める挫折しないためのReact入門](https://www.udemy.com/course/modern_javascipt_react_beginner/)
Udemyで有名なReact講座です。
自分で簡単なTODOアプリを作ることができます。

初めて自分で手を動かして、Reactを用いたアプリを作ることができました。
手を動かした方が断然頭に入りやすいですし、何より楽しいです！

2023年11月フルリニューアルしたそうなので、興味のある方はぜひ受講してみてください👍

## 2週目　OJT研修開始　ついに実務へ
入社2週目でなんと実務に入ることになりました。
**いや、流石に早すぎませんか！？**

転職期間中に面接を受けた企業のほとんどが研修は3ヶ月だったので、大体どこもそんなものだろうと思っていたのですが、まさかの1週間！！！！
実務に入らせてもらえるのはありがたいけど、本当に大丈夫なのか？と不安でした…

### OJTオリエンテーション
まずは社内での開発フローを教えていただきました。
Gitの使い方、PRの書き方、テスト依頼の仕方などです。

印象的だったのは、**わからないことはガンガン聞く。悩むのは最大10分**というルールです。
大体のことは1人で悩まずに相談した方がいいという考えに基づいているそうです。
特にGitに関することは、わからなければすぐに質問して欲しいと言われました。

このルールは今でも意識しています。
**わからないことを物おじせずに質問できる能力**はエンジニアには必要だとも先輩に教えていただきました。
これからも遠慮せずにガンガン質問していきます！

次に環境構築を済ませ、いよいよタスクに入ることになりました。

### 初めてのタスク
「表形式で◯◯一覧を表示する画面で、各行にマウスを乗せた時、その行の背景色の色を変える」というタスクです。
要は、マウスhoverした時CSSでbackground-colorを指定するだけの簡単な実装です。
タスクの説明を受けた時は、あれ意外とできそう！と思いました。
覚えたてのReactの知識も必要なさそうだし、ポートフォリオでも使ったことのある技術だったからです。

しかし、実際にコードを書こうとするといくつか問題がありました。
- プロダクトの機能がわからないため画面を開けない
- CSSの書き方が見たことない書き方になっている

#### プロダクトの機能がわからないため画面を開けない
入社してからプロダクトを触ってはいますが、まだまだ知らない機能がたくさんあります。
入社したらプロダクトについて機能やページを覚える必要があります。
要件を伝えられても、その画面の開き方がわからなければ実装はできないからです。
知らないのは仕方がないことなので、メンターさんに丁寧に教えていただきました。

#### CSSの書き方が見たことない書き方になっている
ポートフォリオではCSSのクラス名は適当につけていました。
トップページの保存ボタンだったら`top-submitbutton`みたいな感じで自分がわかればいいと思っていました。

一方、プロダクトはSCSSでキャメルケース、BEM命名規則に基づいて書かれていました。
CSSなのにネストが多すぎて別物に見えました。

簡単な実装だと思いきや、実際にコードを書いてみると、そううまくはいきませんでした。
これが実務か…と課題をこなしていた時とは違う難しさを実感しました。

メンターさんに助けられながらなんとか実装することができました。
初めて実装できたのが嬉しくて、何度も表の上でカーソルをぐるぐる動かして色が変わるのを見ていました笑

先輩方が「初めての実装おめでとう」と声をかけてくださり、嬉しさが倍増しました。

## 終わりに
この機能がリリースされた後、社員全員が参加する会議で、「こちらおでこ。が初めて実装した機能です」と共有していただきました。なんとなく社員として認められた気がして、嬉しかったのを覚えています。

先輩が「初めての実装は忘れられないよね」とおっしゃっていました。私もきっと忘れないだろうと思います。
JSでカレンダー作りました！

# はじめに
　私はITについて勉強をしている学生で、最近JavaScriptについて学習しています。私はもともとフロントエンドについて興味があったので、楽しく学習しています。今回クラスのみんなでアドベントカレンダーを作成するということになり、自分は何をしようか考えました。ふと、カレンダーを作ろうと思い最近習っているJavaScriptを使用して作ることにしました。
## サンプルコード

<details><summary>HTML</summary></details>

![HTML.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630834/1b5dfb3a-8a83-f192-0626-bb502b939eef.png)

<details><summary>CSS</summary></details>

![css.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630834/d91b285a-f064-5423-4e8c-3cf0efb7869f.png)

<details><summary>JavaScript</summary></details>

![js.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630834/eae8ca6b-bc90-67ba-fa21-3e964d33a284.png)

![js2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630834/b2c6f0d0-5ebb-e13c-1a92-ae84dfee68d7.png)



## 完成した画面
完成した画面はこのようになりました。

![calendar_complete.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630834/be46631b-3238-ed29-4317-9e2518306d0f.png)

サンプルコードはシンプルなものにしましたが、私らしさを出したかったので、CSSを変えてピンクっぽいカレンダーにしてみました。

![pink.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630834/ab9ab561-6e30-b6bf-3ba0-1a1320343652.png)


クリスマスを意識したデザインも...

![Christmas.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630834/d7db4893-4c78-f4b8-b9e2-de78b0f98faa.png)

こんな風に自分でCSSを変えるのも楽しいですね。

# まとめ

　いかがでしたでしょうか。サンプルコードを使って皆さんもカレンダーを作ってみてください！！読んでくれてありがとうございました。
 ###### クリスマスまであと22日:santa_tone1::calendar:
Livewireで簡単にリアルタイム通信してみた

# livewireでリアルタイム通信可能な掲示板を作る

この記事はアドベントカレンダー3日目の記事になります。

実際にサーバーにアップロードしたかったのですが、間に合いそうになかったのでよければデモ動画を見てみてください
2つのローカルを使って検証しています。

https://youtu.be/TQO4m6uIYeU

## はじめに
Laravelを使って他のユーザーとのリアルタイム通信を行うのはハードルが高く感じることが多いです。
それが開発のネックになってしまうのではと感じ、今回のように比較的学習コストを少なくリアルタイム通信機能を導入する方法の記事を執筆させて頂くことにしました。


## 開発準備

まずdockerで `instantSNS`という名前のLaravelアプリケーションを立ち上げます。

```
curl -s "https://laravel.build/instantSNS" | bash
```

詳しい解説はLaravelの公式ドキュメントをご覧ください。

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


## コマンド

LivewireもLaravelのコントローラと同様にコマンドラインを使用して作成されます

```

./vendor/bin/sail composer require livewire/livewire

```

上記コマンドにより生成されるファイルは以下の２つです。
`/instantSNS/resources/views/livewire/post`
`/instantSNS/app/Livewire/Post.php`

Livewireではコマンドを打つことでviewファイルも同時に生成されます。
また、livewireを使ってDBと通信する場合はこちらのファイル内で処理の内容を記述する必要があります。

次に、マイグレーションファイルとモデルを作成しましょう

```

./vendor/bin/sail artisan make:model Post -m

```

これで、開発の準備が完了しました。

## livewire使い方

簡単にlivewireの使い方を解説させていただきます。
livewireは通常のviewファイルの中で以下のコードを記入するだけで、使うことができます。
（今回は例として先ほど作成した `post.blade.php`を使います。）
```
// welcome.blade.php

<body>
    <livewire:post />
</body>

```

上記のように`<livewire:[ファイル名] />`という記述方法になります。
また、livewireファイルに変数を渡したい場合にはviewファイルとコントローラ側でコードを記述する必要があります

```
// viewファイル

<livewire:post :hoge="$hoge" />

```
```
// コントローラファイル (/app/Livewire/Post.php)

class Post extends Component
{
    public $hoge; // 渡す変数名をここに記述

    // 中略

}

```
上記のようにすれば大丈夫です。
`※変数の受け渡しがエラーの原因になることが多いので注意してください`


## リアルタイム通信
今回より簡単にリアルタイム通信を行うため、`wire:poll`を使用しました。
この技術では定期的にリクエスト送信をすることで、ページを最新の状態に保つことができます。
必要になるのは2つのlivewireファイルの書き換えだけです。掲示板への投稿、livewire側の処理全てのコードは以下の通りです。


`/instantSNS/app/Livewire/Post.php`
```

<?php

namespace App\Livewire;

use Livewire\Component;
use App\Models\Post as PostModel;

class Post extends Component
{
    public $text;

    public function create()
    {
        PostModel::create([
            'content' => $this->text,
        ]);
    }
    public function render()
    {
        return view('livewire.post', [
            'posts' => PostModel::all()->sortByDesc('created_at'),
        ]);
    }
}


```

`/instantSNS/resources/views/livewire/post`

```

<div>
    <div class="view" wire:poll.2.5s> // ここでリクエストの間隔を指定
        @foreach ($posts as $post)
            <div class="item">
                <div>{{ $post->content }}</div>
                <div class="created_at">{{ $post->created_at }}</div>
            </div>
        @endforeach
    </div>

    <div class="form">
        <form wire:submit.prevent="create">
            @csrf
            <input type="text" wire:model="text">
            <button type="submit">投稿</button>
        </form>
    </div>
</div>

```

上記のコードはデータの投稿と定期的にページを更新する処理を一緒に行なっています。

`<div class="view" wire:poll.2.5s>`
`wire:poll`を`15s`にすることで15秒おきにリクエストを送れます。

詳細は以下の公式ドキュメントをご覧いただいた方が早いと思います。

https://livewire.laravel.com/docs/wire-poll

## 最後に

今回説明に使用したコードはgithubで公開しています。

https://github.com/kokekokko0116/instantSNS

## 宣伝

ビジネスの最初の5分を変えるwebアプリの作成を行なっています。もし興味があれば触ってみてください。

https://byn.jp/flyer/4fc47013-4622-4aa3-be1a-08e91d680b9b
Storybookで自動的に入る余白をなくす

# やりたいこと
初期状態ではコンポーネント表示エリアに`padding: 16px`の余白ができているので、これをなくします。

![storybookのキャプチャ画像。コンポーネントが表示エリアに対して上下左右に余白を持って表示されている](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3633909/302a23d0-05b7-a831-5888-6a70a5343514.png)

# 方法
`.storybook/preview.ts` ファイルで以下のように設定することで、コンポーネント表示エリアの全画面表示が可能になります。

```typescript:.storybook/preview.ts
import type { Preview } from "@storybook/react";

const preview: Preview = {
    // ...様々な設定...
  
	// ↓↓↓全画面の設定
    layout: "fullscreen",
  },
};

export default preview;
```

![storybookのキャプチャ画像。コンポーネントが表示エリアに対して余白なくぴったりくっついて表示されている](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3633909/10104c81-861b-36b2-2daa-881b1fe22532.png)

`fullscreen`の他に2つ設定値があり、初期状態で余白がついているのは初期値が`padded`となっているためです。

|centerd|fullscreen|padded（初期値）|
|:-:|:-:|:-:|
| 中央揃えに表示します|余白を無くして全画面で表示します|上下左右に余白をつけて表示します|

`.storybook/preview.ts`に記述することで共通設定となりますが、個々のstoriesファイルでも設定が可能です。

# 検証バージョン・公式リファレンス

検証に使用したStorybookのバージョンは`7.4.6`です。

今回の対応に該当する公式ドキュメントは以下です。
https://storybook.js.org/docs/configure/story-layout
今年一年を振り返る

[はじめてのアドベントカレンダー Advent Calendar 2023](https://qiita.com/advent-calendar/2023/first-time) 4日目の記事です。

## はじめに
今年は去年までフリーランスだった私が正社員として就職して、はじめてアウトプットを始めた年でもあります。


## 2023年の11月までに書いた記事

https://qiita.com/makoto-ogata@github/items/3d62b31167d098c13767

https://qiita.com/makoto-ogata@github/items/ffa4eaf665e6b3fe83b5

https://qiita.com/makoto-ogata@github/items/818e4b22dd320afe7f5f

https://qiita.com/makoto-ogata@github/items/132f0a6b8b3707d90c13

https://qiita.com/makoto-ogata@github/items/f9fee9dade897236fd1c

https://qiita.com/makoto-ogata@github/items/7a65fffdf8c38f7f3baf

https://qiita.com/makoto-ogata@github/items/8d6e8f2474f9cc0988c4

https://qiita.com/makoto-ogata@github/items/93cd708ff230c41f35b3

https://qiita.com/makoto-ogata@github/items/29903fa1ab09568e5040

https://qiita.com/makoto-ogata@github/items/176d5f3d215a3c853c1f

https://qiita.com/makoto-ogata@github/items/dcbc5ecc440338140911

https://qiita.com/makoto-ogata@github/items/0418ac16efdadd96919e

以上、12記事です。
アウトプットを去年まで全くやってこなかったし、遅筆を自認している人間としては今年は「アウトプットすることを慣れさせる」という年でした。

## アウトプットしてみて

以前までの私は「こんなの書いたところで…」とか「これについて書こうと思ったけど、もう別の人が書いてた…」とか記事を書く理由よりも書かない理由の方が先にきていました。
記事を書くことに関して、上長と壁打ちしてもらうこともあるのですが「**誰か一人のためになるかもしれないし、その一人が自分自身であってもその記事には意味がある**」という言葉をいただき、だいぶアウトプットに対して抵抗がなくなりました。

実際に以下の記事とかエラーの解決法しか書いてなかったのですが、私にとっては役に立ちました。

https://qiita.com/kkdd/items/be150c3bd38ca6a20451

アウトプットの内容も、他の人が同じ様な事を書いてたとしても気にせずに書くようになりました。
完全な盗作は論外ですが、自分の手元で動かしてみて、自分の考えた文章で書くことに価値があると思います。

## 終わりに

今年はReactを初めて業務で触り始めた年でした。
業務レベルに追いつけるようにUdemyなどで学んだことをアウトプットとして残してきましたが、会社の先輩方に追いついてるとはまだまだ言えません（Reactのスキルも客観的に見てジュニアレベルだと思っています）
アウトプットの量や質に関しては、もっと沢山やってる方もいらっしゃるし上を見上げればキリがありません。
とはいえ、何もアウトプットしてこなかった人間が11ヶ月で12記事書き上げたことに関して、自分自身を褒めてあげたいと思っています。
（今年の締めみたいな記事になりましたが、年内はこの記事以外にあと4記事書く予定です）
知っておくと便利な原則

## SOLID
SOLID原則は、オブジェクト指向設計の5つの基本的な原則を表します。
これらの原則は、ソフトウェアの保守性と拡張性を向上させることを目的としています。

- 単一責任の原則（Single Responsibility）
目的：1つのクラスは1つの責任を持つべき。
理由：クラスが1つの責務だけを持つことで、変更が発生した際に影響範囲を最小限に抑える。
- オープン/クローズドの原則（Open/Closed Principle）
目的：クラスは拡張に対して開き、修正に対して閉じていなければならない。
理由：既存のコードを変更せずに新しい機能を追加できるようにすることで、柔軟性、拡張性、安定性を確保する。
- リスコフの置換原則（Liskov Substitution Principle）
目的：基本型(親クラス)はその派生型(子クラス)で置換可能であるべき。
理由：派生型が基本型として振る舞えることで、コードの予測可能性と拡張性を確保する。
- インターフェースの分離の原則（Interface Segregation Principle）
目的：クライアントが利用しないメソッドに依存すべきではない。
理由：クライアントが利用しないメソッドに依存しないことで、冗長な依存関係を回避する。
- 依存性逆転の原則（Dependency Inversion Principle）
目的：高水準のモジュール(上位の機能)は低水準のモジュール(下位の機能)に依存すべきではなく、どちらも抽象に依存すべき。
理由：高水準のモジュールが低水準のモジュールに依存せず、抽象に依存することで、柔軟性と拡張性を向上させる。

## KISS（Keep It Simple, Stupid）
目的：シンプルなソリューションが複雑なものよりも優れているという考え方。
理由：冗長なコードや複雑な構造はバグの原因となりやすく保守性が低下する。

## DRY（Don’t Repeat Yourself）
目的：同じコードやロジックを重複せずに再利用すること。
理由：共通の機能やロジックを関数やクラスにまとめることで、変更が発生した場合に一箇所の修正で済み、コードの一貫性が保たれる。

## YAGNI（You Ain’t Gonna Need It）
目的：将来の利用を想定せず、不必要な機能や拡張を避けて開発効率を向上させる。
理由：不必要な機能は開発時間の無駄であり、過剰な拡張はコードベースを複雑にし、保守性を低下させるから。

## SLAP（Single Level of Abstraction Principle）
目的：コード内で同じレベルの抽象度を維持すること。
理由：コードの読みやすさを向上させ、理解が容易になり、保守性が向上する。

## Separation of Concerns
目的：システムを異なる概念や機能に基づいて複数の独立した部分に分割すること。
理由：関心ごとの分離により、モジュール性が向上し、変更が特定の領域に制限され、保守性と拡張性が向上する。

## Leaky Abstraction
目的：抽象化が完全でなく、内部の実装の詳細が漏れることを最小限に抑えること。
理由：完全な抽象化が難しい場合、詳細が漏れると、使用者が予測できない挙動や問題に直面する可能性があるため。

## まとめ
これらの原則を適用することで、ソフトウェア開発プロセスがより効率的かつ効果的になります。各原則は、特定の問題を解決するためのガイドラインを提供し、より良い設計決定を行うのに役立ちます。ソフトウェアの品質を向上させるために、これらの原則を常に念頭に置くことが重要です。
Kotlin / composeの同じようで同じじゃない話

# はじめに
自分がKotlinのcomposeを使ってAndroidアプリの開発をしているときにこれとこれって形が似ているけど何が違うんだろうと思い調べたことを書いていきます。

## LazyRowやLazyColumnのcontentPaddingとModifier.paddingの違い
LazyColumnやLazyRowのパラメータにあるcontentPaddingで余白をつけるのと、Modifier.paddingで余白をつけるのとではどちらもその要素自身に余白をつけるということなので同じようなUIになるのでは？？

### いざ実践！！
**contentPadding**
```
LazyRow(
    contentPadding = PaddingValues(15.dp) //<-
) {
    items(10) {
        Text(
            text = "Item $it",
            modifier = Modifier.padding(5.dp)
        )
    }
}
```
**Modifier.padding**
```
LazyRow(
    modifier = Modifier.padding(15.dp) // <-
) {
    items(10) {
        Text(
            text = "Item $it",
            modifier = Modifier.padding(5.dp)
        )
    }
}
```
### 完成したもの
![content.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2987949/9ee89d1b-47b1-2c60-551e-6ba74de594c8.gif) 
上がcontentPadding
下がModifier.paddingで余白を指定
### 違いについて
上の動画を見ると、
contentPaddingで指定した場合はLazyRowの**画面に見えていない部分も含めた全ての要素**の上下左右に余白ができている。
Modifier.paddingはLazyRowの**画面に見えている部分の要素**の上下左右に余白ができている。

つまり下の図のようなイメージである。

<img width="400" alt="スクリーンショット 2023-12-03 23.11.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2987949/d38a45fc-ef42-ac09-6fd9-f8bb341b2562.png">

### まとめ
**contentPadding**を使うと、片方には余白があるがもう一方には余白がないという状態から始まるので、スクロール可能であることがわかりやすい。
**Modifier.padding**を使うと、常に上下左右に余白をつけることができるが、スクロールする際、画面の端からではなく、画面の途中から要素がでてくるためちょっと気持ち悪い。また、要素がキリよく表示されていた時、スクロールできるのかが少し分かりづらい。他の要素や、場面に応じて使いわけよう！！
EC2の"終了”は"削除"だ．シャットダウンではない．

## 背景

**「EC2の"終了"は"削除"だ」**　めちゃくちゃデカい声で言いたい．

仕事を通して，AWSに関する一通りの基礎知識が身についたころ，
「テスト環境EC2インスタンスを削除する」やらかしをしてしまった．
結構間違えると思うので，屍として経緯と３つの学びを残しておこうと思う．

## 失敗した経緯

EC2にsshで接続し，「EC2が起動した際に自動でプロセスが立ち上がるようにする」作業していた．
プロセス設定の作業をやり終えた後，動作確認をするため，EC2をAWSコンソールから再起動した．
ssh接続して，指定したプロセスが動いているのを確認したのちに，
「次は，シャットダウンして起動する方の動作確認」をしようと考えた．
普段別の人が，EC2を落とす担当だったのでシャットダウンをするのは初めての作業だった．
EC2インスタンスの状況変更のオプションのうち，シャットダウンできそうなのは，"停止"・"休止"・"終了"の3つがある．迷った．

![解釈.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3600683/82f10bfa-caf2-9d5b-80d4-dd44d884bd63.png)

自分がよく使うwin10の電源オプションに当てはめて解釈した．
3つあるうち，停止はスリープ的なもの，休止は文字通り休止状態，終了はシャットダウンと解釈し，
「インスタンスを終了」をした．すると確認画面が出る．

![終了メッセージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3600683/ab3e1063-3d07-9abf-89f2-1d16fd3df0e4.jpeg)

... わからない文字が並んだ．
自分にとって，EBS-Backedインスタンス/ルートEBSボリュームが何か当然分からない．
「ローカルドライブにあるストレージは失われます」に関しては，思考停止して読んでいない．
もしくは，「割り当てたストレージへの接続が切れるだけでどこかにはデータが残っている」と解釈したかのどちらかだったと思う．
今読むと，明らかに「インスタンスにあるデータが消えます」という意味だと思う．

そしてそのまま終了ボタンを押して...

![end.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3600683/9c97e66e-766c-a678-2197-f93475984a92.jpeg)

本番環境じゃなくてよかったと本当に思う．

## 学んだこと

### 終了保護をしよう：削除不可

作業中のインスタンスを，削除するタイミングってないと思う．
なので，「削除できないようにする」方法を取るならば，終了保護を有効にするのが一番早い．

![手順.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3600683/d6582953-e668-bff4-7b1b-32bc692b0e2b.png)

終了保護を有効化すると，終了確認画面にも遷移するし，終了ボタンも押せるが，
押した後に削除できないエラーが発生し，削除処理が止まる．
終了確認画面では，終了保護が有効になっている情報も表示される．

![motomeru終了.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3600683/2b8facaf-c54a-6ebe-fa62-87b0c8fdf7d2.jpeg)

### バックアップを取る：復旧可能

バックアップに関しては，今回のような人災以外にもしておいて損はないと思う．
AWSでバックアップを取ることを，**スナップショットの作成**と言うので，
毎回思い出すのに時間がかかる.

![snapshot_zu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3600683/20523e85-c3ef-b69f-b8ea-d3564aa50afe.png)

EC2インスタンスを指定してバックアップするようにしている．

### 分からなかったら聞こう：事故防止

自分は聞き方に関して，以下の順で話すようにルールを設けている(とはいいつつ得意ではない)．
1. 自分の**したい事**を最初に言う
「EC2のインスタンスをシャットダウンしたい」
1. 自分が**つまずいていること**をする
「インスタンスの状態の選択肢が3つあって分からない」
1. 補足する形で**情報共有**をする
「現在，テスト環境で自動でプロセスが立ち上がるようにする設定をしていて....」

この形式だと，相手がせっかちなら1.か2.で情報をもらえて，
ちゃんと適材適所つかんで処置・教育目的で話を聞いてくれる場合でも3.まで行けば情報をもらえる形となる．

## まとめ

**「EC2の"終了"は"削除"だ」**
インスタンス1つを生贄にしたことで得られたものは大きいと思う．
終了保護・バックアップ・聞くの3つは可能な限り必ず続けていく．
闘魂Elixir ── mix phx.new hello --adapter banditしてみたよ

<b><font color="red">$\huge{元氣ですかーーーーッ！！！}$</font></b>
<b><font color="red">$\huge{元氣があればなんでもできる！}$</font></b>

<b><font color="red">$\huge{闘魂とは己に打ち克つこと。}$</font></b>
<b><font color="red">$\huge{そして闘いを通じて己の魂を磨いていく}$</font></b>
<b><font color="red">$\huge{ことだと思います}$</font></b>



# はじめに

[Elixir](https://elixir-lang.org/)の[アドベントカレンダー](https://qiita.com/advent-calendar/2023/elixir)を楽しんでいます。

https://qiita.com/piacerex/items/0c6ffb235e1146c38302#bandit

[Bandit](https://github.com/mtrudel/bandit)が[Phoenix](https://www.phoenixframework.org/)に標準搭載されたとのことを @piacerex さんの記事で知りました。

[Bandit](https://github.com/mtrudel/bandit)については以下の記事のようにLINEボットアプリ制作で使ったことがあります。

https://qiita.com/torifukukaiou/items/05255dc857ddd5a695ee

# What is [Elixir](https://elixir-lang.org/) ?

[Elixir](https://elixir-lang.org/)という素敵なプログラミング言語があるのですね。
その素敵具合は「[Elixir Saves Pinterest $2 Million a Year In Server Costs](https://paraxial.io/blog/elixir-savings)」によく現れています。開発者も経営者もこの事実に瞠目することでしょう。 **$2 Million/年の節約ですってよ！、奥さん。**

https://paraxial.io/blog/elixir-savings

# mix phx.new hello --adapter bandit

`mix phx.new hello --adapter bandit`というふうにした場合に、[Bandit](https://github.com/mtrudel/bandit)が採用されます。
`--adapter`オプションを指定しない場合のデフォルトは[cowboy](https://github.com/elixir-plug/plug_cowboy)です。

# `--adapter bandit`を付けて実行した場合と付けずに実行した場合の違いについて

`mix.exs`と`config/config.ex`の2箇所です。

```diff:mix.exs
-     {:plug_cowboy, "~> 2.5"}
      {:bandit, ">= 0.0.0"}
```

```diff:config/config.ex
config :hello, HelloWeb.Endpoint,
  url: [host: "localhost"],
- adapter: Phoenix.Endpoint.Cowboy2Adapter,
  adapter: Bandit.PhoenixAdapter,
```

この情報があれば、古いプロジェクトをアップグレードしてなおかつ[Bandit](https://github.com/mtrudel/bandit)に載せ替えることもできそうですね！
（アップグレードはそれなりにたいへんです）

# さいごに

`mix phx.new hello --adapter bandit`を試してみました。
`--adapter bandit`を付けて実行した場合と付けずに`mix phx.new`を実行した場合の差を示しました。

---

人類は不老不死の霊薬を意味する素敵なプログラミング言語[Elixir](https://elixir-lang.org/)を手に入れました。並行処理を他のプログラミング言語よりも比較的容易に書くことができます。それはきっとコンピュータ資源を有効活用できることにつながるでしょう。巡り巡って世界平和に貢献できることでしょう。

さあ、そこのあなたも[Elixir](https://elixir-lang.org/)の世界へようこそ。
_手始めに[エリクサーチ](https://elixir-lang.info/)なんていかがでしょうか。私のオススメです。_

---

**闘魂**とは、  **「己に打ち克つこと。そして闘いを通じて己の魂を磨いていくことである」** との猪木さんの言葉をそのまま胸に刻み込んでいます。
知っているだけで終わらせることなく、実行する、断行する、一歩を踏み出すことを自らの行動で示していきたいとおもいます。
**アントニオ猪木さんのメッセージから元氣をもらったものとして、それを次代に語り継ぎ、自分自身が「闘魂」を体現するものでありたいとおもいます。**

---

<b><font color="red">$\huge{元氣ですかーーーーッ！！！}$</font></b>
<b><font color="red">$\huge{元氣があればなんでもできる！}$</font></b>
<b><font color="red">$\huge{１、２、３ ぁっダァー！}$</font></b>
「ポイントで人生が変わる？」ゲームの報酬システムの魔法

# Day 3: 「ポイントで人生が変わる？」ゲームの報酬システムの魔法

## ゲームの報酬システムとその効果

ゲームの報酬システムは、プレイヤーに即座の報酬（ポイント、トロフィー、バッジなど）を提供することで、ポジティブなフィードバックを生み出し、行動の強化と継続的な参加を促します。このシステムは、達成感を与えることで自己効力感を高め、ユーザーが自分の能力を信じ、新たな挑戦に自信を持って取り組むようになります。

現実世界での応用例としては、健康管理アプリや教育プラットフォームなどがあり、これらはユーザーの健康習慣の形成や学習意欲の向上に貢献しています。このように、ゲームの報酬システムは単なる楽しみを超え、実生活における行動変容や目標達成の手助けとなる可能性を持っています。

![gamification-20231203-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129712/dd716f1f-acfb-9df9-081a-663db4562dcc.png)


## 国内の事例

### 楽天スーパーポイント

https://point.rakuten.co.jp/guidance/

楽天では、購入やレビューの投稿でスーパーポイントを獲得でき、これを様々な商品やサービスの購入に利用できます。このシステムは、顧客の購入行動とブランドへの忠誠心を促進します。

### Tポイントシステム

https://t-point.tsite.jp/guide/about/

Tポイントは、購入や特定のアクションに応じてポイントを獲得できるプログラムです。獲得したポイントは、商品購入やサービス利用に使用可能で、顧客のリピート購入を促します。

### ドコモのdポイントクラブ

https://dpoint.docomo.ne.jp/index.html

NTTドコモのdポイントクラブでは、携帯電話の利用料金に応じてポイントが付与され、これを商品やサービスの割引に利用できます。また、アプリ内のミニゲームで追加ポイントを獲得することもできます。

## 国際的な事例

### Starbucks Rewards

https://www.starbucks.co.jp/rewards/

顧客はコーヒーや他の商品の購入で星（ポイント）を獲得し、これを無料のドリンクやフードアイテムに交換できます。この即時報酬システムは顧客にリピート購入の動機を与え、達成感を提供します。顧客はポイントを貯める行為に喜びを感じ、ブランドへの忠誠心が高まります。

### LinkedInのスキルアセスメント

https://www.linkedin.com/help/linkedin/answer/a507663

ユーザーは特定のスキルテストに合格すると、そのスキルのバッジをプロフィールに表示できます。このバッジは、ユーザーの専門性と信頼性を高める即時の報酬として機能し、達成感と自信を与えます。これにより、ユーザーのキャリア機会が向上し、プラットフォームへの関与が深まります。

### Fitbit

https://www.fitbit.com/global/jp/home

Fitbitはユーザーのアクティビティを追跡し、ステップ数や運動量の目標達成時にバッジを授与します。この即時報酬システムは、ユーザーの健康に関する目標達成を促進し、日々の運動習慣を維持する動機を提供します。

### Khan Academy

https://ja.khanacademy.org/

学習の進捗に応じてバッジやポイントを獲得するシステムは、学習者に具体的な目標を設定し、教育プロセスにおける達成感を提供します。これは学習者のモチベーションを高め、継続的な学習意欲を促進します。

### Wazeナビゲーションアプリ

https://www.waze.com/live-map/

Wazeは、ユーザーが道路情報を提供するとポイントを獲得できるシステムを採用しています。このインセンティブは、ユーザーがアプリを積極的に使用し、コミュニティに貢献する動機付けとなっています。

### Forestアプリ

https://mobareco.jp/a21811/

このアプリは、ユーザーが集中して作業する時間を設定すると、その間に仮想の木が成長します。集中時間を完了すると、ユーザーは仮想の森を育てることができます。このシステムは、集中力を保つための楽しい動機付けを提供します。

## まとめ

![gamification-20231203-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129712/a3eda096-458c-0583-7055-e04c8ea72831.png)

報酬システムは、そのシンプルさの中に隠された深い影響力を持っています。日常生活やビジネスに応用された場合、このシステムはモチベーションを高め、人々の行動パターンにポジティブな変化をもたらすことができます。

次回の記事では、ゲーミフィケーションの核心であるフィードバックの力に焦点を当て、目標達成への道を照らす「進捗バー」の重要性を探ります。日常生活や職場におけるフィードバックの効果的な活用方法や、そのインパクトについて深く掘り下げていきます。ゲームの原理がどのように私たちの目標達成をサポートするのか、その魅力と可能性を詳しくお伝えするので、どうぞご期待ください！
遊び心で世界を変える！ ゲーミフィケーションの驚異的な力

#  「遊び心で世界を変える！ ゲーミフィケーションの驚異的な力」



## ゲーミフィケーションの魔法
ゲーミフィケーションとは、ゲームの要素を非ゲームの文脈に応用することで、人々の行動やモチベーションを変革するアプローチです。これは、ビジネス、教育、健康、社会変革など、さまざまな分野で応用されています。ゲームの持つ楽しみ、挑戦、達成感といった要素を日常生活や仕事に取り入れることで、人々の行動を変え、新しいやり方でモチベーションを高めることが可能になります。

![gamification-20231201-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129712/23b41732-9c8b-d26d-bc81-9bd4024f1ed9.png)

## ゲームの力
ゲームは、楽しみ、挑戦、達成感といった要素で私たちを引きつけます。これらの要素を日常生活や仕事に取り入れることで、人々は新しいやり方でモチベーションを高め、目標に向かって努力するようになります。

![gamification-20231201-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129712/da2f545e-f63b-5f2e-6dc4-1a11c0c60c0e.png)


## ゲーミフィケーションの例

| 分野     | 例                                                    |
|----------|--------------------------------------------------------|
| ビジネス | 顧客ロイヤルティプログラムでのポイントやバッジの使用   |
| 教育     | 学習アプリケーションでの進捗バーの活用                 |
| 健康     | フィットネスアプリにおけるユーザー活動の追跡と報酬    |

### ゲーミフィケーションの例とその6要素
ゲーミフィケーションは、ビジネス、教育、健康など多岐にわたる分野で応用されています。その効果を高めるためには、以下の6つの要素が重要です。

- **能動的な参加** - 例: 『[しゅくだいやる気ペン](https://www.kokuyo-st.co.jp/stationery/yarukipen/)』[コクヨ株式会社] 
- **達成可能な目標設定** - 例: 『[みんチャレ](https://minchalle.com/) - 三日坊主防止アプリ』[エーテンラボ株式会社]
- **称賛を演出** - 例: 『[サンクスUP！働くをゲーム化する人事評価システム](https://39s-up.com/)』
- **即時のフィードバック設計** - 例: 『[いきものコレクションアプリ Biome（バイオーム）](https://biome.co.jp/app-biome/)』[株式会社バイオーム]
- **成長の可視化** - 例: 『[そろタッチ](https://www.sorotouch.jp/)』[株式会社Digika]
- **独自性の歓迎** - 例: 『[SDGs ゲーミフィケーション教材](https://www.kanazawa-it.ac.jp/sdgs/education/application/)』[金沢工業大学 SDGs推進センター]

参考: [ゲーミフィケーション６要素](https://www.jgamifa.jp/6elements)

## 効果的なゲーミフィケーション
効果的なゲーミフィケーションは、単にポイントやバッジを追加すること以上のものです。重要なのは、ユーザーに価値を提供し、彼らの内発的なモチベーションに訴えかけることです。これにより、参加者はゲームのような体験を通じて、自然に行動を変え、目標に向かって前進することができます。

![gamification-20231201-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129712/4ad54027-20f9-ee54-5035-cbc6ca44d154.png)


## ゲーミフィケーションの心理学
ゲームには強力な心理学的側面があります。人々は達成感、自己効力感、所属感を求めており、ゲーム要素はこれらの欲求を満たすのに最適です。例えば、リーダーボードは競争心を刺激し、チームでの協力を促します。また、達成バッジやレベルアップは、努力が報われるという感覚を生み出し、さらなる活動を促進します。

![gamification-20231201-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129712/d9673414-2859-2bfd-0b3e-b0fdc12e2f20.png)


## 実践の課題と解決策
ゲーミフィケーションの導入には、適切な設計が必要です。単にゲーム要素を追加するだけではなく、ユーザーのニーズや動機に適応することが重要です。成功するためには、ユーザーのフィードバックを収集し、継続的にシステムを改善する必要があります。

![20231201-05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129712/5aacb493-5746-f29d-322a-2e8cf0b7a3c9.png)


## 未来への展望
ゲーミフィケーションはまだ進化の途上にあり、その可能性は無限大です。ビジネス、教育、健康、さらには社会変革のためのツールとして、我々の生活に革命をもたらす可能性を秘めています。未来に向けて、より洗練され、効果的なゲーミフィケーションの方法が開発されていくでしょう。

ゲーミフィケーションにより、私たちは「遊び」を通じてより良い世界を創造することができるのです。次回は、ゲームの心理学がどのように私たちのモチベーションを高めるのかを探ります。お楽しみに！
`dependent: :destroy`のhas_one関連レコードbuild時の奇妙な挙動


ある時、has_oneの関連レコードがすでに紐づいている状態で、build_association_nameで新たなレコードを作成しsaveをしても、特にエラーなどが起きずレコードが置き換わっていることに気づきました。
この挙動が奇妙だったため何が起きているのか調査をしてみることにしました。

## has_oneのbuild_associationでDELETEが実行されていた
rails7.1.2で以下のようなモデルを使って検証をしてみます。
ポイントはhas_oneに対して`dependent: :destroy`のオプションを与えている点です。

```ruby
class Supplier < ApplicationRecord
  has_one :account, dependent: :destroy
end

class Account < ApplicationRecord
  belongs_to :supplier
end
```

Supplierのhas_oneの関連レコードであるAccountを永続化して紐付けた状態にしておきます。

```ruby
irb(main):005> sup = Supplier.create!(name: 'hoge')
=> #<Supplier:0x0000000108691aa0 id: 2, name: "hoge", created_at: Sat, 25 Nov 2023 03:28:05.312517000 UTC +00:00, updated_at: Sat, 25 Nov 2023 03:28:05.312517000 UTC +00:00>

irb(main):006> sup.create_account!(account_number: '1')
=> #<Account:0x0000000109d6fb78 id: 2, supplier_id: 2, account_number: "1", created_at: Sat, 25 Nov 2023 03:29:36.497616000 UTC +00:00, updated_at: Sat, 25 Nov 2023 03:29:36.497616000 UTC +00:00>
```

この状態でbuild_accountを実行すると、以下のようにbuildの時点でDELETEのSQLが発行され既存のAccountのレコードを削除してしまいます。
どうやらbuild_association_nameメソッドが実行された際に、**紐づく既存レコードがあれば暗黙的に削除される**ようです。


```ruby
irb(main):008> sup.build_account(account_number: '2')
  TRANSACTION (0.1ms)  begin transaction
  Account Destroy (0.9ms)  DELETE FROM "accounts" WHERE "accounts"."id" = ?  [["id", 2]]
  TRANSACTION (0.5ms)  commit transaction
=> #<Account:0x0000000109c8f618 id: nil, supplier_id: 2, account_number: "2", created_at: nil, updated_at: nil>
```

もしbuild後のsaveの処理の際に例外が発生すれば、ただ既存レコードが削除されただけとなってしまうのは少し恐ろしいなと感じます...。
ちなみに、`dependent: :destroy`が付与されていないと、buildしようとした時点で以下のように例外が起きます。

```ruby
irb(main):016> sup.build_account(account_number: 1)
/Users/username/.rbenv/versions/3.1.3/lib/ruby/gems/3.1.0/gems/activerecord-7.1.2/lib/active_record/associations/has_one_association.rb:110:in `remove_target!': Failed to remove the existing associated account. The record failed to save after its foreign key was set to nil. (ActiveRecord::RecordNotSaved)
```

## まとめ
既存のレコードが紐づいた状態で`dependent: :destroy`が付与されたhas_one関連レコードをbuild_associationする際は、暗黙的に既存レコードが削除されてしまうことに注意しておきましょう。
buildが既存レコードに影響を及ぼすとは考えていなかったため、この挙動を知った時は驚きました。
もしこのような挙動となっている理由をご存知の方がいたら教えていただきたいです。

ちなみに以下の記事で紹介されているように、create_associationメソッドの挙動に関しても一悶着あったようです。
投稿者の方がおっしゃるように、全員が幸せになるような挙動を作るのはなかなか難しいのかもしれません・・・。

https://blog.willnet.in/entry/2023/07/04/113321
QGISからMySQLに接続する時、MySQLユーザーのパスワードにはカンマを含まないパスワードを設定しよう

このエントリは、[RDBMS-GIS(地理情報・位置情報) Advent Calendar 2023 ](https://qiita.com/advent-calendar/2023/rdbms_gis)の3日目です。「RDBMS-GIS Advent Calendar」では参加者を絶賛募集中です！軽いネタでもいいので、お気楽に参加ください！

QGISからMySQLに接続する時、MySQLユーザーのパスワードにカンマを含めるとMySQLに接続できません。MySQLユーザーのパスワードにはカンマを含まないパスワードを設定しましょう。

この現象はQGISのGitHubでIssueとして報告されていますが(#54493)、GDALの問題と判断された後で、'not planned'に分類されてIssueがクローズされています。

　[QGIS cannot connect to MySQL if user's password contains commas. #54493](https://github.com/qgis/QGIS/issues/54493)

そのため、QGISからMySQLに接続する時は、MySQLユーザーのパスワードにはカンマを含まないパスワードを設定しましょう。
後輩に Markdown 勧める時

# 後輩に Markdown 勧める時

## 内容

後輩が付いた時に Markdown 記法を進めるシーンとそのあとのウケがいいのでどんな勧め方をしているかメモ
（よっぽど自分のメモの取り方にこだわりがないことを確認して）

## Markdown とは

特定の記号を使って特定のサービスやテキストエディタで見出しなら少し大きいフォントサイズだったりボールドにしてくれたりといい感じのスタイルにしてくれる書き方。
Ｂ acklog・Trello のようなタスク管理ツールならだいたいリッチテキストにしてくれる。VsCode のように自動でリッチテキストに変換はされないが、色が付いたり見出しを判定してくれたり付加価値がおおい多い。
ただのメモ帳に書くとしてもパターンが決まるので見出しや箇条書きする時にここは〇ここは △ じゃあ次は □ にしよう。みたいに悩まなくなる。
記法の簡単なのですぐに使い始めることができる。

## とりあえずこれだけ覚えればＯＫ

- 見出し
  - "#"シャープで見出しになる 例) # ほげほげ
  - 後ろには半角スペースをいれること
  - "##"のようにシャープを重ねることで小見出し・小小見出しのようになっていく
  - VsCode だと Outline としてキャプチャのように確認できる。見出しをクリックするとジャンプできる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/658524/0bf51eef-e48a-931e-366c-476dd498d2db.png)

- 箇条書き
  - "-"ハイフンで箇条書きになる 例) - ほげほげ
  - 後ろには半角スペースをいれること
  - インデントを下げることで箇条書きの下に箇条書きとすることができる
- チェックボックス
  - "- [ ]"ハイフンで箇条書きになる 例) - [ ] チェックなし / - [x] チェックあり
  - 後ろには半角スペースをいれること
  - []括弧の中にスペースがないとリッチテキストにならない時もある。自分用のメモの際は面倒なのでスペースを入れない。必要なら対象だけ置換していれる。

## これもできることは知っといて

以下は必要になったら調べて使う

- ボールド
- 取り消し線
- リンク
- テーブル

## 使うときに注意

基本共通な記法だけどサービスによって使えない記法があったりする。改行の入っていなかったりや半角スペース（インデント）によって反映されないミスがある。
VsCode で自動成形すると間違えがない。ただの自分としてはただのメモとして残したい時に成形されると改行が多い気がして見難いので自動成形されないようにしている。
リッチテキストにしたい時だけ手動で成型する。
GCPのアラート通知チャネルPagerDutyをTerraform管理にする

# 概要
GCPではアラートの通知チャネルとしてメールやSlack、PagerDutyなどを指定できます。
サポートされている通知チャネル一覧は以下のAPIにて確認できます。
[Method: projects.notificationChannelDescriptors.list](https://cloud.google.com/monitoring/api/ref_v3/rest/v3/projects.notificationChannelDescriptors/list?apix_params=%7B%22name%22%3A%22projects%2F994445233963%22%7D)

APIを確認すると、2023/12/3時点でPagerDutyはベータ版ではあるものの通知チャネルとして利用できます。しかし、Terraformの通知チャネルリソースのドキュメント（[google_monitoring_notification_channel](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/monitoring_notification_channel)）にはPagerDutyのサンプルが載っていません。
この記事ではPagerDutyをTerraform管理にする手順を紹介します。

# 前提
[Terraform](https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli)と[Berglas](https://github.com/GoogleCloudPlatform/berglas)コマンドが利用できる。
- PagerDutyの秘密情報はSecret Managerに保存しBerglas経由でTerraformに渡します

# 手順
**1. PagerDutyのサービスを作成する**
作成時にIntegrationsとして`Events API V2`を選択。サービス作成後にIntegration Key控えておきます。
![スクリーンショット 2023-12-03 22.29.15.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133979/39ba6dbf-987f-90b8-0efe-fc552c393668.jpeg)

**2. Secret ManagerにPagerDutyの秘密情報を保存**
Secret Managerでシークレットを作成し、1.で控えたKeyを`シークレットの値`として保存します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133979/c194328d-22ba-0771-c3f6-b3e40e58fa04.png)

**3.　Terraform定義を作成**
秘密情報が保存されているSecretを変数として指定し、通知先チャネルを作成します。ディレクトリやファイル名は任意のもので大丈夫です。
※providerやbackendの設定方法についての説明は省略します。

```terraform/.env.berglas
export TF_VAR_pagerduty_service_key=sm://[project-name]/pagerduty_service_key
```

```tf:terraform/gcp/variable.tf
variable "pagerduty_service_key" {
  description = "PagerDuty Service Key"
}
```

```tf:terraform/gcp/alert.tf
resource "google_monitoring_notification_channel" "pagerduty" {
  display_name = "PagerDuty" # 任意
  type         = "pagerduty"
  sensitive_labels {
    service_key = var.pagerduty_service_key
  }
}
```

**4.　通知先チャネルを作成する**
`terraform apply`コマンドを実行し、通知先チャネルのリソースを作成します。
```bash
berglas exec -- terraform apply
```

**5. 任意のアラートポリシーに通知先チャネルPagerDutyを紐付ける**
作成した通知先チャネルPagerDutyを任意のアラートポリシーの`notification_channels`に設定します。
```tf:terraform/gcp/alert.tf
resource "google_monitoring_notification_channel" "pagerduty" {
  display_name = "PagerDuty" # 任意
  type         = "pagerduty"
  sensitive_labels {
    service_key = var.pagerduty_service_key
  }
}

resource "google_monitoring_alert_policy" "hoge" {
  display_name = "hoge"

  conditions {
    ...
  }
  notification_channels = [google_monitoring_notification_channel.pagerduty] # <- PagerDutyを通知先として指定
}
 ```

**6.アラートポリシーを作成する**
`terraform apply`コマンドを実行し、通知先チャネルのリソースを作成します。
```bash
berglas exec -- terraform apply
```
AWS ALB からEC2インスタンスが切り離されるのを待つ

## ALBから自身のEC2インスタンスが切り離されるのを待つ

すごく限定的な用途ですが、自身のEC2インスタンスが、ALB（Application Load Balancer）から切り離されるのを待つシェルスクリプトを作成しました。


### やりたかったこと（背景）

Webアプリケーションをデプロイ後に起動するが、しばらくの間、諸々の事情でリクエストを受け付けてほしくない。
（遭遇したケースの一例は、Webアプリケーションの起動直後にリクエストを多数受け付けると、データベースコネクションプールの処理が追い付かず、コネクション数が跳ね上がるという現象だった。）

AWS CLI で ALB（ターゲットグループ）から一時的に削除する方が手っ取り早いが、その権限が付与されていない。

なので、ALBのヘルスチェックでNGになったことによって、切り離されたことを確認してから、Webアプリケーションを起動したい。
（切り離されてから自動で復帰するまでの間に、対処できるので）

AWSマネジメントコンソールで、ALBのヘルス状態を確認するのは面倒。


### AWS CLI を使って、指定のEC2インスタンスのALB上のヘルス状況を確認する

`aws elbv2 describe-target-health` を使って、確認する。

権限を付与されているなら、下記でターゲットグループから一旦削除して再登録した方が手っ取り早い。
`aws elbv2 deregister-targets`
`aws elbv2 register-targets`
が、今回は、上記の通り、事情があり、待つことに。

ヘルス状態を確認して、Unhealthy になるまで待つシェルスクリプトを作成してみる。

#### 動作確認環境

```
$ uname -r
4.14.305-227.531.amzn2.x86_64
$ bash --version
GNU bash, version 4.2.46(2)-release (x86_64-koji-linux-gnu)
$ aws --version
aws-cli/1.18.147 Python/2.7.18 Linux/4.14.305-227.531.amzn2.x86_64 botocore/1.18.6
```
#### 免責事項

* スクリプトの実行は自己責任でお願いします。本スクリプトを実行することにより生じるいかなる問題に関しましても、筆者は一切責任を負いません。

```shell
#!/bin/bash

# ALBから自身のEC2インスタンスが切り離されるのを待つ
#
# ヘルスチェック設定 例
#   非正常のしきい値: 2ヘルスチェックの連続的な失敗
#   タイムアウト: 5秒
#   間隔: 30秒

# 非正常のヘルスチェック状態を確認する回数
MAX_CHECK_COUNT=7
# 非正常のヘルスチェック状態を確認する間のスリープ秒数
SLEEP_SECONDS=10

# ALB ターゲットグループ ARN
ALB_TG_ARN=${1:-"ターゲットグループのARN"}


# 指定のインスタンスのALBのヘルス状況を返す
function check_alb_health() {
    local TARGET_GROUP_ARN=$1
    local TARGET_ID=$2
    local STATE=$(aws elbv2 describe-target-health --target-group-arn "${TARGET_GROUP_ARN}" --output text \
        --query "TargetHealthDescriptions[?Target.Id == '${TARGET_ID}'].TargetHealth.State | [0]")
    echo "${STATE}"
}


# ALB から切り離されるまで待つ（関数の呼出し元でリターンコードで成否判定分岐する）
function wait_until_unhealthy() {

    # 自身のEC2インスタンスのIDをインスタンスメタデータから取得する (※1)
    INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)

    # スリープしながら繰り返しALBターゲットグループのヘルスチェック状態を確認する
    for (( i = 0; i < ${MAX_CHECK_COUNT}; i++ )); do
        local STATE=$(check_alb_health "${ALB_TG_ARN}" "${INSTANCE_ID}")
        echo -n "${STATE}"
        if [[ "${STATE}" != "healthy" ]]; then
            echo "[OK]"
            return 0
        fi
        echo "ALBのヘルスチェック状態を確認しています ... "
        sleep ${SLEEP_SECONDS}
    done
    echo "ALBから切り離されませんでした。" >&2
    return 1
}

# （ここで、Webアプリケーションのデプロイ作業などが実行される。）

# ALB から切り離されるまで待つ
wait_until_unhealthy || exit 1

# （ここで、Webアプリケーションを起動する。）

```

※1 のEC2インスタンスIDの取得については、下記の公式の情報を参考に。

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html

### あとがき

cron などで定期的に実行して、ALBのターゲットグループからヘルス状態を確認し、SlackのWebhookなどに、curl などでリクエストを送れば、簡単に異常通知を送ることができそうですね。
CloudWatchアラーム と Amazon SNS と AWS Chatbot とか組み合わせれば、詳細な情報を含めて通知が可能ですが、単に通知を送るだけなら、そんな方法もありかなと。
AIは銀の弾丸ではない（NJSSのラベリング機能改善のためにAIを入れたけど、まあ色々あったよというお話）

ここ数年でAIの技術は一気に進歩しましたよね。
特にGPTが台頭してきたこの1年で非エンジニアの方もAIという技術に
様々な感情を抱いたのではないかなと思います。

さて、そんなAIの技術が進歩する中、今年9月にNJSSの業種システムのリニューアルを実施しました。
NJSSとしては初めてAI技術をシステムに組み込むリリースとなりました。
初めてのAIリリースに至るまでに色々な壁があったので
自分の振り返りも兼ねて書いてみようかと思います。


:::note info
この記事では技術にはまったく触れません。
技術より少しだけ上流の対ステークホルダーやその時に考えてた事を中心に書いていきます。
:::


## 導入前の状況はどうだったのか
端的に言うと **非常に検索ノイズが多い** 状況でした。
当時の設計思想として「モレが少ないこと（≒ Recall）」を優先していたのですが、
反面、「ブレが少ないこと（≒ Precision）」は二の次となっておりました。

その結果、業種を用いた検索はノイズを多く含んだ状態となっており、
ユーザの検索体験としては課題のある状態だったと言えます。

NJSSの中で「AIを使って何か出来ないか？」を検討している段階だったのですが、
上記の課題に対して「AIで精度改善が出来るのでは」という仮説をたて、
取り組みを始めることとなりました。

## AIは銀の弾丸に見られがち
昨今のAIの発展は著しく「AIは優秀で何でもできる」ように見えます。
確かに「それっぽく動く」ことは多いのですが「耐えうる品質で動くか」となると実は話は全然別です。

初めてGPTを触った時は返答の多様さに感動した一方で、たまに返答間違えてましたよね？
端的に言うとコレがビジネスの議論でも起こります笑

### みんなAIには期待しちゃうんだよね
良くも悪くもAIの領域は期待値が高くなりやすく、
ステークホルダーと会話する際に一番ギャップが出やすいポイントです。
そして多少の粗が出るだけで「（優秀なはずなのに）なんでこれ間違えるの？」と指摘を受けるわけです。
（※そしてAIは基本的にブラックボックス化しちゃうので確証を持った証明は基本的に難しいです）

自分もそのギャップとやりとりに非常に苦しみました。



## 不毛なやり取りを防ぐ為にちゃんと動くことを数値で証明する
結局のところ、数値で証明するのが一番分かりやすいです。
今回の開発においては「現状のシステムを代替する」という形だったので
「現行数値」をRecall, Precisionなどの指標で評価した上で「目標数値」を設定しました。
「なに、当たり前のことを言っているんだ」なのですが、
今回のプロジェクトを進めるにあたって非常に助けられることとなるのです。

### 「現行数値」と「目標数値」の2つの基準値が守ってくれる
どんなに優秀なAIでも100%正しく予測が出来るわけではありません。
また、この手の予測システムの場合、レコード単位で見てみると
「現行では正解していたのに新版では間違える」みたいなケースもあります。

ですが「現行数値」と「目標数値」をちゃんと設定していたことで
「全体で見た時は目標値は達成しているし、現行より正しく推論できている」と証明ができ、
非常に細かい課題の解決のために進捗が遅延してしまうことを防止することが出来ます。
（議論しないことを推奨している訳ではなく、今解決すべき課題かどうかの判断材料になるという観点です。）

今回の業種システムの改善の時もレコード単位で見ると劣化するケースはあったのですが、
件数としては少数派であったこともありリリース後の保守で継続改善していく流れで
今回のリリースに踏み切っております。
その点でもちゃんと数値を可視化しておいてよかったなあと感じております。

## 結局、AIは課題解決の為の手段の1つでしかない
実は今回のリリースはAIに全てを委ねる設計にはしておらず、
一部は地道なロジックベースでの実装が介在しております。
なぜならば、AIの判定だけでは精度が頭打ちになってしまった為です。
おそらくAIだけに固執していたらリリースは未達に終わっていたことでしょう。

### 決まった流れはロジックベースがなんだかんだ最強である
決まりきったルールがある場合は下手にAIを入れてブラックボックス化させるより
ロジックベースで設定した方が確実に動く分、精度が上がりやすいです。
（もちろん、作り込みが発生するので手間と工数が掛かるわけですが。。。）

**AIはあくまでも「課題解決の手段の1つ」でしかないのです。**

## リリースをしてみて
まずシステムの定量的成果としては前システム比で1.7倍の改善に成功しました。
当初目標は1.4倍を目標としていた為、数値的には大成功です。

またリリース後、プレスリリースを発信したのですが、
会社の株価が少し上がったので市場からのAIの関心はまだあるんだなあと思った次第です。

実際のユーザの使用率については別プロジェクトの兼ね合いもあり、
正確な計測は出来ていないのですがユーザの使用感のヒアリングも出来たらなあと思ってます。


## まとめ
既存システムの改善の為にAIを取り入れようと考えている方も多いことかと思いますが、
もしも自分の経験が何かしらのヒントになりましたら幸いです。

今回は技術よりは少し上流の部分で記事を書いたのですが、
技術の部分ではGPTの推論が安定しないとか推論時間が遅いとか
こちらも色々ありましたw
もしかしたら続く、かもしれない。