OmniAICreator/Qiita-1.07M huggingface dataset:
attributeに関数を指定できなかったが、別の方法を考えてみた

こちらの内容の課題

```
　fx = fn x -> rem(x, 2) == 0 end
```

の部分がパラメータ化できてない

https://qiita.com/t-yamanashi/items/eb34825d7b05b92e9288#%E8%AA%B2%E9%A1%8C

現時点の結論だめでした…　

あえて、失敗例を載せます


```Elixir
defmodule HogeTest do
  use ExUnit.Case
  doctest Hoge

  params = [
    [true, 1, "s"],
    [true, nil, true],
    [true, 1, false]
  ]

  for param <- params do
    @param param
    test "Hoge.all?/1 param #{inspect(@param)}" do
      assert Hoge.all?(@param) == Enum.all?(@param)
    end
  end

  params = [
    [[2, 4, 6], fn x -> rem(x, 2) == 0 end],
    [[2, 4, 5], fn x -> rem(x, 2) == 0 end]
  ]

  for [param, fx] <- params do

    @param param
    @fx fx
    test "Hoge.all?/2 param #{inspect(@param)}" do
      assert Hoge.all?(@param, @fx) == Enum.all?(@param, @fx)
    end
  end

end
```


```Elixir
** (ArgumentError) cannot inject attribute @fx into function/macro because cannot escape #Function<2.123583373 in file:test/hoge_test.exs>. The supported values are: lists, tuples, maps, atoms, numbers, bitstrings, PIDs and remote functions in the format &Mod.fun/arity
    (elixir 1.13.4) lib/kernel.ex:3509: Kernel.do_at/5
    (elixir 1.13.4) expanding macro: Kernel.@/1
    test/hoge_test.exs:28: HogeTest."test Hoge.all?/2 param [2, 4, 6]"/1
    (ex_unit 1.13.4) expanding macro: ExUnit.Assertions.assert/1
    test/hoge_test.exs:28: HogeTest."test Hoge.all?/2 param [2, 4, 6]"/1
```

エラーメッセージの通り、だめっぽい
だが…

# 無理やり動かす方法を考えた

```Elixir
defmodule HogeTest do
  use ExUnit.Case
  doctest Hoge

  params = [
    [true, 1, "s"],
    [true, nil, true],
    [true, 1, false]
  ]

  for param <- params do
    @param param
    test "Hoge.all?/1 param #{inspect(@param)}" do
      assert Hoge.all?(@param) == Enum.all?(@param)
    end
  end

  params = [
    [[2, 4, 6], "fn x -> rem(x, 2) == 0 end"],
    [[2, 4, 5], "fn x -> rem(x, 2) == 0 end"]
  ]

  for param <- params do
    @param param
    test "Hoge.all?/2 param #{inspect(@param)}" do
      [list, fx_string] = @param
      fx = Code.eval_string(fx_string) |> elem(0)
      assert Hoge.all?(list, fx) == Enum.all?(list, fx)
    end
  end
end
```

つまり、文字列として渡す
その後にCode.eval_stringで文字列から関数を作成する
LangChain + GPT-NEOX-Japanese-2.7b で日本語 LLM やりとり整備するメモ

## 背景

何やら流行りの LangChain でいい感じに日本語扱いたい!

https://note.com/npaka/n/n61ad59380a43

https://qiita.com/wwwcojp/items/c7f43c5f964b8db8a890

とりあえずローカルで動かしたいので, 日本語は gpt-neox-japanese-2.7b 使います.

https://qiita.com/syoyo/items/69b1be40159d08a69b6d

LangChain 自体はなんかいろいろつなげるための wrapper みたいなものです.
(そのうち huggingface もなんか langchain っぽいの出してきそうですネ)

## LLM module

https://langchain.readthedocs.io/en/latest/reference/modules/llms.html

huggingface pipeline 使います.

## gpt-neox-japanese-2.7b


デフォルトだと CPU 実行になってしまうので(CPU でも動くが数分くらいかかる), GPU 処理, また fp16 を使います!

https://qiita.com/syoyo/items/69b1be40159d08a69b6d

また, langchain の(?) デフォルトの max_new_tokens は 20 tokens で, 長い input 与える(下のずんだもんは 220 tokens くらい)と unexpected behavor になるので `max_new_tokens` を大き目にとっておきます.

とりあえず動かしてみます.

```python
import torch

from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain
from langchain.agents import ZeroShotAgent, Tool, AgentExecutor, load_tools

from langchain.llms.huggingface_pipeline import HuggingFacePipeline
from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline

device_num = -1 # CPU
if torch.cuda.is_available():
  device_num = 0 # cuda:0

model_id = "abeja/gpt-neox-japanese-2.7b"
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(model_id)
pipe = pipeline(
    "text-generation", model=model, tokenizer=tokenizer,
　　max_new_tokens=512, device=device_num, torch_dtype=torch.float16
)
hf = HuggingFacePipeline(pipeline=pipe)

print(hf("カラフルな靴下を作る会社の社名にふさわしいのは？"))
```

```
」という質問に対して、「靴下屋」と答えた人が多かったそうです。
```

もうちょっとひねりほしいネ...

https://note.com/npaka/n/n4651ee6d3c51

を参考にして PromptTemplate 使ってみます!

```
prompt_temp = """ずんだもんは東北に住む活発でかわいい女の子です。

    あなた「きみの名前は？」
    ずんだもん「ボクの名前はずんだもんなのだ。」

    あなた「今日の天気は？」
    ずんだもん「ボクは今日の天気は晴れだと思うのだ」

    あなた「今日は何時に起きたの？」
    ずんだもん「ボクは7時に起きたのだ」

    あなた「年齢は？」
    ずんだもん「ボクの年齢は秘密なのだ」

    あなた「朝ごはんは何食べたい？」
    ずんだもん「ボクはおにぎり食べたいのだ」

    あなた「{time}ごはんは何食べたい？」
    ずんだもん「"""

prompt = PromptTemplate(
    input_variables=["time"],
    template=prompt_temp,
)

chain = LLMChain(llm=hf, prompt=prompt)

print(chain.run("昼"))
print(chain.run("夜"))
```

```
Setting `pad_token_id` to `eos_token_id`:31999 for open-end generation.
ボクは何食べたい？」
Setting `pad_token_id` to `eos_token_id`:31999 for open-end generation.
ボクは何食べたい？」
```

昼も夜も, 質問に質問で返されてしまいました... :cry:

pipeline で `do_sample=True, top_p=0.95, top_k=50` あたり追加や, `temperature` 調整すると多少よい結果がかえってきます.

## とりあえずのまとめ

とりあえずはローカルでいろいろスクリプト組んだりして試して, その後必要であれば OpenAI(ChatGPT) や you.com あたりにつなぐとかがいいかも.

また, GPT-J や, https://huggingface.co/abeja/gpt2-large-japanese を使う手もありそうです.
(後者は protobuf 必要になりつらたにえん :cry: であるが! デフォルトのパラメータでそこそこいいかんじの応答してくれる感があります)

## TODO

* [ ] プロンプトエンジニアリングを頑張る
* [ ] 検索エンジンとつなぐ. とりあえずは duckduckgo https://github.com/deedy5/duckduckgo_search がいいでしょうか.
2023/1/2主にITとかセキュリティの記事

バハマ当局、ＦＴＸ子会社の資産35億ドル相当を押収－消失リスク懸念(12/30)
https://www.bloomberg.co.jp/news/articles/2022-12-30/RNP5KIT1UM0W01?srnd=cojp-v2

バハマ規制当局、FTX子会社から押収した35億ドルを保有(12/31)
https://www.coindeskjapan.com/170087/

バハマ当局、FTX資産4600億円押収　「一時的に保護」(12/31)
https://www.nikkei.com/article/DGXZQOGN303UO0Q2A231C2000000/

年末年始は「ミライ散歩」でメタバースを体験！空間で歩いたり話しかけることも可能に(12/30)
https://straightpress.jp/20221230/817593

「Citrix ADC」と「Citrix Gateway」、パッチ適用進まず - 日本も低い適用率(12/31)
https://news.mynavi.jp/techplus/article/20221231-2550340/

Microsoft Edgeで使える広告ブロッカー3選、不要な広告を非表示に(12/31)
https://news.mynavi.jp/techplus/article/20221231-2551057/

新国家安全保障戦略と新安保３文書では、台湾有事の本命「ハイブリッド戦争」を「察知すらできない」ワケ(12/30)
https://news.yahoo.co.jp/articles/071d02f16cb80403c006be45aeb89e6dc22af730?source=rss

【台湾有事】来る「ハイブリッド戦争」に完敗しないために「日本がただちに準備しなければいけないこと」(12/31)
https://news.yahoo.co.jp/articles/087005073144b63bab1abd8f95a38bc7e88b7f71?source=rss
DockerDesktop(windows)が起動できない

# 起動できない
しばらくWindowsはSleepで使用していたのですが、再起動したところ、DockerDesktopが起動できなくなりました。
DodkerDesktop起動してもエラーとなり、"WSL 2 integration with distro Ubuntu 20.04 unexpectedly stopped with exit code 1"となります。
wslを再起動しても同じエラーが繰り返されるだけで、結局DockerDesktopは起動エラーとなりました。

# ググってみた
表示されたエラーから検索すると、対応方法がいろいろと出てきます。
それを見ながらいろいろと試行錯誤。以下のようなことをやってみました。
- DockerDesktopの再インストール
- wslのlinuxの再インストール
- linuxのバージョンを替えてみる
- windowsの再起動

たまに、これでうまく起動できることもありましたが、windowsを再起動すると、同じようにDockerDesktopの起動に失敗してしまいました。

# 見つけた！
困り果てていたところで、やっと対応策を見つけました。[Githubのdocker/for-winでのissuです](https://github.com/docker/for-win/issues/6640#issuecomment-687304908)
Hyper-vをオフにするという方法！
まじか～と思いましたが、それでうまく起動できるようになりました。

そういえば、2か月くらい前にJavaの開発でHyper-vで仮想環境作ってCentOSいれていろいろといじっていました。そちらはIntellij Idea使っていました。
DockerはVisual StudioでC#開発で使用していたのですが、Windowsを再起動せずに使用していたので気が付かなったようでした。

解決してしまえばあっという間ですが、もし同じような現象で困っている方がいればと思い、簡単ですが記事としてアップしました。
UbuntuのvimrcをMacで使おうとしたときのエラー

`.vimrc`を書いた時のメモ。Ubuntuでは正常に動いていたものをM1 Macbook Air(2020)に持ってきたところ、以下のようなエラーが出た。

```
[denops] Denops requires Vim 8.2.3452 or Neovim 0.6.0. See ":h g:denops_disable_version_check" to disable this check.
Error detected while processing /Users/hogehoge/.vim/plugged/indentLine/after/plugin/indentLine.vim:
line    9:
conceal is invalid. To use the plugin, please enable the conceal
Press ENTER or type command to continue
```
Enterを押すと普通に`vim`が起動して設定も反映されていたが、やはりエラーが出るのは気になる。
Vimのバージョンは`8.2.3489`で大丈夫そうであったので色々調べたところ、エラーメッセージにもあるプラグイン`Yggdroot/indentLine`の`Readme.md`に以下のような記述があった。
> MacOS users: The copy of Vim provided in MacOS may not have the conceal feature enabled (check with echo has('conceal')), which will prevent the plugin from loading. To fix this, we recommend using the homebrew version of Vim.

https://github.com/Yggdroot/indentLine#Requirements

どうやらMacのデフォルトのVimだと`conceal`が無いのでプラグインが読み込めないとのこと。そのため、homebrewでインストールしたvimを使えば良いらしい。よって、インストールする。
```
brew install vim
```
その後、パスを更新するためzshの設定を再読込する。
```
exec zsh
```
これでVim起動時にエラーは出なくなった。ちなみにバージョンは`9.0.1100`だった。
Laravelでテスト用DBを作る


## そもそもテストって？
Laravelのドキュメントには以下のように書かれています。
>機能テストでは、複数のオブジェクトが相互作用する方法や、JSONエンドポイントへの完全なHTTPリクエストなど、コードの広い部分をテストします。一般的に、ほとんどのテストは機能テストである必要があります。これらのタイプのテストは、システム全体が意図したとおりに機能しているという信頼性を一番提供します。
>
少し分かりづらいですが、ザックリ言うとテストは<strong>「自分が書いたコードの通りにHTTPレスポンスやDBの処理などが動いているかどうか確かめるもの」</strong>です。テストを実行するツールとしてLaravelではPHPUnitがよく用いられています。PHPUnitの内容説明は本投稿の趣旨と異なるため、また別で記事を書こうと思います。

https://phpunit.readthedocs.io/ja/latest/

## テスト用DBを別で作る理由
理由は単純で開発用DBのデータが削除されてしまうのを防ぐためです。

テストは

1\. DBを`RefreshDatabase`で全テーブルを削除してから作り直す
2\. それぞれのテストケース内で`Factory`などを用いてテスト用のダミーデータを作成しテストを実行

ような流れで実行されるケースが多いです。なのでテストを実行するたびに上の手順1で毎回データを消していることになります。
毎回データを作ったり、`php artisan migrate:fresh --seed`などのコマンドを叩いてダミーデータを入れるのもかなりしんどいので、それならもうテスト用のDBを作ろうとなるわけです。

## 環境構築
今回はDockerでの環境構築の工程は省略します。
DockerでLaravel環境構築を行ったリポジトリを用意しているので、こちらをクローンして確認してもらえればと思います。

https://github.com/Rihitonnnu/Laravel_test_db

### バージョン
Laravel 9.45.1
PHP 8.1.9
MySQL 8.0.30

### ディレクトリ構造
```
docker/
　┣━ apache/
　┣━ db/
　│　┣━ data/
　│　┣━ sql/  
　┗━php/
```

## 早速やってみる
早速テスト用のDBを作ります。作り方は色々ありdbコンテナの中で手動でデータベースを作ることもできますがめんどいので、今回はテスト用のDBを作るスクリプトを書く形式で進めます。

まずはコンテナ内の`./docker-entrypoint-initdb.d`にスクリプトを書いたファイルを配置します。

```
docker/
　┣━ apache/
　┣━ db/
　│　┣━ data/
　│　┣━ sql/  
  │　  ┣━ test_database.sh # 配置
　┗━php/
```
上の場所に新しく`test_database.sh`ファイルを作成し、以下の内容を記述します。
```test_database.sh
echo "CREATE DATABASE IF NOT EXISTS \`test\` ;" | "${mysql[@]}"
echo "GRANT ALL ON \`test\`.* TO '"$MYSQL_USER"'@'%' ;" | "${mysql[@]}"
echo 'FLUSH PRIVILEGES ;' | "${mysql[@]}"
```

続いて`.env.testing`を`.env`と同じ階層に作成します。DBの内容は`DB_DATABASE`以外は`.env`と同じになります。
```.env.testing
APP_ENV=testing
APP_KEY=

DB_CONNECTION=mysql
DB_HOST=
DB_PORT=
DB_DATABASE=テスト用DBの名前
DB_USERNAME=user
DB_PASSWORD=password
```
先程書いた`.env.testing`の環境に対してAPP_KEYを作成します。
```terminal
php artisan key:generate --env=testing
```
※設定されない場合は以下のコマンドでキャッシュクリアをして再度試してみて下さい。
```terminal
php artisan config:clear
```

最後にマイグレーションを実行します。
```terminal
php artisan migrate --env=testing
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2435396/1b5a43e1-6e93-42b1-a3a9-a348dd87ef1b.png)

マイグレーションできました！
これでテスト用のDBの作成は完了です！

## おわりに
今回はLaravelでテスト用DBの作成を行いました。

次回以降の記事でLaravelのテストの書き方を投稿しようと思います。
初めての投稿だったのですが、文章や内容の構成が冗長になったり、いい表現が見つからなかったりとアウトプットの難しさを痛感しました。定期的に投稿してトレーニングしていこうと思います。

Laravel歴5ヶ月程の初心者なので、間違っている部分があればご指摘頂けますと幸いです🙇‍♂
ITホラー短編：売れないDXとDXレポート2.2

## プロローグ

営業A「弊社DX製品、全然問い合わせがないっすね。」
営業B「経産省のレポートでは、2025年までにDXしないと **『毎年最大１２兆円の経済損失が生じる可能性』** があるって言ってるんだからみんなDXするだろ？」
営業A「そっすよねぇ…」

営業A
(…まてよ？…あのレポートが出たのって平成30年だったよな…今はもう令和になってずいぶん経つから新しいレポートが出てるんじゃないのか？)

「これは調査する必要がありそうだな。」
そうつぶやくと営業Aはパソコンに向かってググりはじめた。


## デジタル競争の敗者とジレンマ

営業A「クソ…悪い予感が的中したか」
営業Aは経産省のレポートを眺めながらそうつぶやいた。

![デジタル競争の敗者.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136165/da3a36b8-0d22-84f4-2c93-f6a89bd391ff.png)

出典：[経済産業省　D Xレポート２.１（DX レポート 2 追補版）](https://www.meti.go.jp/press/2021/08/20210831005/20210831005-2.pdf)

少し見ない間に『デジタル競争の敗者』にされているじゃあないか。

しかも…

出典：[経済産業省　D Xレポート２.１（DX レポート 2 追補版）](https://www.meti.go.jp/press/2021/08/20210831005/20210831005-2.pdf)

> 1. 危機感のジレンマ
> 目先の業績が好調のため変革に対する危機感がない。投資体力があるうちに変革を進めていくことが重要であるが、危機感が高まったときはすでに業績が不調であり、変革に必要な投資体力を失っている。
> 2. 人材育成のジレンマ
> 技術が陳腐化するスピードが速く、時間をかけて学んだとしても、習得したときには
> 古い技術となっている。即座に新技術を獲得できる人材は引き抜かれてしまう。
> 3. ビジネスのジレンマ（ベンダー企業）
> 受託型ビジネスを現業とするベンダー企業が、ユーザー企業のデジタル変革を伴走支援する企業へと変革しようとすると、内製化への移行により受託型ビジネスと比べて売上規模が縮小する。また、ベンダー企業がユーザー企業をデジタル企業へ移行する支援を行うことにより、最終的には自分たちが不要になってしまう。

「製品に問題があるのではなく、企業のあり方自体に問題があるという話だろうか…？」


## DXフレームワーク

「１営業のオレには、企業のあり方は **ヘビィ** 過ぎる課題だぜ…」

とりあえず売り方が載ってないか最後まで目を通してみたが、ヘビィな課題に対する **『変革に向けた施策』** があるだけだった。営業のオレにはピンと来ない話ばかりであったが、文中の **『DXフレームワーク』** はしゃべれた方がハッタリがきいてよさそうだと思った。

![DXフレームワーク.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136165/2466e959-eea1-445a-536e-33d0bfc473cd.png)

出典：[経済産業省　D Xレポート２.１（DX レポート 2 追補版）](https://www.meti.go.jp/press/2021/08/20210831005/20210831005-2.pdf)


## D X レポート ２.2

DXレポート２.１から「DX」は気軽に営業ワードで使えない程度の闇の深さを感じたが、製品の売り方のヒントが欲しい。他にすがる物もないので現時点での最新版と思われる[D X レポート ２.2](https://www.meti.go.jp/shingikai/mono_info_service/covid-19_dgc/pdf/002_05_00.pdf)も読むことにした。


D X レポート ２.2 では、ありがたいことに最初から具体的なアクションが明示されていた。

出典：[経済産業省　D X レポート ２.2（概要）](https://www.meti.go.jp/shingikai/mono_info_service/covid-19_dgc/pdf/002_05_00.pdf)

> 「デジタル産業への変革に向けた具体的な方向性やアクションを提示」
> • 具体的には、企業に向けて以下3点のアクションを提示
> ✓ デジタルを、省力化・効率化ではなく、収益向上にこそ活用すべきであること
> ✓ DX推進にあたって、経営者はビジョンや戦略だけではなく、「行動指針」を示すこと
> ✓ 個社単独ではDXは困難であるため、経営者自らの「価値観」を外部へ発信し、同じ価値観をもつ同志を集めて、互いに変革を推進する新たな関係を構築すること
> • 上述を実現するための仕掛けとして、「デジタル産業宣言」を策定
> • さらに、宣言の実効性を高めるうえで、デジタルガバナンス・コードへの組み込みを検討

「…？~~人類~~一企業には早すぎたオーバーテクノロジーだというのか…？」
「『省力化・効率化ではなく』という文言は…『RPAでDXっす！』的な営業文句を封じ込めに来ているのか…？」


## エピローグ

「モノを売るのにバズワード的に便利だと思ってたDXだが、経産省の思惑は全然別のところにあったんだな。」

自社の製品を売るヒントは見当たらなかったが大きな気づきはあった。

省力化・効率化を達成するだけの製品をユーザー企業に導入させるのは難しいということだ。
省力化・効率化を達成できたとして、余った「労働力」を「利益」に転換する方法を合わせて提示できないのであれば、どんなに使いやすい製品だったとしても実際に利用するユーザーには自分の墓穴を掘れとお願いするようなものだろう。

そう考えると、ユーザー企業やユーザーに何らかの利益をもたらす製品を提案できねばならないのは理解できる。
しかし **『デジタル競争の敗者』** を脱するというのは **『ITオリンピックで勝利』** するといった類の内容にも見える。もう少し一般人にも行動に移せる分かりやすい目標を設定してくれたら不足するであろうIT人材43万人も集められるのかもしれない。

「2025年まであと2年か…」

そうつぶやいて営業Aはパソコンを閉じた。


## おまけ1

営業A短編シリーズ

https://qiita.com/kaku3/items/03aae7b9e3c70c55f513


## おまけ2

2025年にIT人材が43万人不足するらしいので、学習用の資料をgitで**無料**公開してます(不定期更新)。
よろしければどうぞ。

[エンジニアのためのお仕事問題集](https://github.com/kaku3/workbooks)
JenkinsからSlackへ通知する挙動がおかしい

# JenkinsでCI/CDからSlack通知への挙動不具合
:::note warn
あくまでメモです。（誰かのご参考になれば）
JenkinsのSlack用プラグインを使いなさい。というご意見はごもっともですが、
諸事情から、shellから叩く方向で実施しています。
:::

## jenkinsの使い方
CI/CDツールにてバージョンが古いJenkinsを利用しておりました。
※ビルド・デプロイを実施
Jenkinのパイプライン処理(shell)の内部で、成功・失敗をSlackに[Slack-API postMessage](https://api.slack.com/methods/chat.postMessage)を利用し通知しています。

## 挙動不具合とは
実行されていない過去のビルド履歴がSlackに通知される。

###### 調査
Jenkinsサーバーについては以下を調査しました。

ログ：不具合の挙動はログに記録されておらず。
プラグイン：既にインストールされているプラグインのアップデートは必要であったが、相関関係は認められず。
ジョブ履歴：ジョブ履歴のログローテートが未設定。肥大化していた。


###### ~~対応~~
~~各ジョブの履歴にローテーション設定。
ログの肥大化を防いだところ、挙動不具合(Slackの過去分送信)は発生しなくなりました。~~

###### ~~考察~~
~~ジョブの履歴のログローテーションを設定していないと、ビルド番号が大きくなるにつれ、
不具合などが発生する可能性が高い。
（=ジョブ履歴のログローテーションをしていないと、不具合の原因になる。）~~

## 対応
**<font color="red">素直に、Jenkinsのバージョンアップを推奨します。</font>**
経緯としては、取消し線部分を対応しましたが、しばらくすると同じ事象が再発。
またJenkinsのJIRAチケットを見てみると、
・ログローテーションのバグ
・スケジュール設定時のバグ
など複数のチケットが報告されていることが確認できました。

## 結論
**<font color="red">可能であれば、素直にJenkinsのバージョンを最新版にする。</font>**
がベストな選択なだと思います。

ここは推測ですが、Jenkins自体の不具合とプラグインの不具合が、本事象の原因かと考えれます。
ただし一つ一つ調べていくことは、非常に複雑で、時間がかかることから私は諦めました。笑
もしこのあたり同じ症状があった方いらっしゃいましたら、コメントなどで教えて頂けると助かります。

→ちなみに最新版にしたところ、特にトラブルは発生しておらず
エラーログも格段に減らすことができました。(半年ほど経っても特に問題　は発生していません。)

##### 参考ページ
https://saitodev.co/article/Jenkins%E3%81%AE%E5%8B%95%E4%BD%9C%E3%81%8C%E9%81%85%E3%81%8F%E3%81%AA%E3%81%A3%E3%81%9F%E6%99%82%E3%81%AE%E5%AF%BE%E5%87%A6/
DIコンテナを使ってWindows Formアプリを作ったときにやったこと、やりたかったこと

# 概要

ここ一年ほど、シリアル通信を使ったWindows Formアプリを業務で作成していた。
その際に「こうすればよかったな」が集まったので業務の棚卸しを兼ねて書いてみることにする。

## 前提

### アプリ概要

大雑把に言うと、スーパーにあるような自動レジみたいなもの。
WindowsPCに様々な機械が接続されていて、ユーザの入力や払ったお金に応じてサービスを行う機械のUIを作成した。
なお、各機械はシリアル通信でやり取りしており、リアルタイムで監視をする必要があった。

### そもそもなんでDIコンテナ？

このUIを作るにあたり、次の問題があったから開発の柔軟性を持たせるためにDIコンテナを使い、
画面の仕様変更への耐性を高めることにした。

- 仕様や要件を把握して音頭をとる人が居ないため、手直しが多くなることが予想される
- 最終的に現行の機械（これも仕様不明）にもアプリを導入する計画があるため、UIを分離しておくと嬉しい

## DIコンテナ導入でやったこと

### 異なる画面で一つしかないインスタンスを無理なく使い回す

一つのシリアルポートにUIの都合とは関係なく送受信で制御を行わなければならないため、
デバイスの大半は別スレッド上でメッセージループを組んで制御していた。
そのため単一の制御用のインスタンスを多数の画面などで使い回す必要があり、
そのクラスへの紐づけ作業などの手間をDIコンテナに押し付けて楽ができた。

### UI側を交換可能にする

実際に実装していたときに思いがけず助かった点。
特にシリアル通信はいろいろな理由で接続が切れる。断線、ノイズ、設定ミス、何でもありだ。
こんなとき、「実際に本番コードで使われているプログラム」を使ったテストツールがあれば
最低限の労力で各デバイスの生存確認ができる。

DIコンテナの利用を前提とした疎結合なコードにしていた事により、
逆にUI側のコードも交換可能になっていてこのテストツールの作成が無理なくできていた。

## DIコンテナ導入でやったほうが良かったこと

### FormのコードにUIスレッド外のコードが入らないようにする

UIスレッド以外からUIを触ってしまうことにより例外を吐かせてしまうのはきっと誰でもやっていることだと思う。
例えばこんな感じのコードを仕込んでおいて、ほかスレッドからのイベントをすべてこのインタフェースを介して処理することにより、
UIコード内にそもそもUIスレッドの外からのコードが入らないようにしておけば、
かなり取り回しが良くなってたと思われる。

ただし、例えばここでForm1クラスがデバイスを使う場合は、互いが互いをインスタンスとして保つ必要が出てしまうから面倒になる。
Form内の画面などにデバイスへの参照をもたせるか、デバイス側が必要になったタイミングでIInvokerクラスのインスタンスを探すなどして、
互いのコンストラクタ内にもう片方のインスタンスを要求しないようにする必要があることには注意。

```cs
    // DIで指定するインタフェース
    public interface IInvoker
    {
        void Invoke(Action action);

        void BeginInvoke(Action action);
    }

    // デバイスを使うクラス
    public class Form1 : Form, IInvoker
    {
        public void Invoke(Action action) => base.Invoke(action);
        public void BeginInvoke(Action action) => base.BeginInvoke(action);
    }

    // 使われるデバイス
    public class Dewice
    {

        private IInvoker Invoker;

        private void OnSomethingOccured()
        {
            IInvoker.Invoke(() => SomeEvent.BeginInvoke())
        }
    }
```

## そもそもプロジェクトとしてやるべきだったこと

### 早い段階でプロジェクトのコントロール権を奪っておく

最初に言った通り、私の視点では開発の音頭を取れる人が自分以外いないように見えた。
曲がりなりにも開発が一段落した今、当時の状況を考えてみると、
もし現在の会社に見切りをつけなかったら、「検証→設計→実装→テスト」の流れと開発スケジュールをこちらから提示して、
どうにかしてプロジェクトのコントロール権をマネージャから奪っておく必要があった。

### コードは定期的にコミットする・させる

未熟なマネージメントとリソース不足の恒として、開発中盤以降でスケジュールが危なくなってから人員を補充された。
その人達や今まで自分が仕事で関わってきた人を見ていて気がついたのが、
「コミットの頻度とその人の能力は反比例する」といったことであった。

コミットが小さく適切なコメントを残せる場合、その人は「自分の仕事を小さく分割でき、簡潔に説明できる」能力がある。
適当なコミットや粒度の大きなコミットをしている人が居たらしっかり指導しておくべきだったなと思った。
【GAS】APIの実行をする

# 概要

API叩いてログ出力する
今回はQiita APIを使用する

# 手順

1. APIのトークンのKeyを発行する
2. 実行する
3. 取得できる


## APIのトークンのKeyを取得する

まあトークンとかAPI Keyの取得は各々のAPIの仕様によって若干異なるけど、大体取得方法は丁寧に説明されているからその通りに取得すればいい

その値はGitHubとかに公開していけない秘密の値で、信用できない人には見せないって覚えておけば問題ない

今回は下記の記事を参考に取得
- [Qiita APIを触ってみる](https://qiita.com/miyuki_samitani/items/bfe89abb039a07e652e6)

## 実行する

- スプレッドシート経由なりとかでApps Scriptの編集画面をひらく
- 下記コードを書く

    ```js
    const BASE_URL = 'https://qiita.com';
    
    const USER_NAME = 'ユーザー名';
    const API_KEY = 'トークンのキー';
    
    const executeApi = () => {
      // header
      let requestHeader = {
        'Authorization': `Bearer ${API_KEY}`,
        'Accept': 'application/json'
      }
      // option
      let requestOptions = {
        'method': 'get',
        'headers': requestHeader,
        "muteHttpExceptions": true
      }
    
      try {
        let requestUrl = `${BASE_URL}/api/v2/users/${USER_NAME}`;
        let response = UrlFetchApp.fetch(requestUrl, requestOptions);
    
        let resCode = response.getResponseCode();
        let resBody = response.getContentText();
    
        Logger.log(`code: ${resCode}`);
        Logger.log(`body: ${resBody}`);
      } catch (e) {
        Logger.log(e);
      }
    }
    ```

- 実行する関数を選択し、「実行」ボタンを押す

    画面の上の方に実行ボタンとかがあるので、実行する関数（今回はexecuteApi）を選択

    ![スクリーンショット 2023-01-02 1.15.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557457/bde65c2d-ba21-c0f5-b594-93c54d0bfbd3.png)


## 取得できる
    
実行すると、下記画像のように実行ログが表示され、自分の情報が出力される

![スクリーンショット 2023-01-02 1.21.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557457/121462ec-e7ed-3f90-0727-5487ec514669.png)


# 最後に

今回はここで終わりだが、まあスプレッドシートに出力するとかこの関数で中身を文字列でかえすとかするときはパースしてなんか色々やる感じで

```js
// たとえば
let obj = JSON.parse(resBody);
let body = obj['body'];
```
R2 Bitcoin Arbitragerを動かすまで【備忘録】

ちょっとここらへんに急に興味が湧いたので、動かそうと思って苦労した備忘録を残す
ターゲットとしたシステムは[こちら](https://github.com/bitrinjani/r2)
ありがとうございます
自分の備忘録ですので、内容・体裁はご容赦ください

## 環境
* Windows10 Pro
* Docker
* Node.js v8.7.0

## 環境構築するまでの道のり
1. そのままで動かせる期待をしながら`git clone`し、README.mdのDockerの手順で実施してみたが、全くうまくいかず
　→このままでは埒が明かないので、ローカル環境を汚す覚悟で実行してみることにした
2. `nvm`のインストールを行い、Nodeのバージョンを色々変更しながら実行してみた
　→`rimraf dist && tsc`のエラー発生
```
error TS1005: ',' expected.
が大量に発生した
```
　→解析した結果TypeScriptのバージョンを変えてみることに
3. `npm install typescript@4.1.6 `と`npm install -D @types/express-serve-static-core@4.17.30`を実行
4. パッケージを手動で更新し、`npm update`で他のパッケージも更新することを試みる
5. 良さそうになったので、再度`npm start`を実行したところエラーが発生
```
The operand of a 'delete' operator must be optional
```
　→`tsconfig.json`の`strictNullChecks: false`に変更
6. `npm start`を実行したところエラーが発生
```
Error: Cannot find module '../build/Release/zmq.node'
```
　→`npm rebuild`を実行
7. 再度`npm start`を実行したところ無事に実行できるようになった
8. 実行が確認できたため、Dockerfileを`FROM node:8.7.0`に変更しbuild&run
F#におけるWebアプリケーション用フレームワーク「Giraffe」を触ってみる①

本記事は、F#どころかプログラミング自体初心者な自分が理解を深めるために書いたものになります。
内容に関して細心の注意は払っておりますが、間違った記述があれば遠慮なくコメントいただけますと幸いです… m(__)m

# Giraffeとは
F#でWebアプリケーションを作るためのフレームワークです。MVCモデルを採用しています。
Microsoftの公式ドキュメントでの説明は以下の通りです。
>Giraffe は、優れたパフォーマンスで豊富な Web アプリケーションを構築するための、コミュニティ主導型の F# ライブラリです。 特に ASP.NET Core を念頭に置いて設計されており、ASP.NET Core パイプラインに追加することができます。
[Web 開発での F# - Microsoft](URL "https://learn.microsoft.com/ja-jp/dotnet/fsharp/scenarios/web-development")

※後述の公式リポジトリではWebフレームワークと謡っている為、この記事のタイトル等はそちらに合わせています。


# リポジトリ
https://github.com/giraffe-fsharp/giraffe


# 公式ドキュメント

https://github.com/giraffe-fsharp/Giraffe/blob/master/DOCUMENTATION.md



# プロジェクトの作成
任意のディレクトリにて以下コマンド実行します。(各オプションは必要な値を設定してください)
`dotnet new giraffe -f "net7.0" -o test` 

実行後には以下の内容が生成されます。
>┣WebRoot/
┃　　┗main.css
┣Program.fs
┣test.fsproj
┗web.config

dotnet runを実行すれば、サッとローカルホストでアプリケーションを起動することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324881/14feff98-e0f1-7e36-c872-a03d8f2c0c62.png)



# 中身を見てみる
既定のProgram.fsの中身を紐解いてみたいと思います。…と言っても既定で各所にコメントアウトを仕込んでくれており、どれがどういう役割を担っているのかは一目でわかるようになっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324881/a4f02dc2-d250-5585-60bd-a4f60365d22b.png)


***

### ①Models
**Message**というモデルを定義しています。後述のWeb App、Viewsにて利用されます。

***

### ②Views
[Giraffe ViewEngine](URL "https://github.com/giraffe-fsharp/Giraffe.ViewEngine")を用いてビューを定義しています。
<dl>
    <dt>layout</dt>
    <dd>ヘッダーとボディを担当</dd>
    <dt>partial</dt>
    <dd>表題部分を担当</dd>
    <dt>index</dt>
    <dd>partial関数を実行して更にpタグも一緒にlayout関数に渡し、layout関数内に定義されているbodyタグの「conent」にそれらを表示させます</dd>
</dl>

***


### ③Web app
アプリケーション部分を定義しています。ここに記述されている２つの関数について内容を見ていきます。

***

##### 1. indexHandler
引数に「**name**」を指定し、greetings、model、viewの3つの定義を行っています
<dl>
    <dt>greetings</dt>
    <dd>pタグに入る文面を定義</dd>
    <dt>model</dt>
    <dd>Messageに入れる内容としてgreetingsを指定</dd>
    <dt>view</dt>
    <dd>modelの内容(=pタグの文面)を引数として②のindex関数を呼び出す</dd>
</dl>


***

##### 2. webApp
リクエストの処理を定義しています。
<dl>
    <dt>rootにアクセスした場合</dt>
    <dd>indexHandlerを起動し、引数に「world」という文字を渡しています。</dd>
    <dt>/hello/%s にアクセスした場合</dt>
    <dd>indexHandlerを起動し、pタグで表示する文章の一部分をURL中の「%s」の文字に変更できるようにしています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324881/34f7a4d0-0be0-d89e-f3ba-7c5f300f7b50.png)</dd>
    <dt>404エラー</dt><dd>ステータスコードが404の場合はtextを「Not Found」とするよう定義しています。ここで使用している**SetStatusCode**については[Giraffeの公式ドキュメント]("https://github.com/giraffe-fsharp/Giraffe/blob/master/DOCUMENTATION.md#http-status-codes")を参照。</dd>
</dl>

***

### ④Error handler
エラーが発生した場合の処理を定義しています。

***

### ⑤Config and Main
コンフィグ、エントリーポイントであるmain関数を定義しています。

:::note warn
後日追記します
:::

***

# 最後に
②では実際にWebアプリを作成した際の模様をお伝えできればと思います。
また、[Microsoftの公式ドキュメント](URL "https://learn.microsoft.com/ja-jp/dotnet/fsharp/scenarios/web-development")ではGiraffe以外にもSaturn、Fable、WebSharper、Falcoといったフレームワーク等が挙げられていますので、時間があればこれらについても記事を書きたいです。
エンジニアに読んでほしい本

若手のエンジニアと仕事していて、プログラミングが結構書ける人でも仕事に対する考え方とかそもそも解決したい問題を把握できてないケースがよくある。
その度に以下の本を勧めるのだけど、毎回面倒なので記事にまとめることにした。
リーダブルコードとかプログラミングに関する本はこれまで多くの人が紹介してきているので、紹介しない。

またエンジニアに求められる英語学習や、論理的思考に関する本は現在調査中。


# (1) コンサル1年目が学ぶこと

https://www.amazon.co.jp/%E3%82%B3%E3%83%B3%E3%82%B5%E3%83%AB%E4%B8%80%E5%B9%B4%E7%9B%AE%E3%81%8C%E5%AD%A6%E3%81%B6%E3%81%93%E3%81%A8-%E5%A4%A7%E7%9F%B3%E5%93%B2%E4%B9%8B-ebook/dp/B00MA671WW


本来、プログラミングなどを通じて携わっているアプリケーションを改善するのが仕事なのに、プログラミングすることが仕事になっている人がいる。
出すべき成果を全く意識できてない。
また1週間ぐらいかけて調査したり、設計方針や実装方法を考える作業を任せると途中の過程が全然ロジカルじゃなくて、適当に仕事をやっているようにしか見えない人がいる。そういう人にぜひ読んでほしい。


# (2) 大人のための国語ゼミ


https://www.amazon.co.jp/%E5%A2%97%E8%A3%9C%E7%89%88-%E5%A4%A7%E4%BA%BA%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E5%9B%BD%E8%AA%9E%E3%82%BC%E3%83%9F-%E5%8D%98%E8%A1%8C%E6%9C%AC-%E9%87%8E%E7%9F%A2-%E8%8C%82%E6%A8%B9/dp/4480816801/


リモートワークな世の中となりslackなど文章でやり取りすることが増えた。
その中で文章の内容を正確に読み取れず、誤解する人やどう読んでも誤解される文章を書いてしまっている人が多い。
プログラミング力よりも国語力が足りてないと思うことが多い。
そういう人にはぜひこの本を読んでほしい。
DHCPについて

●DHCP（Dynamic Host Configuration Protocol）
ホストに対して設定情報を割り当て、自動的に設定させるためのプロトコル。クライアント・サーバ構成を取り、クライアントがサーバに対して設定情報を要求。また、DHCPより以前にあったBOOTP（BOOTstrap Protocol）の上位互換であるため、DHCPサーバからBOOTPクライアントに設定情報を割り当てることもできます。
サーバ、クライアント間の通信には、67/udp（サーバ側）および68/udp（クライアント側）のポート番号を使用。

DHCPサーバがクライアントに割り当てる情報には以下のようなものがある。

・IPアドレス
・ドメイン名
・DNSサーバのアドレス
・デフォルトゲートウェイ　　など


DHCPサーバの設定ファイル「/etc/dhcpd.conf」の冒頭ではグローバルな設定を行うことが出来ます。これらの設定項目の値はデフォルトの値となります。
主な宣言文としてsubnetとnetmask、またhostなど。subnetとnetmaskでは設定するサブネットワークを、hostでは設定するホストを指定。
{}で囲まれた部分が宣言文の適用範囲であり、その中で各設定項目（ドメイン名、デフォルトゲートウェイ、割り当てるIPアドレスの範囲など）を設定。グローバルで記述されている設定項目がこの範囲でも記述される場合は、グローバルで設定された値は上書きされます。
また、設定項目では1つの設定ごとに「;」を付けます。


●DHCPサーバの設定ファイル「/etc/dhcpd.conf」で使用される主な設定項目には以下のものがあります。

・option domain-name ドメイン名;　ドメイン名を指定
・option domainn-name-servers IPアドレス[,IPアドレス…];　DNSサーバのIPアドレスを指定
・option routers IPアドレス[,IPアドレス…];　デフォルトゲートウェイのIPアドレスを指定
・option subnet-mask IPアドレス;　サブネットマスクを指定　
・option broadcast-address IPアドレス;　ブロードキャストアドレスを指定
・option ntp-servers IPアドレス[,IPアドレス…];　NTPサーバのIPアドレスを指定
・option nis-domain ドメイン名;　NISドメイン名を指定
・option netbios-name-servers IPアドレス[,IPアドレス…];　WINSサーバのIPアドレスを指定
・default-lease-time　秒;　デフォルトの貸し出し期限を指定
・max-lease-time 秒;　最大の貸出期限を指定
・range [dynamic-bootp] 開始アドレス[終了アドレス];　クライアントに貸し出すIPアドレスの範囲を指定
・fixes-address IPアドレス;　クライアントに割り当てる固定IPアドレスを指定。宣言分host内のみで使用
・hardware インターフェイスタイプ　MACアドレス　クライアントを特定するためのMACアドレスを指定
・(allow|deny) unknown-clients;　MACアド絵ｒ巣の指定のないクライアントにアド絵ｒ巣の割り当てを許可するかどうか。allow 許可(デフォルト)、deny 拒否

なお、デフォルトのdhcpd.confではアドレスに空きがある限り、host宣言文で記述した以外の素性のわからないクライアントも接続できますが、deny unknown-clients;と記述することで、 host宣言文にMACアドレスが登録されたクライアントのみにアドレス割り当てをすることもできます。こうすることで、登録の手間はかかりますがMACアドレスとIPアドレスを1対1で管理する運用も可能。
アロー関数の省略と向き合う

普段から使うことの多いアロー関数の省略について、ざっと省略の仕方をまとめました。

# 1.省略しない場合と省略した場合の比較

例として、渡された数値を2倍にして返す関数を考えます。
**before**
```js
const doubleNumber = (number) => {
    return number * 2;
}
```
**after**
3行あったコードが1行で記述されています。
```js
const doubleNumber = nubmer => number * 2;
```
上記のようなコードは、Javascript開発に携わっていると、親の顔より見た光景になると言っても過言ではありません。
見慣れてしまえば、なんのことはないのですが、なれていないと「??」と戸惑うこともあるかもしれません。

では、どのような省略の過程を経て3行が1行になったのか見てみます。

# 引数のカッコの省略
まずは引数周りです。

**before**
```js
(number) 
```
↓
**after**
```js
number
```
引数に注目してみると、（）が省略されています。
これは、`引数が一つの時()を省略することができる`からです。

引数がなかったり、引数が複数ある場合は（）は省略できません。

```js
(number)
// ↓
number // ◯

(number1, number2)
// ↓
number1, number2 // × (省略不可)

()
//↓
     // × (省略不可。そもそもなんだか分からんだろう。)
```

ということで、**引数のカッコを省略した版**は以下の通りです。

```js
const doubleNumber = number => {
    return number * 2;
}
```

それでは、次の省略を見てみましょう。

# {} と return の省略
次に省略できる可能性のあるものはブロックを表すの`{}`と`return`です。
前述の**引数だけ省略した版**から、これらを省略してみます。

**before**
```js
const doubleNumber = number => {
    return number * 2;
}
```
↓
**after**
```js
const doubleNumber = number => number * 2
```
はい。これでできる省略はすべて行いました。

この`{}`が省略できる条件は、関数内のコードが式1つだけのときです。
なので、以下のような場合は省略できません。
```js
const greetFunction = name => {
    const greet = `hello ${name}`;
    return  greet;
}
```
もし、このようにひとつの式で終わっていれば、さらに省略できるというわけです。
```js
const greetFunction = name => {
    return `hello ${name}`;
}
```
↓
```js
const greetFunction = name => `hello ${name}`;
```
※この例では、関数の中が2行でも1行でもさほど変わりないのですが、実際のコードはもっと複雑なことも少なく有りません。無理に1行にして、可読性が損なわれたりしないか注意しましょう。

## returnするのが、Objectの場合
**return**するのがObjectの場合。

**before**
```js
const createObj = (name) => {
    return {
        userName: name 
    }
}
```

今まで見てきた省略のルールに従うと、このようにできそうな気がしますが...
```js
const createUser = name => {userName: name}
```

これは**×**です。

この場合、`｛｝`はオブジェクトの`｛｝`ではなく、関数の`｛｝`と認識されていまいます。
以下の状態と同じことになります。
```js
const createUser = name => {
  userName: name
}
```
この場合`userName`はオブジェクトのプロパティ名ではなく、ラベルと解釈されるので、意図する状態ではありません。


そのため、returnするのがojbectの場合は、以下のように()でobjectを囲むようにします。

**after**
```js
const createUser = name => ({userName: name})
```

# まとめ
以上、アロー関数の省略についてでした。

省略記法はごく一般的なテクニックですし、コードの記述量も減るので積極的に使っていきたいところです。
ですが、必要以上に省略をしたことで第3者がコードを見た時に、「は？ここはどういうことだ？」とコードの解読に手間取ってしまうようなことになってしまっては本末転倒です。

実務のプロジェクトでは、エンジニアの入れ替わりなんかも度々あるので、コードの**可読性**も大事です。
「短いコードで書く」ことを心がける確かに大事なことですが、「なんでもかんでも省略すれば良い」というわけではありません。
わかりやすさを損なわないように省略を活用して行きたいですね。
Systems ManagerによるEC2インスタンス操作ログの取得方法

# 目的
AWSを利用したシステムの運用時にSystems Managerを利用してEC2インスタンスを操作することもあるかと思います。
その際にEC2インスタンスの操作ログを取得したい場合もあるかと思いますので、操作ログ取得手順をまとめたいと思います。
手順としては、以下となります。
1. 操作ログ格納用のS3バケット作成
1. EC2インスタンスのIAMロールにS3バケットへのアクセス権限の付与
1. Systems Managerのログ出力設定

## 1. 操作ログ格納用のS3バケット作成
本手順では、「prjtest-dev-log-ssm-20230101」という名称でS3バケットを用意します。

## 2. EC2インスタンスのIAMロールにS3バケットへのアクセス権限の付与
EC2インスタンスのIAMロールには、以下のIAMポリシーが必要となります。
- AmazonSSMManagedInstanceCore
- AmazonS3FullAccess *1

*1 「AmazonS3FullAccess」ポリシーが必要と記載しましたが、以下の権限を備えたIAMポリシーが紐づいていれば問題ございません。
```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:GetEncryptionConfiguration"
            ],
            "Resource": "*"
        }
    ]
}
```

### 補足
ちなみにですが、Systems ManagerからEC2インスタンス接続時に、アクセス権限が不足していると以下のエラーが表示される場合がございます。その際はEC2インスタンスのIAMロールを見直し、S3へのアクセス権限が存在するかを確認する必要がございます。
![2023-01-01 12_39_58-Instance name_ server.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429119/acd7a451-9013-b4ab-6233-101a962105fe.png)


## 3. Systems Managerのログ出力設定
以下の手順でログ出力設定を行います。
![2023-01-01 12_38_36-AWS Systems Manager - Session Manager.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429119/e7f2ffd1-43e1-a4ac-9884-cf9d8a63979f.png)
![2023-01-01 12_38_51-AWS Systems Manager - Session Manager.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429119/7052e0c3-00b5-f4f4-3e85-bdcb66e4a114.png)

ログ出力が設定されているかは確認します。
![2023-01-01 12_39_16-AWS Systems Manager - Session Manager.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429119/6d76196a-00d8-4a15-a9c4-860c9c3ce97b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429119/1163d0ed-7d34-dc40-b96d-d33a00e28c4d.png)
![2023-01-01 23_55_33-prjtest-dev-log-ssm-20230101 - S3 bucket.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429119/de965f45-dace-04ac-2675-2d716acdfadb.png)

## 補足
S3バケットに出力されたログは文字化けしています。
正直なところ原因が良くわかりませんが、メモ帳やサクラエディタで文字コードをutf8にしても文字化けは解消されませんでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429119/1cf8cda8-7594-779d-377c-c339b6fbf524.png)

Windowsユーザーの場合は、Powershellにて以下のコマンドを利用した場合は、文字化けを解消することが出来ます。
今回はAmazon Linux2の文字コードをutf8にしています。
```
Get-Content [ログファイル名] -Encoding utf8
```
コマンド実行後の出力は以下の通り
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429119/5b200536-95a8-bd1c-e0e9-cd498b89d98f.png)

実運用を考えた時には、何か障害発生時に操作ログを確認することになるかと思います。
全てのログを見るわけではない場合がほとんどだと思いますので、いったん、S3バケットに操作ログを格納し、何かあった際に、上記のコマンドを利用する運用もありかと考えています。

## 参考

https://dev.classmethod.jp/articles/recording_session_logs_via_ssm/
［初心者］オープンデータを利用してtableau publicでポイントをクリックしたら関連ホームページに飛ぶダッシュボードを作ってみた。

[DATA Saber APPRENTICE](https://datasaber.world/)としての旅の１ページ
初心者なので書き方などご容赦ください。
Qiita記述については[Markdown記法 チートシート](https://qiita.com/Qiita/items/c686397e4a0f4f11683d#images---%E7%94%BB%E5%83%8F%E5%9F%8B%E3%82%81%E8%BE%BC%E3%81%BF)を参考にしています。

初心者がオープンデータを利用し、tableau publicでポイントをクリックしたら関連ホームページに飛ぶダッシュボードを作ってみました。
簡単に作れるので、是非データを入れ替えて真似して使ってみてください。

誰もが使えるサンプルデータとして[オープンデータ](https://www.digital.go.jp/resources/open_data/)を利用しました。

環境：tableau public2022.4.0(64bit)、win11　
※ubuntuで利用しようとしたらtableau publicのインストールパッケージがありませんでした。linux系で利用する場合はブラウザから利用しましょう。


利用データについて：[佐世保市のオープンデータポータルサイト](https://odcs.bodik.jp/422029/)から[公共施設データ](https://data.bodik.jp/dataset/koukyoushisetu_hyoujyun)をダウンロードしました。
※APIはtableau publicで接続の仕方がわかりませんでした。
※佐世保市の公共施設一覧データはクレンジング済みのデータのようです。
![データダウンロード](https://raw.githubusercontent.com/Kaysan555/Newbie_on_tableau_public/67ac69248b759c560967af3887318af66f3fb5f1/2.jpg)

以下手順
1：tableaupublicを起動させたらダウンロードしたcsvファイルをドロップ。
２：**右下の青く囲んでいる部分が１００行になっている**ので、その左に書いてある**２８２行と同じ数字を打ち込**んでエンターキー。
３：その後にシート１をクリック。
![個々の画面にドラッグアンドドロップ](https://github.com/Kaysan555/Newbie_on_tableau_public/blob/main/4.jpg?raw=true)


4：キャンバスで左側のデータの中にCSV内のデータがあることを確認。
![キャンバスが見える](https://github.com/Kaysan555/Newbie_on_tableau_public/blob/main/5.jpg?raw=true)

5：データ、テーブルの中を下にスクロールすると緯度・経度情報があるので画像のように地理的役割から、軽度と緯度の設定を与える。
6：緯度、経度、をダブルクリックする。
![緯度経度設定](https://raw.githubusercontent.com/Kaysan555/Newbie_on_tableau_public/b16867c0fe470fe3d06a2e9eed6262d4205cb5f7/6.jpg)

7：名称をマークカードの中にドラッグアンドドロップする。
![名称をマークカードの中に入れる](https://github.com/Kaysan555/Newbie_on_tableau_public/blob/main/7.jpg?raw=true)

8：背景地図が分かりにくいので[Open Street Map](https://openstreetmap.jp/)に変更する。![背景変更](https://github.com/Kaysan555/Newbie_on_tableau_public/blob/main/8.jpg?raw=true)

9：URL、名称読みカナ、住所等の情報をマークカードにドラッグアンドドロップする。
![他の必要そうな情報を入れる](https://github.com/Kaysan555/Newbie_on_tableau_public/blob/main/9.jpg?raw=true)

10：点が見にくいので枠線をつけて少し透過させる。
色ボタンをクリックして不透過度を70%くらいにし、さらに下の線の部分をクリックし、黒を選ぶ。
![枠線のえらびかた](https://github.com/Kaysan555/Newbie_on_tableau_public/blob/main/11.jpg?raw=true)

11：名称が地図上に出るようにCtrlキーを押してマークパレットのラベルにドロップ。
![ラベルの表示のさせ方](https://raw.githubusercontent.com/Kaysan555/Newbie_on_tableau_public/34ab51810d6cfd65b73c5e8161551c7342e24e0e/12.jpg)

12：ダッシュボード化のためにダッシュボードを追加
![ダッシュボードを追加](https://raw.githubusercontent.com/Kaysan555/Newbie_on_tableau_public/289f4a91af142be9b60a7b64ad17ee385086d0c3/13.jpg)

13：ダッシュボードに作成した地図のシートを追加を行い、利用者が操作しやすいように地図を触った時の挙動を変更しておく。
![シート１追加](https://raw.githubusercontent.com/Kaysan555/Newbie_on_tableau_public/6035617ffe7ce24ee597c8ac4d39d142fadb184f/14.jpg)

14：施設をクリックしたらページに飛ぶように変更したいのでアクションを設定する。
![アクション設定](https://github.com/Kaysan555/Newbie_on_tableau_public/blob/main/15.jpg?raw=true)

15：URLについて公共施設データシートに記入してあるURLを引用するように、挿入ボタンを押し、URLを選択。その他、公共施設のポイント（公共施設の青い円）をクリックしたら動作するように、アクション実行対象は**選択**時に設定する。![アクション設定画面](https://github.com/Kaysan555/Newbie_on_tableau_public/blob/main/17.jpg?raw=true)

16：左上のファイル→名前を付けてtableaupublicに保存するとパブリッシュされて、誰でも見れるようになる。

URLリンクを好きに張り付ければダッシュボード完成。
表現の仕方には改善点があると思いますが、ササっと時間をかけず真似できます。
kintoneで「足跡」機能を作ってみた


## はじめに
[前回](https://qiita.com/n_none/private/0bfdd781f63c7b9c5035)、カスタマイズスペシャリストの勉強を兼ねてSlack通知プラグインを作成してみました。
しかし、通知されたレコードが本当に確認されたのか不明なままでした。
そこで、kintoneで簡単な「足跡」機能を作成してみました。

https://qiita.com/n_none/private/0bfdd781f63c7b9c5035

#### コード
``` customize.js
(function () {
  'use strict';

  kintone.events.on('app.record.detail.show', function (event) {
    const record = event.record;
    const loginUser = kintone.getLoginUser();
    const existUsers = record.足跡.value;
    const codes = [];

    // 足跡に登録済みユーザーのコードを配列に格納する
    existUsers.forEach(user => {
      codes.push(user.code);
    });

    // ログインユーザーが足跡に未登録の場合
    if (codes.indexOf(loginUser.code) === -1) {
      // 足跡に追加する
      existUsers.push({ 'code': loginUser.code });
      const putParams = {
        'app': kintone.app.getId(),
        'id': record.レコード番号.value,
        'record': {
          '足跡': {
            'value': existUsers,
          }
        },
      };
      // レコードを更新する
      kintone.api(kintone.api.url('/k/v1/record.json', true), 'PUT', putParams, (resp) => {
        // 成功したので再読込みする
        location.reload();
      }, (error) => {
        console.log(error);
      });
    }
  });

  kintone.events.on(['app.record.create.show', 'app.record.edit.show'], function (event) {
    const record = event.record;
    // レコード再利用の場合
    if (event.reuse === true) {
      // 足跡を初期化する
      record.足跡.value = [];
    }
    // 足跡を非活性にする
    record.足跡.disabled = true;
    return event;
  });

})();
``` 
#### 使い方
対象のアプリに「ユーザー選択」フィールドを追加します。
フィールドコードは「足跡」にします。
![ユーザー選択.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3073813/9e6e5f54-da3c-2e7a-1163-821f146bf327.png)
次にコード（customize.js）を対象のアプリにアップロードします。
「アプリを更新」を忘れずに行います。
アップロードの仕方は [こちら](https://jp.cybozu.help/k/ja/user/app_settings/js_customize.html
) を参考にしてください。
![JSアップロード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3073813/05a529ec-79a4-1e98-7b06-2136e4548600.png)

#### 動作確認
対象のアプリでレコード登録を行います。
※この例ではkintoneアプリストアの「商談報告書」を利用しています。
![レコード登録1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3073813/37c939e1-04b9-6211-2721-a5ab136a77bd.png)

必要な情報を入力して、保存すると「足跡」にログインユーザー（N.N）が登録されます。
※JSカスタマイズで作成者を「足跡」に残さない対応も可能です。
![レコード詳細1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3073813/7b9f9c65-3862-0322-6e0b-45175fe72f56.png)

次に別のユーザー（VIP1）でログインして先程のレコードを閲覧します。
![レコード詳細2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3073813/eb654a6b-2100-4714-cc79-9d5ddf13abb0.png)

「足跡」を確認すると、閲覧したユーザー（VIP1）が「足跡」に追加されます。
![レコード詳細3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3073813/addef5fa-18a3-cb9d-6e08-0a0be8e3cd3d.png)

:::note info
ポイント
同じユーザーで再閲覧しても「足跡」には登録されません。
:::
:::note alert
注意
~~レコードコピーには対応できていません。~~
コードを修正しました。再利用は [event.reuse](https://developer.cybozu.io/hc/ja/articles/201941984#step1) で判断するようです。
:::
仕事でGASを使ったのでまとめてく

# はじめに

フリーになって少ししてGASを使うお仕事をしたので、そこで知ったこととか学んだことをつらつらとまとめていきます。

# ざっくり内容

- APIを実行してデータを取得し、スプレッドシートにおこす
- APIの実行は毎日特定の時間に実行、都度タイミニングの２パターン

# 目次

- [APIの実行をする](https://qiita.com/cats-park/items/75a0caebcc9a77baaf44)
- スプレッドシートの最終行に追加する(予定)


※作成中です...
インターネットからの接続を受け付けるサーバーは IP だけではなく Port 番号も記録しておくことが推奨される — あるいは RFC 6302 : Logging Recommendations for Internet-Facing Servers の紹介

IP だけ記録して『これで何があっても最悪警察に通報すればなんとかなる』というとそうでは無い話。

結論：ポート番号も記録するのだ。[nginx なら `$remote_port` に値が入っている。](http://nginx.org/en/docs/http/ngx_http_core_module.html#:~:text=client%20address-,%24remote_port,-client%20port)

RFC 6302 : Logging Recommendations for Internet-Facing Servers
====
インターネット Facing なサーバーでどのようなログを取ることが推奨されるのかちゃんと書いてある資料

https://www.rfc-editor.org/rfc/rfc6302

    It is RECOMMENDED as best current practice that Internet-facing
     servers logging incoming IP addresses from inbound IP traffic also
     log:
     o The source port number.
     o A timestamp, RECOMMENDED in UTC, accurate to the second, from a
       traceable time source (e.g., NTP [RFC5905]).
     o The transport protocol (usually TCP or UDP) and destination port
       number, when the server application is defined to use multiple
       transports or multiple ports.

現在のベストプラクティスとして、インターネットに面したサーバーは、受信IPトラフィックから受信IPアドレスをログする際に、以下のログも取ることが推奨されます。

* <font color="Red">**source port number**.</font>
* timestamp.
* transport protocol (TCP / UDP 両方で受け付ける場合）


総務省の資料
====
> https://www.soumu.go.jp/main_content/000360558.pdf
> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52956/ef828e81-3709-8637-0d73-9ab8b67bbe5f.png)
> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52956/45ee09ab-0672-1714-a06d-7c2204abcfa4.png)
Next.js (React) でエンターを押し続けると色が薄まっていくコード例

# ポイント

- エンターキーを押すたびに 0から +1 ずつ数値をカウントアップする
- 数値を3つ繋げて16進数に直すとカラーコードになる ( 例:  `#999999` )
- カラーコードを css の color として利用する

# コード

`pages/ColorIncrement.tsx`

```js
import React, { useEffect, useState } from 'react';

const ColorIncrement = () => {
  const [count, setCount] = useState(0);
  const handleKeyDownEnter = (event: KeyboardEvent) => {
    if (event.key === "Enter") {
      setCount(count + 1);
      console.log("Enter")
    }
  };

  useEffect(() => {
    document.addEventListener("keydown", handleKeyDownEnter);
    return () => {
      document.removeEventListener("keydown", handleKeyDownEnter);
    };
  }, [count]);

  var color_flagment = ( '00' + count.toString(16) ).slice( -2 );

  var color = '#' + color_flagment + color_flagment + color_flagment
  var style = {color: color, background: "white", fontSize: "50pt"}
  return <div style={style}>{color}</div>
}

export default ColorIncrement

```

# 表示例

![image](https://user-images.githubusercontent.com/13635059/210174501-fb32905d-fee2-42a4-9fc9-9cd756173138.png)
![image](https://user-images.githubusercontent.com/13635059/210174503-5f431639-a487-4342-bf93-4e7b0123cf53.png)
![image](https://user-images.githubusercontent.com/13635059/210174504-391e4135-a3ac-4c4b-839c-c54439498d71.png)

# 環境

next@13.1.1

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ


# Twitter

https://twitter.com/YumaInaura
arXivにおけるquant-phの投稿件数の推移

2023年になりました。
今年も様々な論文が発表されると思いますが、世界中の方がお世話になっている[arXiv](https://arxiv.org/)は、[Wikipediaによると](https://en.wikipedia.org/wiki/ArXiv)1991年8月にローンチされたそうです。

arXivに投稿される論文は「[Subjects](https://arxiv.org/category_taxonomy)」を割り振りますが、量子コンピュータ界隈の方は主に「quant-ph」が含まれる論文をチェックしているのではないかと思います。

「quant-ph」の論文は年々増加しているように感じますが、実際に集計して可視化したものが次のグラフになります。
![num_of_papers.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13107/a9d93c76-a031-7492-01e0-f9e234882ee5.png)

横軸が年で、縦軸がその年の「quant-ph」の論文数です。初期の頃を除き、単調増加しています。

arXivはAPIでアクセスできるので、こういう集計がしやすくていいですね。私はPythonの[arxiv](https://pypi.org/project/arxiv/)というライブラリを使って情報を取得しました。

ちなみに、「quant-ph」として投稿された最初の論文は1992年10月7日にsubmitされた"The Spacetime Approach to Quantum Mechanics"という論文です。2022年は最初に「quant-ph」の論文がarXivに投稿されてから20周年だったんですね。

https://arxiv.org/abs/gr-qc/9210004

2021年、2022年は投稿件数が1万件を越えました。平日にarXivが更新されることを踏まえると、40件/日くらい投稿があるんですね。

2023年も多くの論文が投稿されると思うので、楽しみですね！
Zabbixを使ってサーバ証明書の有効期限を監視してみた

# はじめに
Zabbixでサーバ証明書の有効期限を監視して、期限が近づいたらアラートを発砲して証明書の更新作業を行えるように運用をしたいので、アイテムを取得できるように設定してみます。

# サーバ構成
Zabbixサーバ
- AWS(EC2)
- CentOS7.9
- Zabbix-Agent5.0
- Zabbix-Server

Webサーバ
- AWS(EC2)
- CentOS7.9
- Zabbix-Agent5.0
- Apache2.4
- mod_ssl

# 前提条件
- ネットワーク環境(VPC,サブネット,ルートテーブル,セキュリティグループ)が既に構築済みであること
- 各サーバに実装されているソフトウェアおよびミドルウェアは導入済みであること
- opensslで自己証明書を作成していること
- Apacheの設定ファイルに自己証明書の設定が済んでいること

# 構築してみる
### 証明書の有効期限を出力するスクリプトを作成

ssl_cert_days.sh
```
#!/bin/bash

date +"%s" --date="`openssl s_client -connect localhost:443 -servername localhost </dev/null 2>/dev/null | openssl x509 -enddate -noout | cut -d'=' -f2`" | awk '{printf("%d\n",($0-systime())/86400-1/86400+1)}'
```

### Zabbixのホスト作成
![スクリーンショット 2023-01-01 23.11.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478546/b921cad6-fdf4-4d17-8698-e6f84431ea7a.png)

ホスト名：任意の名前
グループ：任意のグループ
IPアドレス：プライベートIPアドレス

### Zabbixのアイテム作成
![スクリーンショット 2023-01-01 23.13.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478546/f319ce22-e12b-a2da-2d23-41605cd63e60.png)

名前：任意の名前（わかりやすい名前にする）
タイプ：Zabbixエージェント
キー：cert_expire_check[]　　　　　　　　　　　　　（エージェント側のUserParameterと同じキー名にする）
ホストインターフェース：エージェント側のプライベートIPアドレス
データ型：数値（整数）

### Zabbixエージェント設定ファイルの修正
/etc/zabbix/zabbix_agentd.conf

```
UserParameter=cert_expire_check[*],/etc/zabbix/ssl_cert_days.sh
```

### スクリプト配置
Zabbixエージェント側のサーバに上記の設定ファイルで記載したディレクトリにスクリプトを配置する。
また、Zabbixユーザで実行できるよう、スクリプトの権限と所有者を変更しておく。

```
chmod 755 /etc/zabbix/ssl_cert_days.sh
chown zabbix:zabbix /etc/zabbix/ssl_cert_days.sh
```

### Zabbixエージェント再起動

```
systemcctl restart zabbix-agent
```

### Zabbixサーバのログ確認
再起動したら、Zabbixサーバ側のログを確認して、アイテム取得のエラーが発生していないか確認する。

```
tail -F /var/log/zabbix/zabbix_server.log
```

### アイテム取得確認
アイテム値が取得されていることが確認できたら、それを元にトリガーを作成するなりして、後続の作業ができます。
![スクリーンショット 2023-01-01 23.22.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478546/808cfe79-81c0-36cb-cdc0-de67d5f4bca9.png)


# 参考
- [Zabbix公式 ユーザーパラメータ](https://www.zabbix.com/documentation/2.2/jp/manual/config/items/userparameters)
- [ZabbixでSSL証明書の有効期限を監視する](https://qiita.com/ma3ki/items/302205c0402c3746c9ff)
- [ZabbixでSSL証明書の有効期限を監視してみる](https://fingerease.work/archives/zabbix-ssl-monitoring/)
- [ZabbixからSSL証明書の有効期限を監視する](https://eatsmart.hatenablog.com/entry/2019/12/23/114845)
プロジェクトのリスク管理についての振り返り

## 背景
未経験入社後1年5ヶ月経過したタイミングでありがたい事に、ある予約システムのプロジェクトリーダー（PL）を経験させてもらえる事になり、約6ヶ月の開発期間を経て、先日リリースを迎えました。
その過程の中で、プロジェクト開始〜リリースまで進めていくに当たり、リスクが多く潜んでいると感じました。

- 仕様が決まっていない
- 素材が来ていない
- メンバーの突然の体調不良
- タスクの遅延

これらの項目は、考えてみると当然っちゃ当然なんですが、
自分が感じたリスクとは、これらも含めて、

***後で工数が発生するかもしれない状況が存在すること***

だと感じました。
PLとして開発スケジュールを管理する上で、見積る事ができない工数はできるだけ減らしたいです。工数が膨れ上がると計画が崩れますし、いくらバッファを設けていても、これで足りるのか？という気持ちになります。
なので自分の中では、***後で工数が発生し得る状況をリスクとして考える***事にします。

これから、上記以外で***実際に起こった追加の工数***と、それを***できるだけ避けるための策***
を記載していきます。

※補足
[LINE MessagingAPI](https://developers.line.biz/ja/services/messaging-api)という語句がでてきますが、
詳細はリンクから確認ください。


## 実際に発生した追加の工数
#### テストアップのタイミングでクライアントにシステムを展開し、一部のFBは来たが、本当に隅々まで確認してもらったかわからず、結局リリース後に修正依頼が来た

リリースしたタイミングですぐに修正する事自体ミスを発生しやすくする要因です。
また、デプロイ前の修正内容の確認、デプロイ作業・デプロイ後の反映内容の確認を実施するのに工数が必要となるので、追加工数が発生したと考えます。

---
#### LINE MessagingAPIにはリクエスト上限数（2000リクエスト/秒）があるが、一気にこの制限数を超える人数へメッセージを送信したいという緊急要望がリリース後に来た

リリース後であったためすぐには対応できず、現状の機能で実施する形となり、この制限数を超えないよう人数を分割してメッセージを送信する、という本来不必要なオペレーションが発生しました。
同時に、機能追加修正工数が発生しました。

---
#### ローカル環境では動くけどテスト環境では動かない、という事象に遭遇した

画像の保存に関しては、RailsのActiveStorageを利用していたのですが、
画像ファイルへのパスのドメイン ≠ ブラウザ画面のドメインのため、
html aタグのdownload属性の仕様でダウンロードが機能しない事が発覚しました。
ダウンロードボタンを一つの機能としてクライアントFIXしているため、ひと工夫してダウンロードできるようにする必要があります。これに関してはテスト環境で早めに試さなかった事が敗因です。追加工数の発生と考えます。

---
#### テストパターンの洗い出しが不足していたため、プログラム修正後に再度のテスト工数が必要となった

これはそのままの通りでテストパターンの洗い出しが不足していました。修正工数と再度のテスト工数が追加で必要となりました。（テストコードによるテスト自動化の際のテストパターン洗い出しが不足していた問題でもあります）

---
#### 外部ツールの設定方法について、メンバーに１から設定方法をレクチャーするための工数が発生した

今回で言うと、LINE APIとの疎通がうまくいかないとメンバーから質問を受ける機会が多かったです。
途中でチームに加わったメンバーに最初にLINEの設定関連をざっと説明しても、設定方法なんてものは当然一発で覚えることはできないので、動くようにするために工数が必要となりました。


## できるだけ避けるための策
少し大袈裟な書き方ではありましたが、追加工数が発生した部分を分析してみました。
予期せぬ追加工数を完全に無くす事は難しいと思いますが、
できるだけ避けるための策を講じる事はできると思いますので、考えてみます。

#### 外部APIを使用する場合、それはリスクとして考える
> LINE MessagingAPIにはリクエスト上限数（2000リクエスト/秒）があるが、一気にこの制限数を超える人数へメッセージを送信したいという緊急要望がリリース後に来た

外部APIには何かの制限があると思いますので、必ずチェックし、その制限が起こり得るケースなのかどうか考え、予め対策を講じて置くのが良いと考えます。通信が失敗した場合の処理についても考えておくのが良いと感じました。

---
#### 指摘が来そうと感じる仕様に関しては、クライアントに時間を頂戴してでもこちらから先に動作説明し、動作を認識してもらう
>テストアップのタイミングでクライアントにシステムを展開し、一部のFBは来たが、本当に隅々まで確認してもらったかわからず、結局リリース後に修正依頼が来た

時間を取る事が難しい場合、対象箇所の動画を送付するでも良いと思います。動くものを確認いただく事で早めにFBをもらう事が目的です。


---
#### 本番に近い構成のテスト環境を開発初期の段階から用意し、確認するフェーズを設ける
> ローカル環境では動くけどテスト環境では動かない、という事象に遭遇した

ローカル環境では動くけどテスト環境では動かない、という事象を早めに認識するためです。

---
#### 機能開発の際は、テストパターン洗い出しを行い、バグ発覚による修正を最小限にとどめる
> テストパターンの洗い出しが不足していたため、プログラム修正後に再度のテスト工数が必要となった

テストパターンの洗い出しは時間がかかると思います。
また、テストコードを書くのももちろん時間はかかり、進捗が出なくて辛いかもしれません。

しかし、テストコードを書くという事は、テストコードが書けるように本実装のコードを書かないといけなくなるため、コードの品質が良くなるのと同時に、後でかかるであろう修正工数＆テスト工数を削減できるので、結果として最初にかかる工数がペイできると、今では本当に感じます。

---
#### 設定関係は、簡易的でも良いのでドキュメント化する
> 外部ツールの設定方法について、メンバーに１から設定方法をレクチャーするための工数が発生した

最悪手順をまとめている記事を引用するでも何でも良いのですが、ドキュメントを見てやってね〜、わからん部分は聞いて！の形に持っていくのが良いと感じました。READMEに記載はしていたものの、文字しか無くてわかりにくかったので、もう少し画像付きでちゃんとしたものを用意しておけば良かったと思います。backlogをうまく活用したい。

## まとめ
リスク管理と一言で言っても色々とある中で、今回自分は

***後で工数が発生するかもしれない状況が存在すること***

にフォーカスしてリスクを定義し、振り返りを行いました。
次の案件で実践してみて、また振り返りを行いつつ、自分で良いと思えるプロジェクト進行のスタイルを身につけていきたいと考えています。
ZabbixでJboss EAP 7.4 のメトリクスを監視

JBoss EAP 7.4 のメトリクス値(ヒープサイズ、DBコネクション等)をZabbixに取り込んでJBossを監視できることを確認した。

### 確認した環境
- Zabbix 6.2 (dockerイメージ使用)
- Jboss EAP 7.4（スタンドアローン）
- Java  1.8.0_221
- Windows 10

## 確認内容
### JBoss起動
Windows上にJBossを配置し、起動バッチファイルを実行する。
ローカルホスト以外からもmanagementインターフェースにアクセスできるように
JBoss起動パラメタに、-Djboss.bind.address.management=0.0.0.0を追加

```
standalone.bat -b 0.0.0.0 -Djboss.bind.address.management=0.0.0.0
```

### curlコマンドでJBossのメトリクス情報を取得できることを確認

 JBossのメトリクスは、http://<ホスト名>:9990/metricsから取得できる。
Zabbixに取得結果を取り込むため、Zabbix Serverにログインし、JBossへアクセスできることを確認。以下の例では、JBoss ServerのIPは「192.168.11.6」
```
curl http://192.168.11.6:9990/metrics
```
実行結果は、Prometheusと同じフォーマットで出力される。
![Curl.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1284235/e8b24297-fd41-1ea9-ce8c-1b3648f7232a.png)

### itemの追加 metrics実行結果をHTTP agentを使用して取得
Zabbix Serverの監視ホストにJBoss serverを追加し、Itemを追加する。
HTTP ageentを使用して、metricsをHTTPのGETでリクエストした結果をテキストとして取り込むよう設定。

![Http Agent.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1284235/e75bd1fe-0c4b-10f6-3f11-d0ddb40adf25.png)

### Item追加2 Dependent Itemを使用してmetricsの実行結果から監視対象を取り込む
![Dependent.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1284235/e2915cb1-2674-819f-601a-06454409a08d.png)

以下の例では、8080ポートの接続コネクション数を取得する。
- PreprocessingでPrometheus patternを選択
- パラメタは以下を設定
jboss_io_connection_count{worker="default",server="/0.0.0.0:8080"}
- グラフ表示のため、Numeric(float)として取り込む

![Preprocessing.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1284235/e6445afa-4363-8c29-b273-9231099ac7a7.png)

### 登録後イメージ
![登録後.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1284235/dd4ec0a8-539e-c7be-34a3-0b3bb4db54c1.png)

### 監視結果で取り込んだ結果をグラフで表示
![グラフ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1284235/c436b2c9-441f-be3e-4e7a-273fef204238.png)