OmniAICreator/Qiita-1.07M huggingface dataset:
データレイク、データウェアハウス 、データマートの3層構造の分析基盤を運用する話

これは「[弁護士ドットコム Advent Calendar 2021](https://qiita.com/advent-calendar/2021/bengo4com)」の 15 日目の記事です。

# はじめに
データ分析基盤の構成は多種多様なものがありますが、当社ではデータレイクをはじめとして、データウェアハウス、データマートの3層構造をとっています。概念としてのデータレイクは良いものだと思いますが、実際に利用してみると問題もつきものです。今回は当社での実際のデータレイク運用や、運用してみた結果見えてきた問題点等について記載します。


# 1. 当社の運用
## 1.1 構成
分析基盤の構成は次の通りです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570763/cf6d5dee-1b35-6936-5dab-bddb453bd2ef.png)

 - GCPでは権限分けのため、各層をプロジェクト単位で分割
 - trocco転送用DB(各種サービス用DBのコピー)を作成し、troccoサービスを用いてBigQueryにデータ転送
 - 一旦データレイク層に集約し、集計やマスキング処理の結果をデータウェアハウス、データマートに転送
 - BIツールredashからデータウェアハウス、データマートを参照

### 1.1.1 データレイク
1.1構成図の通り、各層はGCPのPJ単位で分たれたBigQueryサービスで構成されています。その中でデータレイク層は一旦全ての必要なデータを投入しています。また、GCPへのデータ転送のためにtroccoを利用しており、当社で利用している他のサービスも、分析で活用するもの、かつtroccoが対応しているものは同様にデータレイク層に投入しています。サービス毎にPJを分けた中ではデータソース毎にデータセットを分けて運用しています。なお、集計やマスキング処理等は行わず生データを保管しています。

### 1.1.2 データウェアハウス
データウェアハウス層はデータレイク層のデータを一次加工したデータを保管しています。機密データへのマスキング処理やある程度使いやすい粒度での集計等を行なっています。データマートを作成、利用していく上で必要になるであろうものを事前準備し、まとめておく層のような認識です。

### 1.1.3 データマート
データマート層は最終成果物のようなイメージです。redashからの利用を念頭に置き、データウェアハウス層で準備したデータを基に実際に利用したいデータ、分析したいデータをアウトプットする層として活用しています。データウェアハウス層で準備したテーブルを複数利用する、最終アウトプットがredashから参照される等の場合はデータマート層にテーブルを作成することが多いようです。

下図はこれら各層の利用イメージを表したもので、データレイク層に存在する各種テーブルからデータマートを作成するまでの大まかな流れを示しています。なお、データレイク層のテーブルに集計クエリをかけた結果をデータウェアハウス層に転送する、等の一連の処理は全てtrocco上で管理しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570763/d79fc78b-1ef9-6576-2d5e-b195e1637f23.png)

## 1.2 権限

以下は各層毎の権限対応表です。基本方針としては生データが保管されているデータレイクは限られたメンバーのみが編集権限を持つというものです。これをベースにサービス単位のPJ毎に権限を振り分けたグループを作成、運用しています。

|  | Admin | Creator | Viewer |
| --- | --- | --- | --- |
| DataLake | CRUD | R |  |
| DataWarehouse | CRUD | CRUD |(R) |
| DataMart | CRUD | CRUD | R |
*CRUD(Create、Read、Update、Delete)

データレイクを参照する必要があるデータウェアハウスのViewは承認済みビュー機能等を活用しています。

# 2. 問題点
## 2.1 権限問題
1.2権限にて権限表を掲載しましたが、では誰がどの権限を持つべきなのかというのは当然の疑問のように思われます。現状は、データ分析業務、基盤運用業務に携わっており作業上必要な方に必要な権限を付与しています。場当たり的な対応ですが、一方で実情としてこれといった基準を決めかねているのも事実で、どうにかしなければと思いつつもこのような運用に落ち着いてしまっています。

# 3. まとめ
今回は弁護士ドットコム社におけるデータ分析基盤を紹介しました。データレイク、データウェアハウス、データマートといった3層の大掛かりな構成としましたが、運用してみて初めて見えてきた問題もありました。データレイクをベースとした分析基盤は適切に利用しなければデータスワンプ(沼)となって使い物にならなくなると言われており、そうならないように運用していきたいと考えております。
【Rails】Not Null制約とpresence: trueの違い【初学者の疑問点を簡潔に解説】

## はじめに
　本記事は、プログラミングの学習を始めて1ヶ月の初学者が、学習を進めていて疑問に思った点について調べた結果を備忘録も兼ねてまとめたものです。
　そのため、記事の内容に誤りが含まれている可能性があります。ご容赦ください。
　間違いを見つけた方は、お手数ですが、ご指摘いただけますと幸いです。

## 今回の疑問点
　今回の疑問点は、

　　_Not Null制約とバリデーション（`presence: true`）の違い_
　
　です。　

 　以前、テーブル定義を考えていた際に疑問を抱きました。

## 疑問点についての解説

###結論

`Not　Null制約`：データベースの項目に付与するNullに対する制約。Nullを拒否、空文字は拒否しない。
`presence: true`：モデルへのバリデーション。Null及び空文字を拒否。


###空文字とは
`空文字`：　長さ0の文字列

`Null`：何も存在していない

cf. `空白`:半角スペース、全角スペース

###Not Null制約とバリデーション（`presence: true`）は両方指定することができる
調べたところ、バリデーションはトラフィックが多い場合に不正な値がすり抜けてしまうことがあるようで、すり抜けても対処できるようにNot Null制約とバリデーションの両方を設定しておいた方が良いようです。



## まとめ
最後にポイントをまとめます。

- Not Null制約とバリデーション（`presence: true`）の違いは空文字を拒否するか否か
- バリデーションは不正な値がすり抜けてしまうことがあるので、Not Null制約とバリデーションの両方を設定した方が良い
エンジニアの給与における地域間格差

# はじめに
[UdonTech Advent Calendar 2021](https://qiita.com/advent-calendar/2021/udontech) の13日目です。

地方のエンジニアや開発会社社長たちと話していたとき、地方ってエンジニアの単価が安いよねって話になったので、どんなもんかなと思って調べてみた。

# 相場
#### フリーランスの場合
あるニアショア系のメディアによると東京を 1.00 とした場合、エンジニアの単価の地方格差は神奈川の 1.00 から青森の 0.65 まで。
全国平均で 0.80 となるそうな。
https://devsamurai.vn/ja/blog-ja/オフショア開発とニアショア開発/

また、全国展開しているエージョントの PE-BANK さんやフリーランス案件の色んなサイトを横断しているフリーランススタートさんで都道府県別に案件を絞ってみてもだいたいそんなかんじ。
https://pe-bank.jp/
https://freelance-start.com/

東京に比べると「同額より少し安く、半額より少し高い」くらいのレンジにだいたい収まる。
ざっと7掛け、8掛けといったところか。

#### 正社員の場合

色んなサイトでいろんな統計が披露されているが、ざっと見たところ東京（というより関東）が年500万円代なかば、それ以外の地方が年400万円代なかばというところが多く、これもおよそ8掛けといったところか。

# 所感
地域間格差はおよそ 0.8 ということは、言語やフレームワークなど技術による差よりは大きいが、年齢や職種、企業の儲けに比べればその差は小さいようだ。
ElectronとNode.jsの制約に苦しめられた話

# 注意事項

Electron初心者なので、間違った情報があるかもしれません。
タスクに追われてるので文章がちゃんとしていない可能性があります。
コードを引っ張り出してくるのが面倒だったので、コードは1行もありません!
ご了承ください。:bow:

## バージョン情報

詳しくは覚えていないのでメジャーバージョンのみ
Node.js v16.x
Electron v15.x

# 経緯

## Electronを採用した理由

- ブラウザの技術でデスクトップアプリを作れるから 
- 実績がある（VSCode、Slackなど） 
- 並列処理もなんとかできると思ってた  

あまり深く考えずにElectronを採用しましたが、これが原因で後々苦しむことになります...



# Electronの仕様

Electronは起動時に2つのプロセスを立ち上げます。

メインプロセスとレンダラープロセスの2種類があります。（参考: https://www.electronjs.org/ja/docs/latest/tutorial/process-model）

また、プロセス間の通信にはIPC（プロセス間通信）を用います。
ElectronにはそのためのAPIが既に用意されています。

なぜこのような仕組みになっているかと言うと、1つのプロセスで様々なことをできるようにするとセキュリティ的によくないからです。
複数のプロセスに分けて、プロセスごとにできることを制限することでより安全にしています。

## メインプロセスについて

Node.js上で動作し、アプリのウィンドウ管理やバックグラウンド処理等を行います。

### 何ができるか?

ストレージにアクセスしたり、コマンドを実行したり、ざっくり言うとネイティブのことはここでします。
また、

### 制約

自分がぶち当たった制約の中で印象深かったのは以下のとおりです。

- メインプロセスで動作が停止すると、レンダラープロセスも停止します
    - 常時バックグラウンドで動き続けるような処理はメインプロセスではできないはず
- ブラウザにあるようなプロンプトがセキュリティの関係上使えない
    - 代わりにレンダラープロセスをもう一つ生やしてプロンプトの機能を実装してる人もいる（https://www.npmjs.com/package/electron-prompt）
- 並列処理が辛い

## レンダラープロセスについて

Chromium上で動作し、ウェブベースのUIを提供します。

### 何ができるか?

ほとんど通常のブラウザとは変わりません。
追加の機能としては、メインプロセスと通信できるようにしてメインプロセスに定義したイベントを実行させることができます。
また、`webview`タグを使用できます。

### 制約

自分がぶち当たった制約の中で印象深かったのは以下のとおりです。

- セキュリティの関係上、デフォルトではNode.jsの機能を呼び出せない
    - `nodeIntegration: true`にすればできる（昔のやり方、セキュリティ上よくない）
    - レンダラープロセスから分離したコンテキストに必要な機能をプリロードして使用する方法もある（新しいやり方、こっちを推奨してるっぽい）

## その他

- Electronでデータ保存するライブラリでまともそうだったのがほとんどJSONに保存するタイプだった
    - 本当はデータベースに保存したかった...

https://github.com/sindresorhus/electron-store



# 並列処理が本当に辛かった

上記の制約は全部なんとかすることができました。
ただし、並列処理だけは本当に辛かったです。

## 並列処理の方法ググってみた

https://www.electronjs.org/docs/latest/tutorial/multithreading

https://medium.com/swlh/how-to-run-background-worker-processes-in-an-electron-app-e0dc310a93cc

色々ググったのですが、あんまりしっくりくる方法ではなかったです。

## 実際にどうしたか

上記のElectron公式ドキュメントにもある通り、Node.jsでもWeb Workerが使えます。
ただし、Web Workerでググってもあんまり参考になる情報がありません。
というのも、Node.jsのドキュメントを見ると`worker_threads`というモジュールになっていて、Web Workerという呼ばれ方はされていないからです。

https://nodejs.org/api/worker_threads.html

情報が少なかった上に、動作する保証がないのでこの方法で行くと決めるまでには2,3日かかりました...。

### 環境変数が使えない

まさかの環境変数が使えませんでした。
メインプロセスでは`process.env.NODE_ENV`のようにすれば環境変数にアクセスできますが、新しく作ったスレッドには環境変数が何も格納されていません。

どうしたかというと、メインプロセスでスレッドを生やすときに環境変数を渡して、生やしたスレッドの`process.env`をオーバーライドしています。
脳筋ではありますが、メインプロセスから分岐したスレッドは別のJS環境として動いているのでこうするしかありません。



# まとめ

苦労したーってことをひたすら書いただけの文章になってしまいましたが、まとめると以下のとおりです。

- Node.jsでマルチプロセッシングするのはそこそこ辛いのでやめておいたほうがいい
- Electronはウェブベースで凝ったデザインにできるけど、その代償として色々辛いことがある
    - 割と関連ライブラリがメンテナンスされてない
    - パフォーマンスが悪い
    - 回りくどいところがある
    - CSS辛い
- 正直、ウィジェット・ツールキットやそのラッパーを使って作るのが楽

https://ja.wikipedia.org/wiki/%E3%82%A6%E3%82%A3%E3%82%B8%E3%82%A7%E3%83%83%E3%83%88%E3%83%BB%E3%83%84%E3%83%BC%E3%83%AB%E3%82%AD%E3%83%83%E3%83%88

Node.jsは色んなことができて汎用性が高いのはそうなんですが、こういう問題にぶち当たるので適切な言語・フレームワーク等を用いたほうがいいなと思った（戒め）
みなさんも技術選定には気をつけてください。ゴリ押しでなんとかなることもありますが、かなり辛いです。
[ServiceNow]ナレッジ記事のバージョン管理方法

今日もナレッジ管理関連について執筆します。
今回はナレッジ記事のバージョン管理方法についてです。

#ナレッジ記事のバージョン管理方法

##Version
- Rome

##バージョン管理なし
ますはバージョン管理なしのナレッジ記事の修正方法について説明します。
自分が書いたナレッジ記事に遷移します。そこで[編集]ボタンをクリックします。
![ナレッジ記事１.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/cb56f0bd-f7da-0987-6355-6781f3e3e0ab.png)

変更を加え[更新]ボタンをクリックします。
![ナレッジ記事２.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/8f05fb4f-8c06-1755-17d0-c8ab363cb1db.png)

##バージョン管理あり
ナレッジ記事のバージョン管理を行うには、まずは以下のpluginを有効化する必要があります。
- Knowledge Management Advanced Installe（ID：com.snc.knowledge_advanced.installer）
![ナレッジ記事3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/6ec58ae4-c355-e420-be5b-1c8eba474a18.png)

プラグイン有効化後、ナレッジ記事に遷移し、[編集]ボタンをクリックします。
![ナレッジ記事4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/2f02bc56-09b9-9665-c599-ca16a04a1b30.png)


先ほどはなかった[チェックアウト]ボタンが表示されているのがわかると思います。
また、左上に記事のバージョンも表示されているのに気づきます。下の図は、"v1.0"です。
[チェックアウト]ボタンをクリックすると、
![ナレッジ記事5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/470dd1c7-2cbd-c56d-ce03-46781c0be907.png)

バージョンが、"v1.01"になります。記事に変更を加え[公開]ボタンをクリックします。
![ナレッジ記事6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/ce42d42f-bf3d-6833-4aac-3b302ea241dc.png)

前のバージョンの記事に遷移するので、[この記事の最新バージョンを利用できます。]リンクをクリックします。
![ナレッジ記事7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/e998e041-a62c-6304-9fe6-324069e4e318.png)

最新のバージョンの記事に遷移します。[最新バージョン]リンクをクリックします。
![ナレッジ記事8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/50bc0cc0-a3b9-e8ac-e1c1-b65f42ef3243.png)

バージョン履歴が表示されます。"v2.0"に更新できました！
![ナレッジ記事9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636124/4080f18b-722d-680a-5055-f32c9163e544.png)
[Windows/WPF] バックグラウンドプロセスを作ってみる(.NET5版)

もくじ

https://tera1707.com/entry/2022/02/06/144447

- **バックグラウンドアプリ関連記事**
    - [バックグラウンドプロセスを作ってみる](https://zenn.dev/tera1707/articles/b961d9810d45f9)
    - [バックグラウンドプロセスを作ってみる(.NET5版)](https://qiita.com/tera1707/items/4d2cc7c55a6df4c1aa62)
    - [バックグラウンドプロセスを作ってみる(.NET5版 別解)](https://qiita.com/tera1707/items/c48f13ea01c8615136cb)
    - [バックグラウンドプロセスを作ってみる(.NET8版 別解2)](https://tera1707.com/entry/2025/05/14/230730)


# やりたいこと

以前`.Net Framework4.7.2`で、バックグラウンドのプロセスを作成した。
それを.NET5で作ろうとしたら、そのままのやり方ではうまくいかなかったので、.NET5でのやり方をメモ。

# 手順

1. 「WPFアプリケーション」を選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352601/41374a9e-02bb-b3e1-c7ac-428fe419262a.png)


1. ターゲットフレームワークで「.NET5.0」を選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352601/aa48712f-edaa-1872-28cc-972e28968bc1.png)

1. プロジェクトのcsprojファイルをエディタで開いて、`<PropertyGroup>`の中に、
`<EnableDefaultApplicationDefinition>false</EnableDefaultApplicationDefinition>`を記入する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352601/d738f168-535a-f3e6-ba79-c341b59dbb00.png)


1. WindowlessAppプロジェクトのApp.xamlのビルドアクションをPageにする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352601/039fc8bc-859a-5ba1-7a65-661b3a866993.png)

1. App.xamlの先頭の<Window>にあるStartupUri="MainWindow.xaml"を削除
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352601/4cb8ec63-4b5f-e32d-90d3-85a2a2ad5fa1.png)

1. App.xaml.cs に '[STAThread]' をつけてMainメソッドを作る

``` App.xaml.cs
using System;
using System.Windows;

namespace WpfApp9
{
    public partial class App : Application
    {
        [STAThread]
        public static void Main()
        {
            App app = new App();
            app.InitializeComponent();
            app.Run();
        }
    }
}
```

これで、裏で動く.NET5版プログラム完成。
ただ、このままだと終わらないプログラムになるので、終わらせる処理のテンプレとして、下記に「起動してから10秒後に終わるバックグラウンドプロセス」のひな型を置いておく。


``` 起動10秒で終了するApp.xaml.cs
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;

namespace WpfApp9
{
    public partial class App : Application
    {
        [STAThread]
        public static void Main()
        {
            App app = new App();
            app.InitializeComponent();

            Task.Run(() =>
            {
                Thread.Sleep(10000);
                App.Current.Dispatcher.Invoke(() =>
                {
                    Application.Current.Shutdown();// ★これでアプリ終了する
                });
            });

            app.Run();
        }
    }
}
```

# 注意

csprojへの追記をする前にビルドアクションを変えてしまうと、このようなエラーがでる。
(これが、.NetFW4.8でやったやり方そのままを.NET5でやったときに詰まったところ。)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352601/99d3ba65-a9c7-9d89-9af0-47afdfac11d4.png)
必ずcsprojを変更してからビルドアクションを変えること。

# 参考

こちらの記事を参考にさせて頂きました。ありがとうございます。

https://qiita.com/satodayo/items/3ad889397c7b4842ea47
大量データ取得機能でのボトルネックが意外だった話

とあるバッチで、OracleDBから複雑なクエリで5000万件ほどデータを取得する部分が長時間処理になっていて問題になっていた。

実行計画をあれこれ解析しても特に改善せず、お手上げかと思っていたが、
バッチの実行ログをみるとクエリの実行には時間がかかっておらず、
その後のフェッチで時間がかかっていることが判明。

なんだよ、実行計画解析意味なかったじゃねーかよ、と思いつつ、
フェッチに時間かかっているなら5000万件だしどうしょうもないかな・・？
と思いつつ、ふとフェッチサイズが気になって調査したところ、JDBCのデフォルトで10に設定されていたことが判明

10！？

試しに、この値を100に上げたところ圧倒的に速度改善！（数時間→数十分）
その後、1000にしたところ10分ちょいにまで改善。

そりゃそうだよね。
フェッチサイズ10ということは、5000万件のデータを取得するのに500万回DBサーバにアクセスしてるんだもんね。1回あたり数ミリ秒でも数百分だよね。。
フェッチサイズ100なら50万回だから450万回も減るよね（1000なら5万回・・）。
もちろん、1回あたりの取得データ量は増えるから1/10にはならないけど、1回のアクセスごとに固定でかかる時間ってそりゃきっとあるよね。

「大量データ取得処理が遅い＝実行計画改善が必要！」というのが固定観念だったと思い知った、いつだかの思い出。

ただし、フェッチサイズを上げすぎるとOracle側での大量メモリ確保が必要になるらしいので注意。
失敗経験を面談で言えない人

SE面接を受ける際、あまり失敗談を話してはいけないと考える人がいる。
この人は失敗する人だと思われる、と考えてしまうようだ。

だが、普通に考えれば何も失敗せずに成長する人間はほとんどいないわけで、どんな失敗を経験してそこから何を学んだのかがその人の力量を構成していると言っても過言ではない。
なので、まともな面接官なら、逆に失敗（と本人が感じている）経験がほとんどない人は、逆にどうなの、と思ってしまうはずだ。

例えば、初めてマネージャーを経験した案件について、

A）特に問題なくリリースに至りました。メンバーの管理も特に苦労しませんでした。

B）スキルアンマッチなメンバーがいたので、勉強会を開いたり、タスクの割り振りを工夫したり、他のメンバーでフォローする体制を取ったりしましたが、結局最後までパフォーマンスが上がってこず、他のメンバーに残業などで大きく負担をかけてしまいました。スキルアンマッチだと分かった時点でメンバーチェンジを図るような対応も考えるべきだったと感じました。

ということを言われた場合、成功談なのはA)の方だが、B)の方がいろいろ考えて手を打てる人なのではないかと感じる。
成功談でも、どういう点で苦労してどういう対応をして結果成功に導けた、という話ならよいのだが、それがないと、たまたま条件、環境が良くて成功したと聞こえてしまい、力量がまったく伝わってこない。

せっかくいろいろ失敗したり苦労したりした経験を持っているのに、それを隠して「難なくうまくできました」と聞こえる話に構成してしまうと、逆に損をしている・・・気がする。
もちろん低レベルの失敗談だと加点要素にはならないが、何もないと話に深みがない。
ターミナル上でポーカーのヘッズアップがしたい

こんにちは！株式会社アトラエで「転職サイトGreen」のエンジニアをしている浅水です。

この記事では、僕がポーカーのヘッズアップを愛用のターミナル上でやってみたい！！と夢見そして、
半分成功、半分夢半ばで挫折した話を書いていきたいと思います。

## 作ったもの
![gamen_test1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1743458/565d7d24-7ac5-4f35-e828-29ab4d80ea2e.gif)

こんな感じで、**[go_poker](https://github.com/klein-mask/go_poker)**というTUIで起動するポーカーゲーム（と言えるほどのクオリティではない）を作ってみました。

### 使用したもの
- **Go 1.17**
- **[tview](https://github.com/rivo/tview)**
    - TUI作成のライブラリ的な

### できること
- ターミナルでテキサスホールデムのヘッズアップがなんとなくできるよ


## モチベーション
今回作成するにあたっては、大きく以下の２つのようなモチベーションで作りました。

- **Goのキャッチアップがしたい！！**
- **TUIアプリを作ってターミナル作業に疲れたら遊びたい！！**

１つ目のGoのキャッチアップに関しては、
僕がアトラエにJoinしたのが今年の7月なのですが、前職では主にインフラの領域を触っていたということもあり、
Greenで使用される技術の１つとして、完全初心者であるGoのキャッチアップをしたいと思ったからです。超絶シンプルです。

２つ目については、以前にQiitaで見かけた**[ファイルパーミッションでスロットがしたい](argocd2.staging.green-development.work/applications)**という記事に衝撃を受け、
自分でもTUIアプリを作っておもろいことがしたくなったからです。。

## TUIの画面構成
こんな感じでターミナル上で動くアプリをTUIアプリと呼ぶ（らしい）のですが、Golangには多数のTUI作成用のライブラリがありました。
[こちら](https://noborus.github.io/blog/go_tui/)の記事を参考にしつつ結論、新し目でイケてそうなやつということで今回はtviewを採用しています。

### Player & Enemy Table
![スクリーンショット 2021-12-13 21.04.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1743458/1e91d7e2-fa20-31e0-b27b-00e24ebf69c8.png)

見たまんまの情報ですが、ターミナル向かって左側がPlayer's Table、右側がEnemy's Tableとなっています。

| 名前 | 用途 |
|---|---|
|Hand| プレイヤーに配られた２枚のカードの内容（Enemy側はShowDown時にオープン） |
|Total Money | 残りの金額 |
|Bet| ベットしている金額 |
|Action | Fold, Call, Raise, Checkの各アクションとTUIを終了するQuit(Enemy側は存在しない) |

基本的にプレイヤーはActionのリストの中から選択して、ゲームを進行するような感じです。

### Center Table
![スクリーンショット 2021-12-13 21.12.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1743458/ed567839-80fa-0cf3-2751-3c411d3de29c.png)

プレイヤーに紐づかない情報や、ゲーム自体の管理に関する情報はTUIの真ん中に大きく枠を取ってます。

| 名前 | 用途 |
|---|---|
|Turn| ターンの進行|
|Pot| 溜まったPotの額（今回は両プレイヤーのベット数に等しい）|
|Flop| フロップのカード情報|
|Information| 現在の進行情報や手役の結果など|

## 半分挫折したとこ
今回かなり見切り発車で作ったこともあり、以下の課題点を残してます。

- 手役が同じ時に勝敗の判定がイカレる（くそ）
- Raiseする時にベット額指定できない
- Enemyのアクションがテキトーなランダム
- そもそもポーカー初心者なのでヘッズアップのルール的に合ってるか怪しい

この辺りは随時修正しつつ、特にEnemyのアクションなどは今後面白くしていけたらいいなと思います。

## TUIアプリを作ってみて
今までターミナルは好きであれどTUIアプリとか独自コマンドみたいのは全然作ってこなかったのですが、
ライブラリの充実により比較的簡単に且つ愛用ターミナルの上で自分のゲームが動くのはシンプルに楽しかったです！

とりあえず、**「疲れたからターミナルでポーカーで遊ぶ！！」**はできると思うので、よかったら試してみてください！
テクノロジーセンター活動の民主化について

# はじめに

こんにちは。エンジニアリング組織のマネジメント責任者、新井です。
この記事は、[mediba Advent Calendar 2021](https://qiita.com/advent-calendar/2021/mediba)  16日目の記事となります。


組織課題における課題解決については、マネージャーを中心に行っていましたが2021年4月より

* 誰でも参加が行える状態
* 個の総和で課題解決を行える状態

を実現するために運営を始めた、「センター活動の民主化」の取り組みについて紹介させて頂きます。

# なぜ始めたのか？
マネージャー主体での組織課題の解決では、

* 現場での課題から遠いケースがある
* 不透明及び健全性が担保されにくい
* 個の総和で成果を実現できていない

という3点が課題として顕在化してきた状況があったため、誰でも参加が可能な民主化活動を実施する流れとなりました。

民主化活動の実現にあたっては、エンジニアリング組織内での活動報告で以下のメッセージと共にメンバーの募集を開始しました。

# 民主化活動の内容
## 概略
マネージャーを中心としていたセンター組織の運営活動を、多様性/透明性を実現するためスタッフレイヤー含めたボトムアップの体制で活動できるよう組織変革を行う

## 目的
センタービジョンとして「良いものを届け続ける」ために個の総力を最大化させることでエンジニア組織としての成長を実現する

## ゴール
まずは、センター内における組織活動において、マネージャー含めスタッフ主導での課題解決推進が行える状態となっていること

## 活動概要
5つのチーム活動を進める

1. 採用チーム
1. 横断連携チーム
1. 教育/オンボーディングチーム
1. 技術力/ガバナンスの向上チーム
1. 評価制度チーム

## チーム内での役割/権限
* 役割
    * マネージャー（1〜2名くらい）
        * 推進体制のリード/フォロー、施策の検討/実施
        * 決裁（費用、役員方針、制度など）が必要なものがあれば対応
    * スタッフ（3〜4名くらい）
        * 施策の検討/実施
* 権限
    * マネージャー
        * 最終的なチームでの活動アウトプットに責任をもつ
    * スタッフ
        * 実施内容の意思決定（チームで意思決定）

## 活動に関わった評価について
活動における評価については、スキル評価にて加味

## 各活動におけるステップ
1. スタッフ募集/体制構築（3〜4人チーム目処。マネージャー除く）
    * 5月末くらい
1. 各個別活動における課題に対し、上期中のアクションプランの策定
    * 6月末くらい
1. 定期的な活動の実施
    * 週1くらい

## 活動詳細
### 採用チーム
#### 20年度でできたこと
* 採用プロセスの定義化

#### 課題
* プロセス周りは整備できたが、そのプロセスが実採用の効率化、質に向上する状態に紐付いていない
* 採用充足率が満たせていない

#### アクションプラン例
* 母集団形成の仕方（リファラル、ダイレクトなどで数を集める）
* 採用に繋がる広報活動を考える
* エンジニア採用専門の人員を補充
* etc

### 横断連携チーム
#### 20年度でできたこと
* スタッフを巻き込んだ活動
* センター活動報告会の運営
* [KGDC](https://kgdc.connpass.com/)
* [mediba Tech Cafe](https://mediba-tech-cafe.connpass.com/)

#### 課題（継続）
* 継続的に社外発信を行い、medibaの認知度/採用活動へ繋がる好循環を生み出すサイクルを実現する

#### アクションプラン例
* センター活動報告会の運営
* 一部エンジニアのみでの情報発信
* 社内外での範囲を広げる
* 継続的なアウトプットの仕組み
* etc

### 教育/オンボーディングチーム
#### 20年度でできたこと
* 新卒のOJT

#### 課題
* 入社時/社内での異動時に技術やサービスに関する情報/知識のキャッチアップがしづらく人材のアロケーションがしづらい

#### アクションプラン例
* 各プロダクトの技術/サービスの共有化
* 新卒/中途含めて、OJTが体系化
* etc

### 技術力/ガバナンスの向上チーム
#### 20年度でできたこと
* とくになし

#### 課題
* プロダクト毎での技術最適化が進んだため
    * 横断的なナレッジが溜まりづらい
    * 品質に対するガバナンスを効かせづらい
    * アーキテクトレイヤー毎の統制がとれにくい

#### アクションプラン例
* 技術採用方針（ガイドライン）の格子作成
* 各職能における領域の方針
* 主要言語くらいは銘打っておく（その限りでは無い、という注釈付き)
* etc

### 評価制度チーム
#### 20年度でできたこと
* スキル評価会の導入

#### 課題
* スキル評価会だけではカバーしきれていない評価の仕組みを整備する必要がある

#### アクションプラン例
* スキル評価のPDCAの実行
* グレード基準の細分化
* MGR/フェロー役割/評価定義
* etc

# 活動してみて

活動開始にあたっては、実業務で忙しいスタッフが参加してくれるのか、マネージャーで実施すべきなのではないかなどいろいろ不安なではあったのですが、当初チームとして集めたかった人数よりも多く、みんなが参加してくれる状況となり、目的としていた「マネージャー含めスタッフ主導での課題解決推進が行える状態となっていること」については早々に実現することができました。

これが本当によかったと思えたことになります。

上期が終わった時点では、各チームで各々のアウトプットがでている状況になりまして、下期に向けたアクションプランの組み立てまで実現でき、継続して各チームで組織課題の解決を行っている状況となります。

引き続き、よりよい組織運営、エンジニアが働きたいと思える組織になる様努めていきます。
共に課題と向き合い解決してくれる仲間も募集しております。

以上、ありがとうございました。

https://hrmos.co/pages/mediba/jobs
位置情報を使って観光案内LINE Botを作った話

#はじめに
位置情報を使って周辺の飯塚市おすすめ観光地へ案内するLINE Botを作成した。
この記事では、位置情報を簡単に送る方法と、ユーザから送ってもらった位置情報をデータベースに保存せずにメッセージやりとうりをする方法を説明する。

# 作ったBot
福岡県飯塚市のおすすめ観光スポットを案内するBotを作成しました。

ドコイコ飯塚

![192smtmm.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12297/ff389f3d-207a-4595-109d-e5ceb02e9bcc.png)


# 位置情報の送り方
LINEで位置情報を送ろうとするとメッセージ送信画面で「＞」→「＋」→「位置情報」とタップせねばならず、送り方を知らない人も多い。
このBotでは位置情報の送り方をわかりやすくするため、リッチメニューに「位置情報を送信」ボタンを設置して、LINE URLスキームをリンクするようにしている。

[LINE URLスキームでLINEの機能を使う](https://developers.line.biz/ja/docs/messaging-api/using-line-url-scheme/)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12297/b0e0a9aa-5d63-2422-d39c-d951cdb4c8c9.png)

# 送られた位置情報の取り扱い
このBotでは位置情報をもとに、周辺の観光地をおすすめしてそこまでの経路をGoogleMapを使って案内する。
手順としては、「位置情報の送信」→「カテゴリー表示」→「周辺観光地を表示」→「GoogleMapを表示」となるため、初めに送ってもらった位置情報を、何かしらの方法で受け渡してやる必要がある。
データベースに入れる方法もあるが、どのタイミングで位置情報を削除するのかや、そもそも機微な情報をアプリに持ちたく無いので、データベースを使わずに送られた位置情報をポストバックアクションのdataに入れたカルーセルを作成して位置情報を受け渡している。

[ポストバックアクション](https://developers.line.biz/ja/docs/messaging-api/actions/#postback-action)


```python
    image_carousel_template_message = TemplateSendMessage(
        alt_text='ImageCarousel template',
        template=ImageCarouselTemplate(
            columns=[
                ImageCarouselColumn(
                    image_url='https://storage.googleapis.com/xxxx/cafe.jpg',
                    action= PostbackAction(
                        label='食事',
                        text='食事',
                        data=geodata  + ',食事'
                    )
                ),
                ImageCarouselColumn(
                    image_url='https://storage.googleapis.com/xxxx/history.JPG',
                    action=PostbackAction(
                        label='観光',
                        text='観光',
                        data=geodata + ',観光'
                    )
                ),
                ImageCarouselColumn(
                    image_url='https://storage.googleapis.com/xxxx/gift.jpg',
                    action=PostbackAction(
                        label='お土産',
                        text='お土産',
                        data=geodata + ',お土産'
                    )
                )
            ]
        )
    )
```
codecommitにて、gitをpushするまでの、道のり。

#はじめに
codecommitにて、gitをpushするまでの、道のり。

# 最終更新日
2021年12月13日

# 環境の情報
OS
Ubuntu20.04

# 注意
最新の状態を確認して下さい。

# 公式はこちら
https://git-scm.com/

https://docs.aws.amazon.com/ja_jp/codecommit/latest/userguide/troubleshooting-ssh.html

#注意
ブランチがmasterとなっています。

#実際にやってみます

リポジトリをクローンします。
空っぽのままの状態です。

```
作っていいところへ移動する。
$ git clone ssh:git-codecommit.XXXXX.amazonaws.com/v1/repos/test（リポジトリ名）
Cloning into 'test（リポジトリ名）'...
warning: You appear to have cloned an empty repository.
```

いることをかくにんします。

```
$ ls
test（リポジトリ名）
```

ブランチはまだこざいません。

```
$ cd test
$ git branch
```

いじるひとの名前を登録します。

```
$ git config --global user.name User
```

メールアドレスを登録します。

```
$ git config --global user.email XXXXX@.co.jp
```

登録されたか確認します。

```
$ git config --global --list
user.email=XXXXX@.co.jp
user.name=User
core.editor=vi
```


試しにハローワールドでも書いてみます。

```
$ echo 'hello world' > README.md
```

アドします。

```
$ git add .
```

コミットします。

```
$ git commit -m "first Commit"
[master (root-commit) XXXXXX] first Commit
 1 file changed, 1 insertion(+)
 create mode XXXXXX README.md
```

ログをみます。

```
$ git log
commit XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX (HEAD -> master)
Author: User <XXXXX@.co.jp>
Date:   Mon Dec 13 15:18:30 2021 +0900

    first Commit
```

マスターがいるのを確認します。

```
$ git branch
* master
```

プッシュします。
特にエラーなど出なければ問題ありません。

```
$ git push origin master
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 223 bytes | 223.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To ssh://git-codecommit.XXXXX.amazonaws.com/v1/repos/test
 * [new branch]      master -> master
```
Solanaでstakingしてみる

## はじめに

https://qiita.com/hhatto/items/d52b58aec86d1c89575f

Solanaさわった続きでStakingしてみます。

## 環境

Rust 1.57 stable
MacOSX 11.6 (Intel Mac)
Solana(CLI) solana-cli 1.8.6 (src:e5aa5efb; feat:591501692)

あとは前提として開発用のdevnetを使っています。

## 準備

stake用のアカウントを作成する必要があるのですが、その元となるアカウントをまず別で作成します。

```shell-session
$ solana-keygen new --no-passphrase -o stake-account.json
Generating a new keypair
Wrote new keypair to stake-account.json
====================================================================================
pubkey: HeNhXBGNr8dW1P8RPocDEpj7DvFtGPBYnAH9BeZBskzi
====================================================================================
Save this seed phrase to recover your new keypair:
melody struggle rescue tornado exotic erode delay ocean battle critic symptom couple
====================================================================================
```

数SOLステーキング予定で、stake元となるアカウント、手数料払うアカウントすべて前回作成した `DmAUUA2Rw1yXhstczJgRQYXBB3GrsesUhTvSVkzGfWWe` アカウントで行う予定なので、`airdrop`しておく。

```
$ solana airdrop 2 DmAUUA2Rw1yXhstczJgRQYXBB3GrsesUhTvSVkzGfWWe
Requesting airdrop of 2 SOL

Signature: 2mjCGJgbfwZUJsAUqScwcTmJmhAqPQVXtXaxxUKL2JbSN6Aj4Rv9VemJMQnNrqwfkywA2hE9SU1H6f4VrpF4q7Ga

2.499995 SOL
```

## stake用アカウント作成

```shell-session
$ solana create-stake-account --from ~/.solana/test-keypair.json stake-account.json 1 --stake-authority ~/.solana/test-keypair.json --withdraw-authority ~/.solana/test-keypair.json --fee-payer ~/.solana/test-keypair.json --seed aaa

Signature: 2cqkvUYpjCaxTDPxFgTPezrcUpEQj2SwoYUumzFHF31n5RmJVjEek3MwMLBpbMoerkZGoyEYhGWwbP5QeX5NffJJ
```
`--from` でstake原資払う人。
`--seed` は適当。
`~/.solana/test-keypair.json` は前回作ったアカウント `DmAUUA2Rw1yXhstczJgRQYXBB3GrsesUhTvSVkzGfWWe`。

エクスプローラーで確認

https://explorer.solana.com/tx/2cqkvUYpjCaxTDPxFgTPezrcUpEQj2SwoYUumzFHF31n5RmJVjEek3MwMLBpbMoerkZGoyEYhGWwbP5QeX5NffJJ?cluster=devnet

![create-staking-account.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1775/f9479f79-30a0-4912-421c-260894bb0dbd.png)

`2Za8hkBAGiMtGRoa8bg7SeL7vBgYn6TetjNqseSL7p2x` が対象のアドレス

生成されたstake用アカウントのアドレスを閲覧してみる。

```shell-session
$ solana stake-account 2Za8hkBAGiMtGRoa8bg7SeL7vBgYn6TetjNqseSL7p2x
Balance: 1 SOL
Rent Exempt Reserve: 0.00228288 SOL
Stake account is undelegated
Stake Authority: DmAUUA2Rw1yXhstczJgRQYXBB3GrsesUhTvSVkzGfWWe
Withdraw Authority: DmAUUA2Rw1yXhstczJgRQYXBB3GrsesUhTvSVkzGfWWe
```

ここまでOKなはず。めちゃ簡単。
Delegate Stake(委任ステーク)とかもできるらしい。

devnetでも増えるのかな？数日してから確認してwithdrawとかやってみる予定。

## 参考
* https://docs.solana.com/cli/delegate-stake
開発環境だと思ったら・・・

# なにがおきた

「よーし、バッチ処理の改修完了したから、開発環境で流してみるか〜」
「ターミナルからポチーっと」
「あれ？開発環境のデータ全然変わんないなあ」
「なんか本番アラートめっちゃきた！何で！？」
「あっ・・・」

# どうしてそうなった

本番環境のターミナルで実行してました

# どうすればよかったのか

- 本番環境を開きっぱなしにするのはやめましょう
- 環境ごとにターミナルの色を変えてわかりやすくしましょう
kintoneでIot！M5StickCをノーコードで設定［土壌水分編］アナログセンサー

土壌水分センサーのデータをkintoneにレコード追加
------------------------
M5StickCで「土壌水分センサー」を使用しkintoneのアプリにレコードを追加します。
今回は「観葉植物への水やり」をkintoneでグラフ表示してみました
![kintone1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228252/2305cc15-c5cb-325d-a757-58d3d9c5f8ca.png)

水分センサーとM5stickCを接続
---------------------------
Capacitive Soil Moisture Sensor v1.2「静電容量式土壌水分センサー」
電極が腐食しにくい構造です。
　※今回は付属のケーブル（メス―メス）ではM5stickCに差込めないので使用しません
![senser3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228252/8c835efc-f47b-f871-3a5d-96f5459579c3.jpeg)


ジャンパーワイヤ（メス-オス）でセンサーとM5stickCを接続します

| センサー |  | M5stickC |  
|:-:|:-:|:-:|
|  GND |   | GND  | 
|  VCC |   | 5V→  | 
|  AOUT |   | G36  | 

このように接続します
![senser4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228252/3902e537-8275-fa6c-580b-2cef6ad04d33.jpeg)


M5stickCをノーコード（UIFlow）で設定
-------------------------------------
Capacitive Soil Moisture Sensor v1.2はセンサー値がアナログ出力されます
M5stickCの36ピンからアナログ値を読み取ります
「1秒間隔でセンサーの値を表示」してみます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228252/227a1349-37b5-16d2-af93-57b5ad3f4a52.png)

このようにセンサーが乾燥状態（水分に触れていない状態）では、
センサーの値が最大値として1023を表示させます。
センサー部に水分が触れるとその度合いによって抵抗が増しセンサーの値が下がります
![IMG_4862.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228252/9e04355a-d8dd-e296-c891-929be160e609.jpeg)
センサーの値が表示できることを確認できれば、この値をkintoneにアップする設定を追加してみます

kintoneにレコード追加
-----------------------

「wifiに接続」し「10分間隔で値を表示」すると同時に「kintone（アプリ番号104）にレコード追加」
とした場合は次のようになります
![app.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228252/9814ae69-bee9-f125-7097-3614e6f3bd37.jpeg)

観葉植物の土壌水分はセンサー設置時に925でした。
水やりを行うと一時的に700まで下がり750あたりに落ち着くことがわかります。

![mizuyari.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228252/193358dc-1eaa-f30f-7ab7-da780594b264.jpeg)

センサーの値をそのままグラフにしていますので「乾燥の度合いを見る」という表現が適しているかも

UIFlowの設定は前回の記事も参考に

https://qiita.com/yama_moto250R/items/a3b81806c52b8d91e759

次回は
-------------
防水型のデジタル温度センサーを使った
「kintoneでIot！M5StickCをノーコードで設定［土壌温度編］デジタルセンサー」
の予定です

追加しました。

https://qiita.com/yama_moto250R/items/b622a92b79e8f19fb5a7
1年越しのCRONがサービスを落とした話

# なにがあったのか

平穏であるはずのとある平日の朝、サービスダウンのアラート通知がきました。
特に最近何かのリリースなど行っていなかったので、インフラ的な障害かアタックかを最初疑いました。
調べてみたところDBが負荷が異常に上がっていて、何も処理を受け付けない状態になっていました。

# どうしてそうなった

何のプロセスが走っているのかSQLのプロセルを確認したところ・・・、同じ処理が二重に実行されていました。
バッチサーバのプロセスをみると、深夜に動く重たい集計処理が二重に実行されていました。
どうしてこうなった？と思ってcronの設定をみたところ・・・。

**デイリーの集計処理の設定に加え、1年前の今日に設定した、「月日時分」で設定した集計処理の設定がありました。**

思い起こせば1年前、集計処理の改修を行い、初めて本番で実行する前日に、もしかすると想定以上に処理時間がかかるかもしれないので、元々のデイリーのcron設定をコメントアウトして、次の日のいつもより3時間早い時間に「月日時分」を設定していたのでした。

翌日、元々のデイリーのcron設定のコメントアウトを戻したものの、「月日時分」で設定した部分は消さずにそのままにしていたようです。

そのバッチ処理も排他制御などかかっていなかったので、起動すれば同時に動かせる状態になっていました。

# どうすればよかったのか

- cronの設定は定期的に見直しましょう
- できればcronではなく、GUIで管理できるようなタスクスケジューラを入れましょう
- 同時に実行されないよう、バッチ処理には排他制御を入れましょう
cron

本日ちょっとcronがうまく読めなかった。。。

曜日を月曜日から金曜日
土日を変えるなんてこともやっている。

うーん。cronも深いな。
結果を
> /dev/null 2&>1もOK

https://www.server-memo.net/tips/crontab.html
Dynamics 365 Finance and Operations ~ Inventory Visibility Add-in（在庫可視化アドイン）~

おはこんばんちは。
2021年Wave1でリリースされた Inventory Visibility Add-in について少し調べてみました。

https://docs.microsoft.com/ja-jp/dynamics365-release-plan/2021wave1/finance-operations/dynamics365-supply-chain-management/inventory-visibility-add-in-dynamics-365-supply-chain-management

> Inventory Visibility により、組織は最小限の設定でグローバルな手持在庫を管理できます。 この非常にスケーラブルなマイクロサービスは、さまざまなエンドポイントからの同時要求を処理できます。 この機能には、補助システムとの統合を簡単に行うことのできる使いやすい RESTful API が付属しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/2efe8477-d608-4929-0fe5-3eb47d0d3a0d.png)

どうやらこのアドインは、Dataverse 上に構築されており、Power Apps や Power BI を使用したシナリオでも特に力を発揮するようですね。
従来の手持在庫やInventory系の標準レポートよりも、以下の点で優位のようです。

#1. 拡張性
[シナリオ例]
・eコマースサイトで現在の在庫を照会できるようにしたい。
・D365 に限らず、その他のシステム（POS、3PL、WMS）を横断的に、一つのプラットフォームにまとめて、現在の在庫量を正確に把握したい。
・D365 Intelligent Order Management に対してリアルタイムの在庫情報を送ることでロジ担当がフルフィルメント業務を効率的に行えるようにしたい。

#2. リアルタイム性
[シナリオ例]
・フィールドエンジニアが D365 Field Service などを使って Work Order の作業を進める前に現在の手持在庫を知りたい。
・営業担当が出先でモバイル端末から現在の手持在庫を確認したい。

#設定・使用

まずその他システムとの連携する場合は、当然データソース連携が必要になります。階層構造も設定でき、見やすくなるだけでなく、パフォーマンスにも良いみたいです。
・分析コード (色、サイズ、スタイル、バッチ/シリアル番号、サイト/保管場所コード etc.)
・物理的測定（在庫ステータス etc.）
・計算メジャー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/5bfb8745-a135-44ea-0fd3-a1aee488318d.png)


Power Apps や 外部システム連携用のAPI のために、手持在庫を照会するクエリを定義できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/990a082e-230a-d305-8d1c-3489de17a171.png)

これは面白いのですが、仮引当（Soft Reservation）という機能を有効化すれば、このアドイン上で在庫引当を可能にできます。
引当の条件も細かく設定できるみたいですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/266462e9-c6ad-ce68-afc5-c6a707f4c5a0.png)

手持在庫画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/922623fb-a788-e22b-8c5f-61a3866f98e5.png)

Power Automate連携で常に最新の手持在庫を取得できる仕組みを作れるのもいいですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/27af1e3d-1c26-139f-6b66-b7fa542260b9.png)
【Rails】 超初心者向け！アプリケーションを作成する準備

#はじめに
私は２ヶ月ほど前からプログラミングの勉強を始めた、とてつもない初心者です。まず初めはみなさんご存知の[Progate](https://prog-8.com/)をやっておりました。ある程度履修を終えて、[現場で使えるRuby on Rails 5速習実践ガイド](https://www.amazon.co.jp/%E7%8F%BE%E5%A0%B4%E3%81%A7%E4%BD%BF%E3%81%88%E3%82%8B-Ruby-Rails-5%E9%80%9F%E7%BF%92%E5%AE%9F%E8%B7%B5%E3%82%AC%E3%82%A4%E3%83%89-%E5%A4%A7%E5%A0%B4%E5%AF%A7%E5%AD%90/dp/4839962227)を進めていました。その際に初心者すぎて困ったことをここで少しずつまとめていきたいと思います。
プログラミングの「プ」の字も理解していなかったり、元々PCの扱いが慣れていないと、とても小さいことでも分からないことがあったので、できる限り誰でも分かるように丁寧に説明していきたいなと思います。

※とてつもない初心者なので、ここはこうした方がいい等あると思いますが、その際は是非教えていただけたらなと思います！！



##バージョン
・Ruby 2.5.1
・Rails 5.2.6




##アプリケーションの雛形を作成する
###①コードエディターであるVSCodeを開き、新しいターミナルを開く
![Screenshot 2021-12-12 14.36.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2204487/b488a768-e923-c410-9d7f-398008795b4e.png)
開くと下部にターミナルが出てくる。
![Screenshot 2021-12-12 14.37.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2204487/060b12ce-c9b0-d8e8-b9ba-ed7fd7415abe.png)


###② ターミナルにRailsアプリケーションの雛形を作るコマンドを打つ
rails newコマンドで、アプリケーションの基本的なディレクトリ・ファイル類を一式作成します。

```
$ rails new アプリケーション名　[オプション]
```

コマンドを打つと以下のような内容が表示される。
![Screenshot 2021-12-12 14.37.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2204487/5e8c3d6b-e26f-0f6b-040f-90977394aaa8.png)

###③ 作成したファイル一式をVSCodeで開く
エクスプローラー（左の一番上のアイコン）押して、【フォルダーを開く】を押すとパソコン内のフォルダが開く。
![Screenshot 2021-12-12 14.48.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2204487/c99198de-f8fc-cc51-02ea-06ee2f4433f0.png)
自分がつけたアプリケーションの名前のフォルダが出てくるので、そのフォルダ（今回の例では「runmew」)を選択し、【開く】を押す。
![Screenshot 2021-12-12 14.48.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2204487/023e1d5d-21d3-cd2f-b8cf-a5b11a462b86.png)
VSCodeに以下のようにファイルを開くことができる。
![Screenshot 2021-12-12 14.48.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2204487/dd2d6cbb-91fe-0ab3-2e21-75fbd39acd84.png)

###④データベースを作成する
ターミナルにデータベースを作成するコマンドを打つ。

``` rails
$ bin/rails db:create
```
※このときにアプリケーションディレクトリに移動していないといけない



 今自分がどこのディレクトリにいるかどうかは、以下のコマンドを打てば分かる。

```
$ pwd 
```




ただ、コマンドを打たなくてもターミナルのある部分を見たら自分がどこのディレクトリにいるかは理解できる。
例えば以下のようにターミナルに表示された場合は、__「runmew」__というディレクトリに今いるということになる。

```
kuuuuu@Kuuuuu runmew $ 
```





###⑤サーバーを起動
ターミナルにサーバーを起動するコマンドを打つ


```rails
$ bin/rails s
```

ブラウザを立ち上げて（例：GoogleChrome)　http://localhost:3000 にアクセスする。
正しく動いていると以下の右のような画面が出る。
![Screenshot 2021-12-12 15.15.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2204487/53b71698-8130-53ab-55d7-ffb705c0a2c5.png)

サーバーは[Ctrl + C]を押すまで動作し続ける。


##オプションについて
以下の記事が非常に分かりやすかった。
https://pikawaka.com/rails/create_app

##データベースについて
オプションの中に利用するデータベースを指定するコマンドがある。
データベースについては以下の記事が分かりやすかった。
https://www.bold.ne.jp/engineer-club/type-of-database
https://news.mynavi.jp/siryou_hikaku/20201023-1386925/


#おわりに

今回の内容は[現場で使えるRuby on Rails 5速習実践ガイド](https://www.amazon.co.jp/%E7%8F%BE%E5%A0%B4%E3%81%A7%E4%BD%BF%E3%81%88%E3%82%8B-Ruby-Rails-5%E9%80%9F%E7%BF%92%E5%AE%9F%E8%B7%B5%E3%82%AC%E3%82%A4%E3%83%89-%E5%A4%A7%E5%A0%B4%E5%AF%A7%E5%AD%90/dp/4839962227)のChapter3-1-1〜3-1-3 (P.82~85)です。
アプリケーションを作る際には誰でも行う作業だと思うので、スムーズにできることを祈ってます。
プログラミングが楽しくなるようにみんなで頑張りましょう！
Ubuntu20.04のwardenのmagentoの環境構築にて詰まったところ

#はじめに
Ubuntu20.04のwardenのmagentoの環境構築にて詰まったところを記載しました。

# 最終更新日
2022年3月4日

# 環境の情報
OS
Ubuntu20.04

# 注意
最新の状態を確認して下さい。

# 公式はこちら
https://docs.warden.dev/environments/magento2.html


# 参考さま
https://linuc.org/study/knowledge/507/


# 状況
Global Services
https://docs.warden.dev/services.html
Installing Magento 2
https://docs.warden.dev/environments/magento2.html
Automatic DNS Resolution
https://docs.warden.dev/configuration/dns-resolver.html

のドキュメントに従って、wardenにてmagentoの環境構築を行っていたが、
```
After running warden svc up for the first time following installation, 
the following URLs can be used to interact with the UIs for services Warden runs globally:
```
の個所が表示されない。
起動に成功したら、以下のURLで確認できるはずだが、どれを叩いても、アクセスできません、のようになってしまう。

・https://traefik.warden.test/
・https://portainer.warden.test/
・https://dnsmasq.warden.test/
・https://mailhog.warden.test/



![Screenshot from 2021-11-16 14-38-08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148394/dad10098-d3fb-64f4-1ecb-30e6a4eb621c.png)
しーん


# このようにしました

resolv.confに、nameserver 127.0.0.1　を加えました。

```
sudo vi /etc/resolv.conf
nameserver 127.0.0.1
```

>「/etc/resolv.conf」ファイルは、名前解決（ホスト名からIPアドレスを調べること）の設定を行うファイルです。
https://linuc.org/study/knowledge/507/

# 見れるようになりました
![Screenshot from 2021-11-16 16-51-33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148394/fb1a38ce-1b65-6b2b-b6b4-a595406eaa58.png)
【Tableau】FontList〜フォント全部試してみよう！〜

この記事は[Tableau Tips ＊ Tabjo Advent Calendar 2021](https://adventar.org/calendars/6202)の14日目の記事となります。

本日の記事はタイトル通り、FontListを作成しました！
今回これを作成した経緯としては、私が過去に更新した[記事](https://qiita.com/t_misaki1029/items/e13192105ebc81ed05a1)ではフォントタイプで悩んだ場合には
専門家が読みやすいとするものを活用するのが無難とお伝えしました。

>フォント
　・専門家が読みやすいとするフォントは以下
　　　Trebuchet MS or Verdana
　　　Arial
　　　Georgia
　　　Times New Roman
　　　Lucida sans

https://qiita.com/t_misaki1029/items/e13192105ebc81ed05a1


とは言え私自身が全フォントを見たことが無かったので、
今回全て試してみようというチャレンジです！！（2021/12月時点）
![イメージ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1537142/bc846d8c-43bd-2f56-3f37-091a5013ae05.png)

**ローマ字・ひらがな・カタカタ・漢字・数字**を記載しました。
フォントサイズは全て同一ですが、フォントの種類によって大きく見えたり、小さく見えたりするものがありました。

しかしこれをTableau Publicにパブリッシュしたところ、Tableau Desktop上のフォントタイプが上手く反映されない・・
調べてみたところ**TableauPublic・TableauOnlineでは日本語環境でサポートされているフォントが限られている**ようです。（悲しい）
詳細はTableau公式の**[こちら](https://kb.tableau.com/articles/issue/fonts-not-displaying-as-expected-after-publishing-to-public)**で確認できます。

なので、今後活用する機会がある方には、これを一度ダウンロード頂きDesktopで開いて頂きますようお願いします。（超面倒、ごめんなさい！）
**[TableauFontList](https://public.tableau.com/views/tableaufontlist/_AlBayanPUA_DamascusPUA?:language=ja-JP&:display_count=n&:origin=viz_share_link)**をTableau Publicに公開させて頂いたので、今後どこかで誰かのお役に立てば嬉しいです。

https://public.tableau.com/app/profile/misaki.takatsu/viz/tableaufontlist/_AlBayanPUA_DamascusPUA

そして今回参加させて頂いている[Tableau Tips ＊ Tabjo Advent Calendar 2021](https://adventar.org/calendars/6202)では面白いTipsが沢山あります！！
まだ見ていない方は是非とも見に行ってみてください。
はてブで組織的にブックマークしたら何も表示されなくなった話

# 何がおきてしまったか

はてブのホッテントリに乗ると集客効果が高いってことで、「みんなではてなアカウント作って会社のサービスブックマークしましょう！」という周知が社内でまわり、みんなその通りにしたら、その会社のサービスのドメインのブックマークがすべてはてブに表示されなくなりました。

# どうしてそうなった

はてブでは作為的にランキングを吊り上げるような行為を禁止しています。

[はてなブックマークにおけるスパム行為の考え方および対応について - はてなブックマークヘルプ](https://b.hatena.ne.jp/help/entry/spam)

IPなどを見ているのか、アカウントの動向などを見ているのか、１〜２日ですぐに表示制限措置の対象になりました。

# どうすればよかったのか

シンプルに他人を欺くような行為はやめましょう。
結局その後、はてなに謝罪文を書いて許してもらいました。

ちなみにその会社では他のサービスでも同じようなことをして同じようにBANされまくってました。
WebArena Indigo 環境設定１）TeraTermからログインするまで

　WebArena IndigoはVPSサーバとしては国内最安値だが、そのためにサポート体制が貧弱とのことだ。
　私はサーバ設定について初心者だが、WebArena Indigoでの設定方法について書き残しておくことにした。CentOS7、RockyLinux8、Ubuntu20.04LTSの3種類のOSで行なったので、これらの差異についても書いておく。

# コントロールパネルでの設定
　設定は以下に従ってやっていく。

コントロールパネルにログインする（Indigo）
https://help.arena.ne.jp/hc/ja/articles/360050605513/

SSH鍵を作成する（Indigo）
https://help.arena.ne.jp/hc/ja/articles/360049805674/

インスタンスを作成する（Indigo）
https://help.arena.ne.jp/hc/ja/articles/360049806534/

　ここでOSを選ぶようになる。

SSH接続でインスタンスにログインする（Indigo）
https://help.arena.ne.jp/hc/ja/articles/360049807634/

　ここにログインするために必要な情報は書いてある。

>ホスト名：作成したインスタンスのIPアドレス
パスフレーズ：空白
ポート：22
鍵：SSH鍵の秘密鍵（private_key.txt）
インスタンスのIPアドレスの確認方法：
[インスタンス管理]→[インスタンス]に移動し、作成したインスタンス名のIPアドレスの欄を確認してください。
ユーザ名：
CentOSの場合、centos
Ubuntuの場合、ubuntu
Rocky Linuxの場合、rocky

 しかし、ログインするための具体的な手順はサポート外ということで書いてない。

# TeraTermでの設定
　PC上でTeraTermを用いて以下の方法でログインできるようにした。

1.TeraTermを起動して最初に表示される「新しい接続」の画面で「Cancel」をクリックする。

![a1_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2384942/90df6580-ac72-7408-3706-0b0764637186.png)

2.ツールメニューの [設定(S)] から [SSH認証(A)] を選ぶ。

![a1_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2384942/f6d2c9ec-8446-4285-de5c-85336f78445e.png)

3.「SSH認証設定」画面で、[User name] にこの場合は「centos」または「rocky」または「ubuntu」を入力し、[Use RSA/DSA...] にチェックを入れ、ダウンロードした秘密鍵を指定する。「OK」をクリックする。


![a1_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2384942/9e074696-d086-bf9f-e6b9-8e020dd10a55.png)

4.TeraTermのツールメニュー [ファイル(F)] から [新しい接続(N)] を選ぶ。起動した「新しい接続」画面で、ホスト(T)にIPアドレス、TCPポート#(P)に22を入れる。「OK」をクリックする。

![a1_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2384942/6a113977-2d32-1d3c-2c42-3d2bfdddbb31.png)

5．「SSH認証」画面で「OK」をクリックする。

![a1_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2384942/3831de3e-4729-703c-29da-f436ab2f6d07.png)

6.TeraTermがWebArena Indigoの
/home/centos
に接続できる。

7.TeraTermのツールメニュー  [設定(S)] から [設定の保存(S)] を選んで、設定を保存しておく。



---

WebArena Indigo 環境設定2）ユーザ追加
https://qiita.com/naga_kt/items/c7b6e09e93570252314e
に続く。
Google Chat にDrive bot を追加して通知を受け取ろう


# はじめに
2021年[NI+C Advent Calendar 2021](https://qiita.com/advent-calendar/2021/niandc_teamgcp)の14日目です。
この記事はGoogle Workspace ユーザーを対象にしています。

+ **Google Chat でチャットはしているけど、bot を活用していない人**
+ **ドライブの通知を受け取りたい人**

よかったら最後までこの記事を読んでください。

# Google Chat にbot を追加してみる

**手順**
まず[Google Chat](https://chat.google.com/) アプリにアクセスします。
「チャットを開始」アイコンをクリックします。
![スクリーンショット_(4)_121321_060358_PM.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2365766/a457404b-6071-c4aa-ff5e-0b0fcb299f32.jpeg)

[bot を検索] をクリックします。
![スクリーンショット_(5)_121321_061746_PM.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2365766/fdab7250-33a2-1b7e-1425-7a5b4f4798cf.jpeg)

bot名[**Google Drive**]を検索するか、botのカードをクリックします。
![スクリーンショット_(7)_121321_062707_PM.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2365766/5e3e36b6-3a53-9c75-4377-e9e4b8d12453.jpeg)

[Chat]をクリックします。
![スクリーンショット_(8)_121321_061835_PM.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2365766/e336ccb6-7f31-05c7-46d9-0a1a2cc5f51b.jpeg)

メッセージが届くので、通知をオンにします。
![スクリーンショット_(9)_121321_063103_PM.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2365766/6b4116c0-4e30-8ca2-79e9-f24eadcaf785.jpeg)
手順は以上です。
**通知をオンにすることで、ドライブのアクティビティの更新にすぐに反応できますよ！**

# bot とのチャットから設定変更する
[**Google Drive**]botとのチャットルームからいつでも通知をオフにしたり、ドライブの設定変更が可能です。
![スクリーンショット_(10)_121321_063332_PM.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2365766/3d7ca52d-9fbe-63b1-5b36-fb0e796b7b93.jpeg)

[ドライブの設定]では、詳細な通知設定が可能です。
![スクリーンショット_(11)_121321_063447_PM.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2365766/c331b443-b6c0-4799-6719-eb7fb685472e.jpeg)

# さいごに
この記事では、Google Chat にDrive bot を追加して通知を受け取る方法をご紹介しました。
ほかにも様々なbotがあるので、追加して活用してみてください。

# 参考
[Google Chat で bot を使用する](https://support.google.com/chat/answer/7655820?hl=ja&co=GENIE.Platform%3DDesktop)
[Google が提供する Chat 向け bot](https://support.google.com/chat/answer/9649420?hl=ja&ref_topic=7649114)
探索的テストの進め方について

#はじめに
皆様本年もおつかれさまです。

今年は新規プロダクトのリリース前QAの業務を携わっており、
モバイルゲームで探索的テストを適用したときの工夫として、
テスト観点を明確にして精度向上をはかったときの話をできればと思います


#探索的テストとは
探索的テストとは、JSTQBでは「テスト担当者がテストアイテムや以前のテストの結果の知識や調査情報を使用して、
テストを動的に設計、および実行するテストアプローチ」と定義されているものとなります

最近だと一般的になってきたテストケースを用いたテストとは異なり、
テスト観点など準備した上で探索的に行うテストといったイメージです

その上で、それを取り入れて進めたときのモバイルゲームならではの注意点や工夫した点を次に纏めてみました

#実施目的を明確にしておく
まず初めに、探索的テストをする前に実施する目的を明確しておきましょう
目的を明確にしておかないと、ただとりあえず実施して終わりとなってしまうため、実施目的が果たせません
下記のように目的をしっかりとさせることで、テストする側、してもらう側の認識齟齬も解消することができます

####<目的例>
- 機能テストでの不具合検知数が想定よりも低かったため、探索的テストを実施し品質向上を図る
- 不具合検知率の高い機能に適用することで更なる品質向上を図る
- 不具合検知率は低いものの不具合があった際に影響が大きい機能において重点的にテストを実施する

#探索的テスト実施をお願いするときの注意点
なるべくどのように検証をしてほしい、などの細かい指定はない方が望ましいかと思います
指定をしてしまうとその方針や観点が重視されてしまい、他に目がいかなくなる可能性があるためです
※今回絶対に確認してほしい所などがある際は、ある程度の指定などは必要

テストの道しるべとして、ある程度のテスト観点表のようなものがあれば、下記例のようなものを共有して参考にしてもらいましょう
探索的テストを進める上で、行き詰った際の道しるべとして使用してもらうイメージになります
※資料を展開する際は、あくまで一例にすぎず、他の観点もないか考えてもらうことを忘れずに伝えましょう

|テスト観点例|詳細|
|:---:|:---|
|テキスト|表示、整合性、文章校正など|
|データ|設定、仕様書との整合性、過去事例からの逸脱|
|動作|正常動作、複合条件動作、境界値|
|遷移|リンク選択後の遷移、直打ち系操作遷移|
|画面表示|画像、レイアウト|

|イレギュラーテスト観点例|詳細|
|:---:|:---|
|タスクキル、復帰|-|
|ネットワーク切断|機内モードなど|
|連続タップ|-|
|同時タップ|複数ボタンなど|

#まとめ
探索的テストは、目的や方針をしっかりと持つことで非常に効果のあるテストになります
皆さんも単に探索的テストをやってくださいと投げるのではなく、
しっかりと必要な点にフォーカスすることを心がけてみてください
typesync用のnpm scriptsはpreinstallよりpostinstallのほうが良さそう

typesyncはnpmパッケージを追加すると型定義パッケージも自動でインストールしてくれる。

npm scripts を設定する必要があるが、

```json:package.json
"scripts": {
  "preinstall": "typesync || :"
}
```

よりも

```json:package.json
"scripts": {
  "postinstall": "typesync && yarn install --ignore-scripts"
}
```

のほうが良さそう。

前者はnpmパッケージを追加したあと、型定義パッケージをpackage.jsonに追記するだけで実際にはインストールしない。別途`yarn install`するか次のnpmパッケージをインストールする直前にインストールすることになるから。

後者はnpmパッケージを追加した直後に型定義パッケージもちゃんとインストールしてくれる。なお`&& install --ignore-scripts`が無いと前者同様pakcage.jsonに追記するだけで実際にインストールしてくれない。`--ignore-scripts`は`yarn install`する際にnpm scriptsを実行しないためのオプション。

参考:
[TypeScriptの@typesパッケージをtypesyncで自動管理する](https://qiita.com/yamadashy/items/225f287a25cd3f6ec151)

[npm script の実行順のメモ](https://susisu.hatenablog.com/entry/2017/04/20/182627)

[yarn install --ignore-scripts](https://classic.yarnpkg.com/en/docs/cli/install/#toc-yarn-install-ignore-scripts)
wardenで作ったmagentoの環境にサンプルを入れていくまでの流れ。


#はじめに
wardenで作ったmagentoの環境にサンプルを入れていくまでの流れ。

# 最終更新日
2021年12月13日

# 環境の情報
OS
Ubuntu20.04


# 注意
最新の状態を確認して下さい。
環境は構築できている前提となります。

# 公式はこちら
https://docs.warden.dev/environments/magento2.html

https://docs.magento.com/user-guide/catalog/navigation-top.html

https://marketplace.magento.com/

https://docs.magento.com/user-guide/magento/magento-marketplace.html?itm_source=merchdocs&itm_medium=search_page&itm_campaign=federated_search&itm_term=Marketplace

https://docs.magento.com/user-guide/magento/magento-account-share.html


#準備
マーケットプレイスで作ったキーをご用意下さい。


#実際に行っていく。

シェルして、入ります。

```
~/作ったプロジェクトの場所$ warden shell
```


入れていることを確認します。

```
www-data@project-php-fpm:/var/www/html$ ls
CHANGELOG.md         app               generated                 project
COPYING.txt          auth.json.sample  grunt-config.json.sample  pub
Gruntfile.js.sample  bin               lib                       setup
LICENSE.txt          composer.json     nginx.conf.sample         var
LICENSE_AFL.txt      composer.lock     package.json.sample       vendor
SECURITY.md          dev               phpserver
```


サンプルデプロイしていきたいと思います。


```
Username:
Password: 
```

には、マーケットプレイスで作ったものを入れます。

```
www-data@project-php-fpm:/var/www/html$ bin/magento sampledata:deploy

Authentication required (repo.magento.com):
Username:
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Password: 
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

auth.jsonは、はいです。

```
Do you want to store credentials for 
repo.magento.com in /var/www/html/var/composer_home/auth.json ? [Yn] yn
```

このように、ダウンロード始まれば大丈夫かと思います。

```
- Installing magento/sample-data-media (100.4.0): Downloading (100%)
```

終わりましたら、こんな感じになります。

```
Writing lock file
Generating autoload files
120 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
PHP CodeSniffer Config installed_paths set to ../../magento/magento-coding-standard,../../phpcompatibility/php-compatibility
```


終わりましたら、アップデートします。

```
www-data@project-php-fpm:/var/www/html$ bin/magento setup:upgrade
Cache types config flushed successfully
Cache cleared successfully
File system cleanup:
/var/www/html/generated/code/Composer
```


サイトを見に行き、ナビゲーションなど表示されるようになりましたら、問題ありません。
【java】スレッドセーフではないHashMap

#概要
以前マルチスレッド環境における「java.util.HashMap」に対し、複数のアプリがアクセスした際、応答が帰ってこなかっり、HashMapの値が入れ替るなどの事象がありました。
その原因や対応など備忘録的に以下を記載しようと思います。

#原因
とても単純で、「java.util.HashMap」は複数のスレッドから同時にputやgetが実行されると何が応答されるか保障されないことを理解していなかったり、排他制御をしないで使用していたからです。
この事象について調べてみると、昔からいろいろなサイトに記載されていることがわかります。

**■何が応答されるかわからない**
どうやらHashMap.putを実行すると、HashMap内のデータ構造が再構築されるみたいです。
この最中にgetが実行されると、指定されたキー情報を元に対象を検索しに行きますが、再構築中のため延々と検索したりして何を応答するのか予想がつかないみたいです。
これは、よく言われるputとgetが同時実行された際に起こる、無限ループやデータ構造が破壊される事象です。

**■HashMapの値が入れ替る**
これはスレッドローカル変数に対してではなく、static変数に対してputやgetをしており、排他制御を実装していないことが原因でした。
サンプルですが以下のようなソースです。
![src01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2216379/70cb6e40-6a64-dc27-3d1a-874ef351a2d4.png)
開発環境で以下の手順でデバッグ実行してみるとわかりますが、スレッド1つ目が25行目でmapにput後、スレッド２つ目が28行目でputしているため、スレッド1つ目がgetした場合、違う値に変更されています。
【手順】
１．24行目でブレークポイント
２．スレッド1つ目を25行目まで実行
３．スレッド2つ目を29行目まで実行
４．スレッド1つ目を26行目まで実行
これがシングルスレッドなら問題ないですが、複数スレッドからアクセスする場合への考慮が足りていなかったです。
処理順番のイメージは以下です。
![img01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2216379/a8c3da10-04b5-87f2-62ee-8b1f144d3536.png)
#対応
対応は、各事象ごとに考えます。

**■何が応答されるかわからない**
これは、HashMapに対してgetとputによる同時アクセスが原因となりますので、同時アクセスに対して同期を取るようにして、誰かがアクセスしている最中はもう片方からのアクセスを待たせる対応となります。
・synchronizedメソッド
メソッドに対して排他制御をかけます。

```java:SynchronizedSample.java
public synchronized static void putMap(String[] args){
　　// ～何かしらの処理～
}
```

誰かがこのメソッドを使用している場合、他からアクセスしてきた人は最初にアクセスした人の処理（synchronizedの範囲内）が終了するまで待たせる状態となります。
しかし、上記のサンプルはstaticメソッドなのでマルチスレッド環境化でも有効ですが、staticではないメソッドの場合、そのインスタンス単位の範囲となるため、スレッド間に対する排他制御は有効となりませんので注意が必要です。

・java.util.concurrent.ConcurrentHashMap
　HashMapをjdk1.5から使用可能となるConcurrentHashMapに変更します。

```java:ConcurrentHashMapSample.java
private static ConcurrentHashMap<String,String> map = new ConcurrentHashMap<String,String>();
```
HashMapはスレッドセーフではないですが、ConcurrentHashMapはスレッドセーフとなり同期化も勝手に実施してくれます。
自前でsynchronizedを実装しなくて済みますし、パフォーマンスも向上します。
なので、複数スレッドからアクセスが頻繁に発生する場合は、ConcurrentHashMapを使用したほうがいいです。

**■HashMapの値が入れ替る**
複数スレッドからstatic変数にアクセスしているので、タイミングによって値が変更されるのは当然でした。
自分がputした値が変更されたくないのであれば、排他制御を実施したり、スレッドローカルの変数にオブジェクトをコピー（clone）して使用するなどの対応が必要です。

#まとめ
淡々とソースコードを記述していると気づきにくいですが、どのような環境化で実行されるプログラムなのか意識しながら記述しないと、後々の調査などが大変です。
なので、スレッドセーフなのか、頻繁に変更してもいいものか、誰が利用するべきリソースなのかなど常に意識しながら記述したほうがいいと思います。

#参考
[・谷本 心 in せろ部屋](https://cero-t.hatenadiary.jp/entry/20091126/1259254839)
[・ThreadとHashMapに潜む無限回廊は実に面白い？](https://atmarkit.itmedia.co.jp/ait/articles/0803/28/news141.html)
GNU とは

## 勉強前イメージ

よく聞くけど組織の名前かな？
色々出てくるよね

## 調査

### GNU とは

GNU is Not Unix の略で、GNUはUnixではないという意味になります。
UNIXと上位互換のあるOSで、UNIXと同等のOSをソフトウェアで開発するPJになります。
また、フローソフトウェア財団を立ち上げて、多くのフリーソフトを提供しています。
`GNU ○○` と記載されているソフトウェアはGNUPJで開発されているソフトウェアになります。
例としてはGNU Emacsなどあります。
gccなども上記にあたり、gから始まることが多いです。
ちなみにGNUはグニューと呼ばれることが多いようです。

### GPLも・・・

[GPL](https://qiita.com/miyuki_samitani/items/3478df16ae66da84c3ee) という言葉がありますが、
GNUで開発されたソフトウェアは `GPL` というライセンス(利用承諾契約)で公開されて
誰でも扱うことができます。
GPLはGNU以外にもOSSで利用されています。

### GNU/Linux

GNUPJで作ったソフトウェアをlinuxカーネル上で動かしているとき GNU/Linux と書いているようです。
gccやbashはGNUで作られたソフトウェアでGNUでカーネルも作られています。

## 勉強後イメージ

OSとかPJとか財団の名前かー
ソフトウェアとかなんでもGNUつけてるのね。

## 参考

- [GNU/Linuxってなに？を学んだ](https://blog.mtb-production.info/entry/2018/03/18/151646)
- [GNU 【GNU is Not Unix】](https://e-words.jp/w/GNU.html)