OmniAICreator/Qiita-1.07M huggingface dataset:
Progate体験記 -プログラミングを勉強する

## この記事について
- ここのところではオンラインでプログラミングを学ぶことができる機会がかなり増えているそう。
- そのオンラインで学べるプログラミング講座について、どれだけ効果があるのかを少し見てみようと思って自らやってみました。
- 今回やってみたのはProgate（詳細は後程）というオンライン講座。レッスンの途中までは無料で取り組むことができる。有料プランならもちろんすべてのレッスンを受講できる。
- この記事では実際にやってみた所感と、改めてプログラミングを勉強するってどんなことか、思ったことを書いてみようと思います。
- ちなみに自分は1年半前にプログラミングに初めて触った人間です。やったことある言語はC#くらい。まだ人に聞いたり調べたりしてみないとちゃんとコーディングはできません。

## Progateについて
- https://prog-8.com/
- 初心者に向けた、あるいは初めてプログラミングをしてみようと思っている人に向けたオンライン講座。
- 先のとおり、有料プランと無料プランがある。980円/月支払って有料プランになれば、用意されている全80レッスンが受講できる。無料プランでは、そのうちの18講レッスンが受講できる。今回はこの無料プランをお試し感覚でやってみました。

## 今回のお試しについて
- 試しにやってみたコースは「HTML&CSS 初級編」「JavaScript Ⅰ」「Git Ⅰ」の3つ。いずれも各コースの基礎編にあたるもので、無料プランでできるところまではやってみました。

## 実際にやってみた
- レッスンの進み方は、初めにスライド形式で内容の説明が入る。
![Start.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/465891/ebd767b0-45b0-9b03-45c4-644e643fe021.png)
![Presentation.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/465891/1d0effa5-dd3f-b1bc-f3a3-72bf602f9218.png)

- スライドでの説明が終了したら、実際にその内容を試してみましょうのコーナーがある。
![LetsTry.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/465891/12ff3c20-4c20-868b-8c8f-6c80143b90f8.png)
    - ここでは、実際にどう書いてみるかが画面左の手順に記されている。
    - もう一度スライドの内容を確認することも可能。その際は画面左下の「スライドを見る」をクリックするとスライドに戻れる。
    - 自分が書いてみた内容がどう動作するかは、画面右上に表示される。これはJavaScriptの講座の例で、画面右上部分の右上部分にある再生ボタン（？）を押すことで、動作の確認ができる（いわゆるデバッグというやつなのかな）。HTML&CSSの場合は、自分が書いたものが即座に反映される。
    - 画面右下はお手本。JavaScriptでは動作させたときにどういう挙動をしてくれれば正しいかを教えてくれる。HTML&CSSの場合は、そのレッスンでの完成形を示してくれるので、完成形と自分が書いた状態のものを比較しながら進めることができる。
    - 正しくできたと思ったら、画面中央下部にある「確認して次へ」ボタンを押す。そうすると答え合わせが行われ、正しくかけていたら次のレッスンに進む。間違っていた場合は「～が間違っていそうです」などといったメッセージが表示されるので、再度挑戦できる。

## やってみた感想
- ひとつひとつのレッスンでやる内容のボリュームは多くなく、一歩一歩進めていくという感じで、初めてでもとっつきやすいと思いました。先の画像のように、ポップなイラストも使いながらの説明もあり、堅苦しさもないので、気軽に取り組めます。
- レッスンを見て、手を動かすの繰り返し。単に見るだけでは終わらないのがいいところ。自分で開発環境を用意しなくても、その場ですぐ確認できるから、そういう意味でも初心者にとってとっつきやすいのでは。
- レッスンを終えるごとに経験値がもらえるシステムで、レベルアップしていく。モチベーションアップのための工夫でしょうね。
![LevelUp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/465891/efa891b0-0097-0fc7-bf4a-3e08bbd74e52.png)
- 実際にVisual Studioとかでの開発経験がある人にとっては、微妙にやりにくさを感じることがあるかもしれないです。インテリセンスはないですし（あったらあんまり練習にならないと思いますけれど）、一部間違っているところに赤線は引いてくれるけれど、末尾のセミコロン抜けは赤線引いてくれませんでした（n敗：n > 10）。インデントの設定もできないので、普段と違う形だと少し気持ち悪さを感じることがあるかも。これらすべて大した問題ではないですけどね。

## Progateで学んだこと
　HTML&CSS, JavaScriptのレッスンを今回やってみましたが、たぶん今の時点では何も理解できていないです。これはProgate批判などではもちろんありません。たぶんこれがProgateでなくてもそうなると思います。初めてのことをちょっと勉強して、それをなぞってちょっとコード書いてみるだけでは、たぶん理解不十分で終わります。結局大事なのは「その後どうするか」ですね。実際に自分で何かを書いていくうちに少しずつやりたいことができるようになり、さらにやりたいことが見つかり、それを実現するために新しいことを勉強し、それができるようになり、それの繰り返しだと思います。自分がC#をちょっとずつわかっていったのも、なんだかんだそういう流れだったと思います。
　なので、これらのオンライン講座については、きっかけづくりのつもりでやるといいと思います。実際、自分もそのつもりでした。ここで「こんなことができるのか」ということを知り、「じゃあこんなことやってみよう」と思い、実行する。そこまでいけば、まさに講座に取り組んでみた甲斐があったと言えるのではないでしょうか。

## 最後に
　プログラミングに出会うきっかけ、動機は本当に人それぞれだと思います。出会った後、その道に進むとしたら、勉強は避けては通れないですね。そのきっかけづくりの一つがProgateなどといったオンライン講座なのでしょうか。この記事がそんなきっかけづくりのきっかけになればいいなと思って書いてみました。半分は自分への戒めの言葉でもありますけれど。
Rails テストデータをテーブルに保存する

#はじめに
テーブルを作成し、適当なデータを自動で入力する方法を学んだので、書き記します。

**開発環境**
ruby 2.6.5
Rails 6.0.3.4

#目次
1.テストデータの作成
2.テーブルへの保存

#1.テストデータの作成
テストコードなどで使用するGem Fakerを導入する。これによりランダムなデータを作成する。Gemfileに記述したら、忘れずにターミナル上でbundle installを実施する。

```ruby:Gemfile
group :development, :test do
#中略
  gem 'faker'
```

次にテストデータを作成する。ここではseedsファイルに10個のデータを作成する記述をする。生成するデータは文字列とした。

```ruby:db/seeds.rb
Faker::Config.locale = :ja
10.times do 
  Task.create!(
    task:Faker::Lorem.sentence
    )
end
```

#2.テーブルへの保存
最後にseedsファイルによって作成されたデータをテーブルに保存する。ターミナル上で下記コマンドを実行する。

```bash:ターミナル
rails db:seed
```
参考まで、テーブル情報を下記に示す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703987/d722a5ed-6839-3647-5dab-82e6dffc5a1c.png)

以上
MYSQL_ODBC設定について

バッチ(管理者として実行)(ODBC Driver 5.3)
--
```
REM  VC++インストール(/passive /quiet)
"\\server\MySQL_ODBC\ODBC_5.3.14_32bit\vcredist_x86.exe" /quiet

msiexec /package "\\server\MySQL_ODBC\ODBC_5.3.14_32bit\mysql-connector-odbc-5.3.14-win32.msi" /quiet

REM 元は同じ名前のODBC接続があったら、上書きされる
reg import "\\server\MySQL_ODBC\reg\ODBC_1.reg"
```

ODBCドライバ自動インストール(3.51)
--
インストール
msiexec /package "C:\Users\user1\Desktop\mysql-connector-odbc-3.51.30-win32.msi" /passive
アンインストール
msiexec /uninstall "C:\Users\user1\Desktop\mysql-connector-odbc-3.51.30-win32.msi" /passive

※下記もOKです。
msiexec /package "C:\Users\user1\Desktop\mysql-connector-odbc-3.51.30-win32.msi" /qb

mysql-connector-odbc-3.51.30-win32.msi /?　でヘルプ情報を確認できます。


ODBC　DSNを自動追加
--
下記の内容をODBC.regで保存して、ダブルクリックで登録できます。

```
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\ODBC\ODBC.INI]

[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\ODBC\ODBC.INI\Makino_LMS]
"Driver"="C:\\Program Files (x86)\\MySQL\\Connector ODBC 3.51\\myodbc3.dll"
"SERVER"="SERVER"
"UID"="UID"
"PWD"="PWD"
"DATABASE"="db"
"CHARSET"="sjis"
"PORT"="3306"

[HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\ODBC\ODBC.INI\ODBC Data Sources]
"Makino_LMS"="MySQL ODBC 3.51 Driver"
```
【-bash: ./hogehoge: そのようなファイルやディレクトリはありません】ではまった話

# 概要
centos7→centos8にお引越した後、特定のバイナリファイルで

```
-bash: ./hogehoge: そのようなファイルやディレクトリはありません
```

というエラーが出た。
こちらの解決にそこそこの時間を費やしたので、戒めのために解決策を記載する。

# 結論
hogehogeが32bit用バイナリファイルなのに、64bitのOSで実行しようとしていたのでエラーとなった。


# 解消手順
## ファイルが本当にあるか確認する
ファイルが無いと同一のエラーが出るので、まずは本当にファイルがあるか、見れる権限を持っているかを確認する。

```
# ls -al　/home/hoge/hogehoge
-rwxr-xr-x 1 hoge hoge 64162 12月  2 17:35 /home/hoge/hogehoge
```

ファイルがありますし、権限上は問題なさそうです。

## バイナリファイルのファイル形式を確認する
```
# objdump -a /home/hoge/hogehoge

/home/hoge/hogehoge:     ファイル形式 elf32-i386
/home/hoge/hogehoge
```
32bit用を示す`elf32-i386`と表示されていますね。ちなみに、64bitバイナリファイルなら`elf64-x86-64`と表示されます。

## 自身のOSのアーキテクチャ(32bit/64bit)を確認する
```
# uname -m
x86_64
```
64bitですね。ちなみに、32bitなら`i686`と表示されます。

## 32bitバイナリを動かすために必要なライブラリをインストールする
```
# dnf install libstdc++.i686
メタデータの期限切れの最終確認: 0:02:45 時間前の 2020年12月03日 10時47分32秒 に 実施しました。
依存関係が解決しました。
================================================================================
 パッケージ        Arch         バージョン                 リポジトリー   サイズ
================================================================================
インストール中:
 libstdc++         i686         8.3.1-5.el8.0.2            BaseOS         487 k
依存関係のインストール中:
 glibc             i686         2.28-101.el8               BaseOS         3.4 M
 libgcc            i686         8.3.1-5.el8.0.2            BaseOS          85 k

トランザクションの概要
================================================================================
インストール  3 パッケージ

中略

完了しました！
```
これで実行できるようになりました٩( ᐛ )و


# 感想
移行前のcentOSも64bitだったので、バイナリファイルも64bitって思いこみ、バイナリファイルが32bitだって気が付くのが遅れました。
思い込みって怖いですね。

# 参考文献
https://qastack.jp/superuser/435988/how-can-i-resolve-the-error-cannot-execute-binary-file
マインドマップでアーキテクチャ設計を勉強　第二回：マイクロサービスのアーキテクチャ設計


※ 内容の説明は、理解を深めるから更新する予定です！
また、こちらのマインドマップは、Architecting with Google Compute Engine専門講座の内容を参照しております。

![Microservice Design and Architecture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544279/f6d58800-e527-91eb-f85b-66341b48a091.png)
Go　依存モジュール管理ツールでプロジェクトを作る：（備忘録）

Goでプロジェクトを作成するときに毎回調べているので備忘録として残す。

環境
・Mojave 10.14.6
・go1.15.2 darwin/amd64

## プロジェクト作成

```bash
cd (任意のディレクトリ)
go mod init (プロジェクト名)
```

## ビルドコマンド

そのまま作る場合

```bash
go build
```

Windows用の場合

```bash
GOOS=windows GOARCH=386 go build
```


コンパイル設定値 
[公式サイト](https://golang.org/doc/install/source#environment)

|$GOOS|$GOARCH|
|:----|---|:---:|
|aix|ppc64|
|android|386|
|android|amd64|
|android|arm|
|android|arm64|
|darwin|amd64|
|darwin|arm64|
|dragonfly|amd64|
|freebsd|386|
|freebsd|amd64|
|freebsd|arm|
|illumos|amd64|
|js|wasm|
|linux|386|
|linux|amd64|
|linux|arm|
|linux|arm64|
|linux|ppc64|
|linux|ppc64le|
|linux|mips|
|linux|mipsle|
|linux|mips64|
|linux|mips64le|
|linux|s390x|
|netbsd|386|
|netbsd|amd64|
|netbsd|arm|
|openbsd|386|
|openbsd|amd64|
|openbsd|arm|
|openbsd|arm64|
|plan9|386|
|plan9|amd64|
|plan9|arm|
|solaris|amd64|
|windows|386|
|windows|amd64|
WordPressでメディアライブラリが表示されない時の対処法

ワードプレスのテーマtwentytwentyを基盤に、管理者画面のメディアライブラリで投稿した画像が表示されないエラーを対処する実装を行ったので、備忘録的にこの記事を残す。

# 環境情報

PHP：version 7.3.12
WordPress：version 5.5.3
WPテーマ：twentytwenty

# 対処法

修正を行うには、直接admin-ajax.phpファイルを書き換える必要があります。

変更前

```wp-admin/admin-ajax.php
header( 'Content-Type: text/html; charset=' . get_option( 'blog_charset' ) );
```

変更後

```wp-admin/admin-ajax.php
if( in_array( $_POST['action'], array( 'query-attachments', 'send-attachment-to-editor' ))){
	header( 'Content-Type: application/json; charset=' . get_option('blog_charset' ));
}else{
	header( 'Content-Type: text/html; charset=' . get_option( 'blog_charset' ) );
}
header( 'X-Robots-Tag: noindex' );
```
GASで日付を足したり減らしたりする

単純に

```JavaScript
const today = new Date();
const yesterday = new Date();
yesterday.setDate(today.getDate() - 1);
```
で良いそうです（コメント参照）。
難しく考えすぎでした。

---

~~GASでは`Date`型のオブジェクトが使えますが、このオブジェクトには`addDate`のような関数は用意されていません。~~
~~そのため、「（実行時から見て）先週の日曜日を求めたい」というような場合に困ります。~~
~~そんな時は`setTime`を使います。~~

```JavaScript
// 昨日を求める
const today = new Date();
const yesterdayMillis = today.getTime() - (24 * 60 * 60 * 1000);
const yesterday = new Date();
yesterday.setTime(yesterdayMillis);
```
~~つまり、加算・減算したい分のミリ秒を作ってあげて、その結果を`setTime`してあげるということです。~~
特定のディレクトリ配下のファイル名を全部取得する

```php
$result = glob('/path/to/target/' . '*');
foreach ($result as $key => $value) {
     var_dump($value);
}
```

## /path/to

※ルート直下のpathというディレクトリ、という意味では無い

/path/toは、自身の環境に合わせて適宜読み替えてね、という意味
https://teratail.com/questions/153120
パソコンの説明の回でした。

今回はRLoginに慣れていこう！
PCってこういうので出来てるよ！
見たいな内容でした。
今回の授業ページ : 

CPU、GPU、ストレージ、メモリ、バス、ディスプレイなど
パソコンに必要なパーツの説明。
コマンドを使ってPCの情報を取得する方法。
コマンドを使ってストレージの使用率を見てみよう！
などなど。

今後はRLoginを使っていくので慣れていこうね。
っていう内容だと思います。

前回に引き続き楽な内容でしたが。
先週は急にモチベがさがりサボってしまったため、
復帰するにはよかったかなって思います。

次回もがんばるぞい！
開発へ改善依頼をする際に気を付けていること

#概要
QA業務に従事していると、どうしてもQAだけでは解決できない開発側の課題に直面し、改善を依頼することがあります。そういった時に伝え方次第で、依頼を受けてもらえる可能性や改善スピードが大きく変わることを実感したので、今までの経験から学んだことを投稿しようと思います。基本的な内容が多いので主に新人QAの方の参考になれば幸いです。

#自己紹介
2017年からQAチームにてモバイルゲームのテスト管理や障害削減、テスト効率化の推進などをしています。

#開発向けの改善依頼で気を付けたいこと
##サマリ

1. **開発との良好な関係性を築き、感謝を忘れない**
2. **改善を依頼する課題は厳選し、適切なタイミングで提示する**
3. **課題は具体的なエビデンスと合わせて伝える**

##1.開発との良好な関係性を築き、感謝を忘れない
改善依頼単体の注意点で言うと2,3だけですが、開発との間に信頼関係がなければどんなに準備して改善を依頼したとしても結果にはつながらない、あるいは一時的に結果が出せても継続は難しいと思います。

そこで、前提となる良好なコミュニケーションにつなげるポイントをまとめてみます。

###開発のことを知る
**開発が何を課題視しているのか、またその温度感を知っておく**

- QAにとって温度感の高い課題でも、開発側ではそうではないことがあることを認識しておく
 - 温度感が揃ってない状態でどんなに課題を伝えても響かないため、まずは開発との温度差を把握することが重要

**開発側の負荷状況を知っておく**

- 負荷が高い状況で優先度の低い要求をしない
 - 「今それ言われてもさすがに無理」、「そもそも状況を把握してる？」とNextActionに繋がらないだけでなく信頼を失う可能性も

###開発と目線を合わせる
**課題に対する温度感を合わせる**

- QAはなぜその課題を重要視しているのか、それによるリスクや懸念を明確化して伝えて理解してもらう

**共通の目標を持つ**

- 期初など仕切り直しのタイミングで、共通の品質目標を立て一緒に取り組むことを合意しておく
 - 例えばQAへの検証依頼漏れによる障害を○%減らすなど

###開発の立場を尊重し感謝を忘れない
**求めるだけでなく、まず感謝もしっかり伝える**

- 感謝と依頼のバランスが大事
 - 感謝せず依頼ばかりしていると、関係性が悪化したり相談しづらくなるため要注意

**開発側の課題にもできる範囲で貢献する**

- 開発側で困っていることにもアンテナを張り、改善案を提示したり、他タイトルの改善事例を共有するなどできる限り貢献していく

##2.改善を依頼する課題は厳選し、適切なタイミングで提示する

**現場の要望や課題はそのまま伝えず、取捨選択し優先度をつける**

- 現場の要望や課題に対して、何が根本原因か、またどの職種で改善すべきかを考える
 - 精査した結果QA内で解決すべき話であればQA内で対策する
- 課題に優先度をつける
 - 優先度は課題の発生頻度や重大度などを基準に考えるとぶれない

**ベストなタイミングを見計らう**

- 開発の温度感と課題の優先度をもとに、今改善依頼をあげるべきか、来月に回すべきかなどタイミングを精査する

**精査した上ですぐに改善してほしいことがたくさんあったとしても、一度にまとめて投げない**

- もちろん課題の優先度にもよるが、できるだけ今一番改善してほしいこと1つに絞って相談する
 - まとめて依頼してしまうと優先度がよくわからなくなるため、NextActionが定まらなかったり初動が遅くなり、結果遠回りになる

##3.課題は具体的なエビデンスと合わせて伝える

**課題を裏付けるエビデンスはKPIだけでなく具体的な情報も合わせて提示する**

- 必ずKPIの中身は事前に分析しておいて、具体例と合わせて提示する、もしくは聞かれた際に答えられるようにしておく
 - 具体的な内容や事例がないと対策も曖昧になり、効果を発揮できずに終わってしまう

#さいごに
自分なりに開発への依頼で気を付けるべきと思ったことを列挙してみました。チーム開発の現場において信頼関係はとても重要です。一見課題が出次第すぐ開発へ改善を依頼する方が改善は早く進みそうですが、実際はそうではないことの方が多いと感じます。1つ1つの課題に丁寧に向き合い、開発と一緒に解決して行きましょう。
SwiftではNSDictionaryのサブクラスが作れない

Swiftの制約によってNSDictionaryのサブクラスが作れなくなっちゃった話

実はNSDictionaryというクラス自体は使うことができない

```swift
print(type(of: NSDictionary())) // __NSDictionary0
print(type(of: NSMutableDictionary())) // __NSDictionaryM
```

実はNSDictionaryのイニシャライザは`NSDictionary`を返しておらず実際は`__NSDictionary0`、`__NSDictionaryM`という型を使っている。

`NSDictionary`・`NSMutableDictionary`には実装がないので直接継承するとエラーが出る

```swift
class Dict: NSDictionary {}

let dict = Dict() // ここでエラー
```

このため`NSDictionary`のサブクラスを作るためには各実装を`override`する必要がある。


例えばこのようにすることで、追加された順番を`Array`に記録した順番付き辞書を作ることができる。

```swift
class NSOrderedDictionaty: NSMutableDictionary {
    let storage = NSMutableDictionary()
    let order = NSMutableArray()
    
    class Enumurator: NSEnumerator {
        var iterator: NSFastEnumerationIterator
        
        init(iterator: NSFastEnumerationIterator) { self.iterator = iterator }
        
        override func nextObject() -> Any? { iterator.next() }
    }
    
    override var count: Int { storage.count }

    override func keyEnumerator() -> NSEnumerator {
        Enumurator(iterator: order.makeIterator())
    }
    override func removeObject(forKey key: Any) {
        storage.removeObject(forKey: key)
        order.remove(key)
    }
    override func setObject(_ object: Any, forKey key: NSCopying) {
        storage.setObject(object, forKey: key)
        order.add(key)
    }
    override func object(forKey key: Any) -> Any? {
        storage.object(forKey: key)
    }
}
```

ただしこの実装は完全ではない

本当は`NSDictionary`のイニシャライザである

```swift
init()
init(capacity numItems: Int)
init?(coder: NSCoder)
```

を`override`する必要がある。(というかしないと落ちる)

しかしなんということでしょう
Swiftで`extension`で追加されたイニシャライザに`required`なものが存在してしまっている。


```swift
required convenience init(dictionaryLiteral elements: (Any, Any)...)
```

Swiftでは`extension`で定義されたメソッドを`override`できない、しかし`required`なイニシャライザは`override`する必要がある。

これにより`NSDictionary`のサブクラスを作ることが不可能になっている。
【Unity 2020.1.9f1】Standard Assets のエラーを消して動作させる


Standard Assets (for Unity 2018.4)のエラー直す方法。

使用Unity 2020.1.9f1

このアセットで、ThirdPerthonCharactor/prefab/ThirdPersonController を使用方法


下記をまずUnityに追加、インポートなどでプロジェクトの追加
https://assetstore.unity.com/packages/essentials/asset-packs/standard-assets-for-unity-2018-4-32351#description

Assets → Standard Assets → Utilityを開く。
②Utilityフォルダー内にある、「ForcedReset.cs」と「SimpleActivatorMenu.cs」を削除

奈落に落ちてしまうので、Planeなどのオブジェクトで人（イーサン）が置ける場所を作る

ThirdPersonCharacterGuideLines.txt にやり方が書いてあり、２番で

2) Place the "ThirdPersonCharacter" prefab in the scene.

と書かれているが、ThirdPersonController をシーンにドラッグ＆ドロップしたら、
キャラクターがカーソルキーやスペースなどで動かせるようになる

おまけ

![EthanAlbedoSpecular.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76087/a636f43f-9336-5d4f-104b-b38c68c6fffb.png)

この画像をDL
そして ThirdPersonCharactor/Textures にドロップ

ドロップしたTextureを選んで EthanBody にドロップ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76087/bdf55a6a-ebef-2482-8324-1efd4c2d6023.png)

するとイーサンの服や肌に色が着色される

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76087/5317db48-4934-cfc4-4883-86d1b78850b2.png)


![EthanAction.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76087/4a7bafba-3c48-c5ae-0700-e9e1a6dcfbd7.gif)


情報源：
https://www.sbcr.jp/support/48965/
ネットワークIOが刺さったプロセスの接続先がどこかを知るためのTIPS

nfsなりdbへ接続するプロセスがあったとして接続先が原因でプロセスのIO刺さることは多々ある。

刺さったプロセスがどこに対するIOでその状態になったかを特定する方法の記事

``` bash
# 刺さったプロセスのPIDを取得
$ ps aux | grep "プロセス名"

# pidから開いているソケットを確認
$ ls -l /proc/${PID}/fd

# straceを使ってfdの番号を取得
$ strace -p ${PID}

# fdを取得したらsocketの接続先を取得する
$ readlink /proc/${PID}/fd/${↑で取得したfd}

# ソケットのinodeを頼りにnetstatでgrep
$ netstat -antep | grep ${↑で取得したinode}
```

straceでソケットを取得する方法が意外にもlsofが入ってる環境なら

``` bash
$ lsof -i -a -p $PID
```

だけで取得できてしまう。
やってることはファイルディスクリプタとソケットの話がわかればとっても簡単だけどlsofで一発で取れちゃう。

この他にも`/proc/net/tcp`から取得する方法もあるとのこと。16進数への変換やらが必要なので手数的にはこっちの方が少ないので使い分けるのも良さそう。
http://blog.1q77.com/2020/10/socket-in-proc-pid-fd/
量子コンパイラを作る。 その6

# 概要

量子コンパイラを作る。
練習問題、全加算器、やってみた。

# コードを書く。


```
make 8
in 0 2
wire 3 5
xor 1 2 3
and 1 2 4
xor 0 3 7
and 0 3 5
or 4 5 6
out 6 7
```

# コンパイル結果

```
from blueqat import Circuit

print (Circuit(8).h[ : 3].cx[1, 3].cx[2, 3].ccx[1, 2, 4].cx[0, 7].cx[3, 7].ccx[0, 3, 5].ccx[4, 5, 6].cx[4, 6].cx[5, 6].m[ : ].run(shots = 1000))


```

# 成果物


https://embed.plnkr.co/plunk/wcTCIqFFeAXHNsi2

# 真理値表で確認。

![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/a3c9fbe1-67d1-1366-2ec8-e045f12b2df4.jpeg)

# 成果物

https://embed.plnkr.co/plunk/dn6OkSUpgFdgcrK0

# 回路図で確認。

![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/7797b07f-f61f-75fb-0d81-592c92c8e420.jpeg)

# 成果物

https://embed.plnkr.co/plunk/vq56JBayaRCHK7fy

# 実行結果


```

Counter({
  '01010001': 152, 
  '00000000': 136, 
  '11010110': 132, 
  '11101011': 127, 
  '01101010': 127, 
  '00110001': 124, 
  '10000001': 105, 
  '10110110': 97
})



```

以上。
シナリオQAに必要なこと

# はじめに
私が担当しているIPタイトルは、原作ファンの方が多くプレイされています。
原作になかった展開や原作を補完する内容等、原作ファンの方にも楽しんでいただけていると思っています。

せっかくストーリーは満点なのに誤字・脱字が多くて面白さ半減・・・とならないようにQAもしっかりとおこなう必要があります。

文字を読んでミスを見つけるだけでしょ？簡単じゃない？と思われる方もいるかもしれませんが、結構手間がかかり大変です。

シナリオQAを始めてすでに3年程経っているのにいまだ万全とは言い難く、細かな誤字・脱字を出してしまっている状況ですが、シナリオのQAをおこなううえで、気を付けている点等を共有できればと思います。

# シナリオ作成の流れ
少しQAの話からは逸れますが、シナリオの作成開始から本番にリリースされるまでの大まかな流れを説明します。
※各工程はプロダクト側で使用している用語のため、一般的な工程の名称とは異なるかもしれません。
**工程1～4まですべて監修があり、監修通過で工程完了です。**

**1.草案作成**
どんなストーリーを作成するかの案出しの工程。
本編では絡みのなかったキャラAとキャラBが共闘する内容にしたい、主人公が覚醒する内容にしたい等、ストーリーの方向性を決めます。

**2.概要作成**
草案で決まった内容をもとに、ストーリーの内容や流れ、登場人物、設定等を決める工程。

**3.プロット作成**
概要で決めた内容をもとに、さらに細かくストーリーの進行を決めていく工程。

**4.シナリオ作成**
プロットをもとにシナリオを作成する工程です。


**5.スクリプト作成**
作成されたシナリオをアプリ内で再生できるようにスクリプトに落とし込む工程です。
この工程で立ち絵やSE、エフェクトなどが組み込まれ、ゲームとしてプレイ可能な状態になります。

**6.QA**
組み込まれたシナリオを実際に実機で確認する工程です。
シナリオが進行不能にならず最後まで進行可能か、シナリオ内のテキストに誤字・脱字やレギュレーション違反のテキストがないか、立ち絵やムービーが正しく再生されるかなど、ユーザーがシナリオを楽しむうえで障害となるあれこれを取り除きます。

**7.本番反映**
全ての工程が完了したシナリオを本番に反映し、あとはリリースを待つだけ！



シナリオ作成開始からリリースまでに大体3か月程度かかっています。


# QAで実施している内容

工程の説明で軽く記載しましたが、実際にQAで確認している内容は以下になります。
・シナリオが通しで再生できるか
・シナリオとバトルパートの整合性がとれているか
※シナリオ内で戦う流れになった際に、バトルにその相手がちゃんと出現しているかを確認
**・シナリオのテキストに誤字・脱字や表記揺れ等がないか**
**・シナリオのテキスト内がレギュレーション違反になっていないか**
・立ち絵やボイスが、セリフにあった内容になっているか
・立ち絵やSE、エフェクト等スクリプトで指定したものが表示、動作しているか

どれも当たり前な確認ですが、作業量は意外と多いです。

太字の項目が特に工数をかけて確認している内容です。
工程の説明では記載していませんが、工程4で監修提出する前にもQA側で誤字脱字やレギュレーション違反の確認を行っています。
この段階で提案込みで平均300件程度、多い時は500件ほどの指摘があがる場合もあります。

# シナリオQAを行う際の留意点
シナリオのQAを行う際にあるといいもの等をいくつか紹介します。

●レギュレーションがまとまった資料
何は無くてもこれがないと始まりません。
特にIPタイトルの場合、IP独自の用語や設定等、シナリオを確認するうえで必要になりますが、一つにまとまっていないと確認効率が落ちてしまいます。また、新しい設定などが出てきた場合に都度更新が必要になるので、そういった点でもまとまっていたほうがいいです。
これに関してはシナリオを作成する際にも必要な資料なので、プロダクト側で作成されていると思います。
もし資料が散っているようであればまとめましょう！

●検証メンバーの固定化
検証は基本的に外部ベンダーさんに依頼をするのですが、シナリオ確認は通常の検証のように手順通りに確認すればOKというような内容ではありません。レギュレーションなどをまとめた資料はありますが、都度資料を確認しつつ検証を進める形だとどうしてもシナリオの確認に集中できず、見逃しが発生しやすくなってしまいがちです。
シナリオ確認を行うメンバーを固定できれば、回数を重ねるごとに担当されたメンバー自身にも知見が溜まり、効率よく確認が行えるようになったり、セリフなどの言い回しに対しての提案等も行えるようになります。
メンバーの中に文章に強い方やIPに詳しい方、好きな方をアサインできるとなお良しですね。


# さいごに
魅力的なシナリオを不備なくユーザーに届けるために、これからも品質の高い検証を効率よく行えるよう工夫をしていきたいと思います。
この投稿が同じような苦労をされている方の一助になれば幸いです。
PowerPointで作成したスライドショーに合成音声を吹き込みたい

プログラミング関連の記事ではありませんが，ここに書いてもいいものなのでしょうか...

今回は__Microsoft PowerPoint__で作成したスライドショーに，合成音声を吹き込んで，動画をファイルを作成する方法をまとめました．（主流ではないと思いますし，個人的にはグレーな気もするので個人で使用する範囲にとどめてください）
環境は__Windows10__で，__PowerPoint2019__を使用しています．
可能な限りソフトウェアをダウンロードせずに，無料でやることを念頭に置いています．


合成音声の作成は__Google text-to-speech__のお試し機能を使います．
個人的には日本語の発声の流暢さはあると思います．
無料登録でもファイル出力などできるそうなのですが，Google cloud platform使ってないし，登録するために住所やクレジットカード情報を入力するのが嫌だったので...

音声の収録は，Windows標準実装されている__ボイスレコーダー__を使用します．
この手法で収録ができない環境もあるそうなので，要注意（下記参照）

###背景
スライドショーを使って素直に自分の声を吹き込めばよいのですが，自分の声が嫌いなので，スライドショーに自分の声だけがのっている動画を作成する，というのは（個人的に）とても気分が悪いのです．
（しかもそれが外部に一般公開されるとなるとなおさらなのです．リアルタイムの会議でしゃべる分には問題ないのですが...）

###やったこと
1．Microsoft PowerPointでスライド作成 (動画用なのでアニメーションもばっちり)
2．合成音声さんに話していただく原稿作成 (収録時間にあわせて原稿を)
3．ファイル出力 (かなり手間で，できない環境もある)
4．収録 (PowerPoint 2019の機能を使用)
5．動画ファイル出力 (今回はMPEG4形式に)

####合成音声ファイルの作成
↓に入るとお試しで，好きな文章の合成音声を視聴できるはずです．
https://cloud.google.com/text-to-speech/?hl=ja
![tmp1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654731/b3a79736-e099-7d95-2476-e5e4738843b9.jpeg)
私はオスなのでwavenetDを選択しました．
しかし音声ファイルを出力することはできません．
そこでPCから流れてくる音声を__ボイスレコーダー__で取り込みます．

↓ここを参考にしました．
https://vip-jikkyo.net/win10-how-to-set-up-a-mic
Reaktekのステレオミキサーは，私の周辺の環境ではデスクトップPCには実装されていて，surface goには実装されていませんでした．
収録にはヘッドホンなどの出力機器を使用せずに，外に音声ダダ洩れの状況を作らなければなりません．
逆にイヤホンを差さないと収録できないパターンもあるそうなので，いろいろ試してみてください．
（ダダ洩れにする音声を聞かれないように誰もいなくなった瞬間を狙って，あとはメールの着信がないことを祈りながら収録しました．PCから出力される音声はすべて拾ってしまうので...）

音量が十分ではないときの対処法は，以下のようにしました．
ボイスレコーダーで出力されるファイル形式はM4A形式だそうで（あまり聞いたことない），これを一旦MP3形式に変換します．
以下のサイトを使用しました．
https://online-audio-converter.com/ja/
(おそらく「M4A MP3 変換」で検索すると一番上ヒットします．)

それから以下のサイトで音量を大きく（正確には3dBに調整?）します．
https://www.mp3louder.com/jp/
（「MP3 音量調整」で検索するとヒットします．）

これで適度な音量のMP3形式の合成音声ファイルができたはずです．

####収録
↓収録そのものは，ここを参考にしました．PowerPointにこんな機能が実装されたのですね...
https://douga-tec.com/?p=19915
（「パワポ　動画　作成」で検索しました．）
ただこの方法は（私の好まない）自分の声を吹き込むパターンで，自分のタイミングでスライドを送る形式になります．
せっかく音声ファイルをゲットしたので，これを活用しましょう．

とりあえず一番初めのスライドに移動します．
PowerPoint上部のツールバー「挿入」→「オーディオ」→「このコンピューター上のオーディオ」を選択し，音声ファイルを選択します．
目立たない右下のすみっこに暫定的に音声データのスピーカーマークを移動させます．
このスピーカーマークは，マークをぽちっとしたあとに，画面上部のオーディオツール「再生」→オーディオのオプション→「スライドショー実行中にサウンドのアイコンを隠す」にチェックを入れると収録時には表示されません．

そして画面上部のオーディオツール「再生」→オーディオスタイル→バックグラウンドで再生を選択します．
これでスライドショーを始めると同時に合成音声が流れ始めます．

いよいよ収録します．
画面上部のファイル→エクスポート→ビデオの作成を選択し，画面中段の「記録されたスライドとナレーションを使用する」から「タイミングとナレーションの記録」を選択します．
見慣れない黒背景の収録画面に移動します．
あとは，左上にある収録ボタンを押すと，3秒カウントダウンの後に収録が始まります．
流れてくる合成音声に合わせて，スライドを送るだけ．スライドを送るタイミングもとってくれるようです．
最後のスライドまで行ったら，停止ボタンを選択する．

収録が終わったら，画面上部のファイル→エクスポート→ビデオの作成の画面中段の「ビデオの作成」ボタンを押すと，動画ファイル保存場所やファイル名を指定することができます．

------------------------
できましたでしょうか．

終わり
CSVファイルを型安全に取り扱う


csv ファイルを型付きのオブジェクトとして読み込みたい。

例えば、以下のような csv ファイルであれば `{name: string, age: string, gender: string}[]` 型として読み込みたい。

```
name,age,gender
aaa,18,M
bbb,23,F
ccc,30,M
```

csv の読み込みは [papaparse](https://www.papaparse.com/) を利用しています。

```typescript
import papa from 'papaparse'

const readCSV = <T extends {}>(file: File, config: papa.ParseConfig) =>
    new Promise<papa.ParseResult<T>>(((resolve, reject) => {
        config.complete = ((results: papa.ParseResult<T>, _) => resolve(results))
        config.error = ((error, _) => reject(error))
        papa.parse(file, config)
    }))

// readonly ["name, "age"]
const required = ["name", "age"] as const

// Row<readonly ["name", "age"]> は {name: string, age: string}
type Row<T extends readonly string[]> = {[K in T[number]]: string}

// If header is true, the first row of parsed data will be interpreted as field names.
// An array of field names will be returned in meta, and each row of data will be an object of values keyed by field name instead of a simple array.
readCSV<Row<typeof required>>(file, {header: true})
    .then((results) =>
        required.every(e => results.meta.fields && results.meta.fields.includes(e))
            ? results.data  // {name: string, age: string}
            : undefined
    )
```

パースされたオブジェクトが期待される型であることはランタイム時にはじめて分かります。（ランタイム時に型はないので、「分かる」という表現は不適かもしれません。）
各行の値がいずれも `string` 型であることは自明ですが、オブジェクトのキーが期待される名前であることはコンパイル時には分かりません。

そこで、`required.every(e => results.meta.fields && results.meta.fields.includes(e))` という処理によって、オブジェクトに期待される名前のキーが存在するかを検証しています。papaparse はオブジェクトのキーを `results.meta.fields` に格納するため、`required` 配列のすべての文字列が `result.meta.fields` に含まれることを確認できます。

`results.data` は `required` 配列で指定したキーをもつオブジェクトとして扱うことができます。つまり、そのオブジェクトの型は `required`配列の型 ( `readonly ["name, "age"]` ) を `T`とすると `{[K in T[number]]: string}` になります。
include?メソッド

##include?メソッド
include?メソッドは指定した要素が、配列中に含まれているかを判定するメソッドです。
[公式リファレンス](https://docs.ruby-lang.org/ja/latest/method/Array/i/include=3f.html)

例）以下のように使用します。

```
array = ["foo", "bar"]
puts array.include?("bar")
#=> true
puts array.include?("hoge")
#=> false
```


今回は呼び出しをarray123(nums)を使い、以下の出力結果になるようになります。

出力例
array123([1, 1, 2, 3, 1]) → True
array123([1, 1, 2, 4, 1]) → False
array123([1, 1, 2, 1, 2, 3]) → True

```ruby:ruby
def array123(nums)
  if nums.include?(1) && nums.include?(2) && nums.include?(3)
    puts "True"
  else
    puts "False"
  end
end

array123([1, 1, 2, 3, 1])
array123([1, 1, 2, 4, 1])
array123([1, 1, 2, 1, 2, 3])

```
解説
numsに1,2,3が入っているか判断するためにinclude?メソッドを使用します。
&&演算子を複数使用することで、条件式の条件を複数にすることが可能です。
unimplemented!、todo!、unreachable!の違い

Rustのマクロのうち実装が行われていないことを明示的に記載することで型検査を通すことができます。
複数人で実装した際にパニックを起こさないためにも適切なマクロを使うことで実装漏れを防げます。

## エラーメッセージ

| 名前           | エラーメッセージ                         |
| -------------- | ---------------------------------------- |
| unimplemented! | not yet implemented                      |
| todo!          | not implemented                          |
| unreachable!   | internal error: entered unreachable code |

## 役割

| 名前           | 役割                                                         |
| -------------- | ------------------------------------------------------------ |
| unimplemented! | 未完成であることを表す。                                     |
| todo!          | 未完成かつ必ず実装しなければいけない箇所を表す。             |
| unreachable!   | 到達不能であることを表す。<br />ハンドリングする必要がない箇所に記載するといい。 |
マインドマップでアーキテクチャ設計を勉強　第一回：要件定義

数年前から、ソフト開発サービスの機能を覚える・理解するためマインドマップを使って始まりました。
手描きで試したこともありましたが。ただ、アプリで一つも作ったことはありません。

今回アーキテクチャ設計を勉強するには、初めてマインドマップを描画するアプリMindNodeで設計要素描いてみました。
一目瞭然で分かりわすいです！知的生産性向上を目指す方是非試してください！
これからシリーズで更新、一部の言葉を日本語に変更する予定です。
（MindNodeは有料です、一年間２千円ぐらいの利用料金）

![Architecture Design and Process: Defining Services 2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544279/512e2afa-d117-1258-5cc6-ad923db7b0ba.png)

### 要件定義
※ ここでは、主な考え軸だけを記載します。また、こちらのマインドマップは、Architecting with Google Compute Engine専門講座の内容を参照しております。

要件定義には、主に以下４つの部分で考えられます。（伝統的な日本の言い方・考え方若干違いますが）
#### 対象となるユーザの定義
　　ロールやペルソナで登場人物と相当のシステムの振る舞いの定義で、要件を確定します。
　　ロールは一般できなマネージャー、管理者、カスタマーと考えられます。ペルソナは一つの要件定義の方法論です、ペルソナ別にシステムの機能を整理することでよく使用されます。

#### 量的な要件
  　業務面のKPI、技術面のKPIが分かれています。良いKPIの設定方法にはSMARTモデルは使えます。

#### 質的な要件
　ユーザーストーリー駆動設計が推奨されています。ユーザーストーリーは基本5W1Hで整理します。ここでWhereを略します。

#### サービスレベルの測定・評価
　主にはSLI、SLO、SLAに分かれています。以下はGoogleの製品ニュース[SLO、SLI、SLA について考える : CRE が現場で学んだこと](https://cloud.google.com/blog/ja/products/gcp/availability-part-deux-cre-life-lessons)の表現です。

* SLO (Service-Level Objective): システムの可用性を担保するにあたってターゲットとする目標、数値。
* SLI (Service-Level Indicator): SLO が満たされているか評価する際に用いる指標。エラー率やスループットなど。
* SLA (Service-Level Agreement): サービスの利用者に対して約束する可用性のレベル。
foreachでコレクションに格納しているStringは更新できない/不変性

#はじめに
これは、Stringのコレクションを拡張for文、ForEachでは「内容の更新」が出来ないというお話です。

##どんな時か
以下のコードで、strArrayに放り込んだ"a","b","c"に"X"という文字を連結し、その内容をforeachを抜けた後で出力します。

```java
private void modifyStrInCollection() {

	String strArray[] = { "a", "b", "c" };
	///foreachで更新。
	for (String str : strArray) {
		str += "X";
		System.out.println("01:" + str);
	}
	///配列の内容出力
	for (String str : strArray) {
		System.out.println("02:" + str);
	}
}
```

どんな結果になると思いますか？ "aX","bX","cX"になっているでしょうか。 実行結果は以下の通りです。

```java
01:aX
01:bX
01:cX
02:a
02:b
02:c
```

更新しているforeachの中ではstrに"X"が連結されていますが、外に出ると元に戻っています。 なぜでしょうか。

##Stringクラスの「不変性(immutable)」が、その理由
簡単に言えば、「文字列を更新しているようで、していない。 新しく文字列オブジェクトを作成する」のです。 詳細は「String 不変性」で検索していただけたらと思います。

foreachは、コレクションの最初から一つずつ要素の値を抜き出しますが、Stringは「参照型」です。 そして、**Stringは不変**であるため、更新した場合**「元の文字列はそのまま、新しい文字列オブジェクトを作成し、その新しい参照を返す」**のです。
つまり、配列から要素の参照を抜き出すまではいいのですが、それを更新しても元の文字列は変わらず

```Java
str += "X";
```

の[str]には、**配列の中にあった参照とは別もの**が設定されています。 やっていることは

```Java
String modifiedStr = str + "X";
```

と同じで、元のstrは何の影響も受けません。

##Stringを内部に持っているクラスなら問題なく更新する
当然ですが、Stringをメンバに持つクラスをforeachにかけ、メンバとしてのStringを更新することはできます。 Stringに限らず、不変性の性質を持つクラスはforeachで(直接)更新できないというだけです。

##おわりに
foreachを覚えてすぐの初心者の方が、もしかしたらハマるかな？と思い記事にしました。 思い当たることがあれば幸いです。
RHEL8（CentOS8）にPostgreSQL 13をインストールする

# 環境
Red Hat Enterprise Linux Release 8.2

# リポジトリ追加
探し先はこちら。
[https://yum.postgresql.org/repopackages/](https://yum.postgresql.org/repopackages/ "Repo RPMs")

RHEL8のリポジトリを追加します。

```
sudo dnf install https://download.postgresql.org/pub/repos/yum/reporpms/EL-8-x86_64/pgdg-redhat-repo-latest.noarch.rpm
```

# PostgreSQL AppStreamの無効化
もともと入っているバージョンを無効化します。(しなくてもインストールは可能)

PostgreSQL AppStreamリポジトリを無効にします。

```
sudo dnf module disable postgresql
```
良ければyで無効化します。

# PostgreSQL 13のインストール

```
sudo dnf install postgresql13-server
```

# DBの初期化

```
sudo /usr/pgsql-13/bin/postgresql-13-setup initdb
```

# DBの起動、自動起動
DBの起動と自動起動設定を行います。

```
sudo systemctl enable --now postgresql-13
```

起動の確認を行います。
```
sudo systemctl status postgresql-13
```

自動起動設定の確認を行います。
```
sudo systemctl is-enabled postgresql-13
```
dismiss後に親ViewのNavigationControllerを遷移させる

dismissのcompletionの中で遷移させるだけなのですが、親Viewをあらかじめ取得しておく必要があります。

```Swift
        let parentNav = self.presentingViewController as! UINavigationController
        //viewControllersの添字は状況に応じて変更してください
        let parentVc = parentNav.viewControllers[1] as! ParentViewController

        self.dismiss(animated: true) {
　　　　　　　//ここでは親Viewの遷移元のViewに戻っています
            parentVc.navigationController?.popViewController(animated: false)
        }
```

dismissのクロージャの中で取得しようとするとnilになるので注意が必要です。
備忘録：merpay Tech Talk ~ 伝わる技術文書の書き方 ~に参加してみた

# はじめに
こんにちは。oka-shi@技術ブログ初心者です。

先日、merpayさんのオンライン勉強会『伝わる技術文書を書く』 に参加してきたので、自分用に備忘録を残します。
動画はYouTubeに公開されていますので、興味がありましたらご参照ください。

## 動画の概要
* merpay Tech Talk ~伝わる技術文書の書き方~  
https://www.youtube.com/watch?v=GvjScPO3OcA&feature=youtu.be
* こんな方におすすめ
  * 技術発信したいけど自信がない方
  * 技術発信をより伝わるものにしたい方
  * アドベントカレンダーで何か書かなければいけない方
  * 書籍を執筆したい方
* 目次
  * 伝わる技術文書の書き方
     * 外部公開の分類
     * 細かな言葉の注意点
     * レビュー
     * 「はじめに」の重要性
     * フレームワーク
  * 今すぐテクニカルライディングが必要になったときの転ばない杖
     * 対象読者と期待値のコントロール
     * 正確性と分かりやすさのバランス
     * 結論から述べる完結な文書構造
     * 事実と意見の分離
  * 実践！テクニカルライディング
     * 文章を書く流れ
     * うまく書けない場合
     * めっちゃ書いちゃう場合
     * セルフレビューのテクニック
     * メルカリ・メルペイにおける技術文書を書く機会

## 何故参加したか
* 技術ブログをアウトプットするペースを早くしたい　※現状隔月1本
* 相手に伝わる技術ブログを書きたい

## 参加して学んだこと
技術ブログ初心者の観点で、動画から参考になった部分を引用して、学びをまとめてみました。

### 伝わる技術文書の書き方
>* 外部公開の分類  
>  * A. 理解した技術のまとめ
>  * B. 新たな技術のまとめ
>  * C. 自分で考えた手法（技術）のまとめ
>  * D. プロセス（プラクティス）改善・導入
>  * E. 自分の考えを伝えたもの
>  * F. 書籍の紹介

技術ブログは、新たな技術のまとめや、自分で考えた手法（まとめ）だけをイメージしていました。理解した技術のまとめや、書籍の紹介などであれば、アウトプットしやすいですね。  

###  今すぐテクニカルライディングが必要になったときの転ばない杖
>* 対象読者と期待値のコントロール  
>  * 読者は筆者が思った通りには、行動しない
>      * そもそも文章を書いたら読んでもらえるというのは**書き手の勘違い**
>      * 対象読者を指定する

技術ブログを書いたら読んでもらえるという**書き手の勘違い**を、正にやっていました。書く時間を決めることで、アウトプットするペースが早くなるか試してみます。
また、対象読者を指定すること（本当は誰に届けたいの？と振り返る鉄の意思）で、書きやすくなると感じました。　

### 実践！テクニカルライディング
>* うまく書けない場合  
>  * うまく書けない項や節を飛ばす
>      * 書きたいところから書く
>      * 見直すと不要な場合もある

うまく書けないところは、そもそも不要な場合がある、という点に気付けていませんでした。書けないところは思い切って捨ててみました。


>* セルフレビューのテクニック 
>  * 耳で聞く
>      * OSの読み上げ機能を使う
>      * 耳で聞いて頭に入ってこない文章は、読んでも分かりづらい
 
セルフレビューで**耳で聞く**という観点はありませんでした。実際に耳で聞いてみると、文章が冗長な点に気付けますね。テキストの読み上げは、AWSのAmazon Polly（テキスト読み上げ機能）も使えますね。

## まとめ
今回は、技術ブログ初心者の観点で、オンライン勉強会『伝わる技術文書を書く』に参加した内容をアウトプットしてみました。技術ブログをアウトプットするペースを早くするには、テーマや対象読者を絞り込んだ上で、理解した内容をまとめることが効果的だと感じました。
最後になりますが、いつも良質な情報を公開して頂けるmerpayさんに感謝です。m(_ _)m
Swiftlint autocorrectでコードを自動修正する

## はじめに
この記事はand factory Advent Calendar 2020 の3日目の記事です。
昨日は[@yasukotelin](https://qiita.com/yasukotelin)さんの[KotlinでResult型使うならkotlin-resultを使おう](https://note.com/yasukotelin/n/n6d9e352c344c)でした🎉

## やりたいこと
- swiftlintのルールに合わせて、debugビルド時にコードを自動修正する

## 背景
僕のチームでは、
今期から3人で2つのプロジェクトの開発を担当しています。

それぞれswiftlintのルールが微妙に違うため、
プロジェクトごとに細かな記法を意識してコーディングする必要があり、
少し手間に感じていました。

そこで、今回swiftlintの機能を用いて
ルールに反したコードを自動修正する仕組みを導入します。

## やること
1.Swiftlintを導入
2.BuildPhaseで実行するスクリプトを書く 

## swiftlintの導入
Mintで導入してます

``` txt:Mintfile
realm/SwiftLint@0.39.2
```

## BuildPhasesにscriptを定義

最終的に採用したスクリプト

```.rb:script
if [ $CONFIGURATION = "Debug" ]; then
  git diff --name-only | grep .swift | grep -v Pods/ | grep -v R.generated.swift | while read filename; do
    xcrun --sdk macosx mint run SwiftLint swiftlint autocorrect --path "$filename"
  done
  xcrun --sdk macosx mint run SwiftLint swiftlint
fi
```
## スタックしたポイント
### エラー: Parse error(s)
下記スクリプトでビルドしてみると、エラーが。。。


```.rb:script
if [ $CONFIGURATION = "Debug" ]; then
    mint run SwiftLint swiftlint autocorrect --path "$filename"
    mint run SwiftLint swiftlint
fi
```

```txt:error
github.com_realm_Swiftlint: manifest parse error(s)
unable to load standard library for target 'x86_64-apple-macosx-10.15'
```

```txt:warning
using sysroot for 'iPhoneSimulator' but targeting 'MacOSX'
```

上記エラーは
SwiftlintをmacOS用にビルドしようとしているのに、
利用するSDKがiOSシミュレーター用になっているのが原因のようです。

BuildPhaseに `unset SDKROOT` を追記することで
スクリプト実行の間だけ環境変数SDKROOTを解除し、回避することも可能ですが、
macosxのsdkを指定するほうがおすすめです。

```.rb
xcrun --sdk macosx mint run SwiftLint swiftlint
```

### 各コミットで発生した差分のみ自動修正したい

while文で対象を指定することで解決しました。

```
git diff --name-only | grep .swift | grep -v Pods/ | grep -v R.generated.swift | while read filename; do
    xcrun --sdk macosx mint run SwiftLint swiftlint autocorrect --path "$filename"
 done
```

## 運用
autocorrect機能を本導入する際に、
プロジェクト全体を自動修正しておきます。

その後修正対象を差分に絞ると
debugビルドを実行するたびに差分を自動修正してくれます👏

## まとめ
細かな記法を気にせず進めるために導入しましたが、
記法ミスがあっても勝手に修正されるのは気持ち的にかなり楽です。

## 参考URL
- [Swiftの静的解析ツール「SwiftLint」のセットアップ方法](https://qiita.com/uhooi/items/bf888b53b4b8210108aa#mint)
- [XcodeのBuild Phasesでmintを実行する時の注意点](https://qiita.com/temoki/items/b0912f97d8e3fe7b0210)
- [[iOS]Mintを使ってプロジェクトごとのSwift製CLIツールのパッケージ管理を行う](https://dev.classmethod.jp/articles/package_management_by_mint)
- [Swiftlint](https://github.com/realm/SwiftLint)

先人の知恵に感謝...🙏🙏🙏
おわり
SQL*PLUSで日付型をWHERE句で比較するときの注意点

# SQL*PLUSで日付型をWHERE句で比較するときの注意点


Oracle SQL*PLUSで日付型をWHERE句で比較するときの注意点について備忘録として記載する。

# 例題
Oracleデータベース テーブル構成

テーブル名：NAME_TABLE
名称　　　：NAME     ：VARCHAR2
使用開始日：STARTDATE：DATE
使用終了日：ENDDATE  ：DATE

※STARTDATE、ENDDATEは時分秒は入れない。(00:00:00になっている)
※日付型のフォーマット(nls_date_format)は'YYYY/MM/DD HH24:MI:SS'形式となっている。


上記テーブル構成で現在日付(SYSDATE)において有効な名称(使用開始日 ≦ 現在日付 ≦ 使用終了日の名称)を取得する場合のSQL

```

SELECT NAME FROM NAME_TABLE
WHERE
 STARTDATE <= TRUNC(SYSDATE)
AND
 ENDDATE >= TRUNC(SYSDATE);

または 
SELECT NAME FROM NAME_TABLE
WHERE
 STARTDATE <= TO_DATE(TO_CHAR(SYSDATE,'YYYY/MM/DD')) 
AND
 ENDDATE >= TO_DATE(TO_CHAR(SYSDATE,'YYYY/MM/DD')); 
```

TRUNCまたはTO_CHARとTO_DATEを使用して、SYSDATEの時分秒部分をカットして比較する。


TRUNC使用方法
文法
　TRUNC ( datetime [, format] ) 
　return [ date ] 
引数
　datetime：切り捨てを行なう日時式（DATE 型）
　format：切り捨てする時間の要素(デフォルトは'DD'のため上記例題では時分秒部分をカットする)
戻り値
　切り捨てられた日付(DATE 型)


# 参考

・現在の日付型のフォーマットの確認方法

```
SQL> select sysdate from dual;

SYSDATE
--------
2020/12/03

→YYYY/MM/DD形式になっている
```


・接続しているセッションのみ、フォーマット形式を変更する方法(YYYY/MM/DD HH24:MI:SSに変更する場合)

```
SQL> alter session set nls_date_format='YYYY/MM/DD HH24:MI:SS';

session SETが変更されました

SQL> select sysdate from dual;

SYSDATE
-------------------
2020/12/03 12:00:00

→YYYY/MM/DD HH24:MI:SS 形式になっている
```
iOSでの新規開発について考えてみた ~ 2021年初頭版

## はじめに
- iOS開発状況は年々変わってきています。SwiftUI、CombineなどApple純正のフレームワークも進化しています。まず現状の分析を踏まえて、今後の展望についても考えてみました。個人的な思いも入ると思うのでご了承ください

## 前提
```
Xcode 12.2
Swift 5.3.1
deployment target iOS13
```

### ライブラリ管理
- Swift Packager Manager
- Cocoa pods
- Carthage
    - ライブラリ管理では上記の３つが選択肢にあがります。今後の展望を考えるとApple純正の`Swift Packager Manager`を優先的に使いたいです。
    - `Carthage`に関して、[Xcode12Workaround](https://github.com/Carthage/Carthage/blob/master/Documentation/Xcode12Workaround.md)、Apple Siliconの対応がうまくいっていないのが現状です。
    - `Swift Packager Manager` > Cocoa pods > Carthageの優先度で使って、将来的には`Swift Packager Manager`を寄せていきたいです

### Architecture
- MVC
- MVVM
- Redux or Flux or [TCA](https://github.com/pointfreeco/swift-composable-architecture)
    - SwiftUIの実装が増えていくと思いますのでCombineとの組み合わせを考えると`MVVM`がメインのアーキテクチャになると思います。複雑な画面と状態管理が必要なのであれば、Reduxなどのアーキテクチャを採用するのもありだと思います。個人的には仕様に合わせて、画面ごとにアーキテクチャを変えて、メンテしやすくする方針にすることが多いです。
    
### Network
- [Alamofire](https://github.com/Alamofire/Alamofire)
- URLSession
    - 個人的にはAlamofireはオーバスペック感を感じて実装中にほとんどの機能を使わずにいることがほとんどです。さらに大きいライブラリなのでメンテコストが高くなります。個人的にはURLSessionを必要な部分だけ拡張する方が運用しやすいと思っています。

### UI
- UIKit
- [SwiftUI](https://developer.apple.com/tutorials/swiftui/)
    - メインでは`SwiftUI`を使うことになりますがまだ対応できないUIは無理をせずに`UIKit`を使うことになると思います。
    - `SwiftUI`と`UIKit`の共存環境は2年ぐらい続くことを考えて、実装することを頭に入れておくといいと思います。

### DataBinding
- Combine
- [RxSwift](https://github.com/ReactiveX/RxSwift)
    - 今後はApple純正のCombineが主流になっていくと思うのでCombineで実装していくことをお勧めします

### Image Cache
- [kingfisher](https://github.com/onevcat/Kingfisher)
- [Nuke](https://github.com/kean/Nuke)
    - 画像取得とキャッシュのライブラリとして、パフォーマンスとSwiftらしい設計で書かれたNukeを積極的に使いたいです。

### Tracking
- [Firebase](https://github.com/firebase/firebase-ios-sdk)
    - 様々な機能と連携を考えると`Firebase`一択になります。

### Resource
- [R.swift](https://github.com/mac-cain13/R.swift)
- [SwiftGen](https://github.com/SwiftGen/SwiftGen)
    - ImageやStringの呼び出しをType Safeに扱える様にするライブラリです
    - カスタマイズ性を考えると`SwiftGen`をおすすめします

### Lint
- [SwiftLint](https://github.com/realm/SwiftLint)
- [SwiftFormat](https://github.com/nicklockwood/SwiftFormat)
- 追記 [apple/swift-format](https://github.com/apple/swift-format)
    - Lintは長期的にメンテされている`SwiftLint`、`SwiftFormat `が選択肢に入ります。
    - Apple製の`swift-format`も注目です

## まとめ
- iOS開発状況は年々変わってきています。
- 状況に合わせて、柔軟に対応できる環境、アーキテクチャを選ぶことを個人的にお勧めします。
CentOS8だとSSHエージェントが使えない件(libsshのrpmbuild)

[前回：net-snmp-perlのrpmbuild](https://qiita.com/hatman621221/items/cf6be57b9531beaba2e9)

うん、そうなんだ。実はnet-snmp-perlだけじゃないんだ。
SSHエージェントを動かしても値が取れないんだ。

「Cannot read data from SSH server」とか出ると思う。
君は「ZABBIXの設定ミスかな」と疑うだろう、違うんだ。

[libssh(0.9.0.4)のバグなんだ](https://www.miraclelinux.com/support/miracle-zbx50/zbx-support/ssh-monitoring-not-work-on-ml8)

dnfインストールするとこれが落ちてくるから気をつけるんだ。

## 試してないけど一番はやい方法

[CentOS8-stream用のリポジトリ](http://ftp.riken.jp/Linux/centos/8-stream/BaseOS/x86_64/os/Packages/)から持ってくるのが一番てっとり早いかも。
http://ftp.riken.jp/Linux/centos/8-stream/BaseOS/x86_64/os/Packages/libssh-0.9.4-2.el8.x86_64.rpm


これに気づく前にRPMビルドして作成してしまった。

##  適当なユーザで最新版ソースを持ってくる

    $ mkdir libssh
    $ cd $_
    $ git clone https://git.centos.org/centos-git-common.git
    $ git clone https://git.centos.org/rpms/libssh.git
    $ cd libssh/
    #### 持ってくるソースを確認
    $ git tag
    #### チェックアウト
    $ git checkout imports/c8/libssh-0.9.4-2.el8

## ビルドする

    $ sh ../centos-git-common/get_sources.sh
    #### できてるか確認。libssh-0.9.4.tar.xzがあるはず
    $ ls -l SOURCES/
    $ rpmbuild --define "%_topdir `pwd`"  -ba SPECS/libssh.spec 

### ビルドにコケたらこれを見て。

ビルドにはこれらが必要だった

    $ sudo dnf install doxygen --enablerepo PowerTools

## インストール

    $ cd RPMS
    $ sudo rpm -Uvh noarch/libssh-config-0.9.4-2.el8.noarch.rpm x86_64/libssh-0.9.4-2.el8.x86_64.rpm x86_64/libssh-devel-0.9.4-2.el8.x86_64.rpm 
    #### libを確認する 4.8.5を向いてるならOK
    $ sudo ls -l  /usr/lib64/libssh.so*
    lrwxrwxrwx 1 root root      11 12月  3 10:02 /usr/lib64/libssh.so -> libssh.so.4
    lrwxrwxrwx 1 root root      15 12月  3 10:02 /usr/lib64/libssh.so.4 -> libssh.so.4.8.5
    -rwxr-xr-x 1 root root  465192 12月  3 10:02 /usr/lib64/libssh.so.4.8.5
真理値表から論理式を求める。 その2

# 概要

sympyで真理値表から論理式を求める。
and,or,not,nand,nor,xorやってみた。

# サンプルコード

```
import sympy as sym



print(">and")
print(sym.POSform(['a', 'b'], [[1, 1]]))
print(sym.SOPform(['a', 'b'], [[1, 1]]))
print(">or")
print(sym.POSform(['a', 'b'], [[1, 1], [0, 1], [1, 0]]))
print(sym.SOPform(['a', 'b'], [[1, 1], [0, 1], [1, 0]]))
print(">not")
print(sym.POSform(['c'], [[0]]))
print(sym.SOPform(['c'], [[0]]))
print(">nand")
print(sym.POSform(['a', 'b'], [[0, 0], [0, 1], [1, 0]]))
print(sym.SOPform(['a', 'b'], [[0, 0], [0, 1], [1, 0]]))
print(">nor")
print(sym.POSform(['a', 'b'], [[0, 0]]))
print(sym.SOPform(['a', 'b'], [[0, 0]]))
print(">xor")
print(sym.POSform(['a', 'b'], [[1, 0], [0, 1]]))
print(sym.SOPform(['a', 'b'], [[1, 0], [0, 1]]))

```

# 実行結果


```


>and
And(a, b)
And(a, b)
>or
Or(a, b)
Or(a, b)
>not
Not(c)
Not(c)
>nand
Or(Not(a), Not(b))
Or(Not(a), Not(b))
>nor
And(Not(a), Not(b))
And(Not(a), Not(b))
>xor
And(Or(Not(a), Not(b)), Or(a, b))
Or(And(Not(a), b), And(Not(b), a))


```

# 成果物

https://paiza.io/projects/srBomRbfCisdurw8FwEp3w

以上。
【JS】２次元配列を１次元にする方法。reduce & concatで多次元配列の次元を１つ下げる方法。

reduceとconcatを使うことで２次元配列を１次元にすることができる。



##できること

`[[1,2], [3,4]]`のような配列を、内側のカッコを外して`[1,2,3,4]`とすることができる。


##実例

```js:
arr = [[1, 2], [3, 4], [5, 6]]

res = arr.reduce( (newArr,elem) => {
  return  newArr.concat(elem)
}, [] )

console.log(res)   //[1, 2, 3, 4, 5, 6]
console.log(arr)   //[[1, 2], [3, 4], [5, 6]] 非破壊
```

- `配列.reduce( (処理結果, 要素) => 処理, 初期値 )`
    - reduceは指定した配列の要素を一つづつ取り出し、記述した処理を実行し、最後の処理結果を返す。（値は一つ）
    - 第１引数が処理結果、第２引数が配列の一つ一つの要素が入る変数。
    - 処理の後ろに「 , 」をつけて処理結果の初期値を指定できる。
        - newArrの初期値を空の配列にしている。
    - reduceは非破壊処理。
    - 元の配列はそのまま。（上記ではarr）
    - 処理結果を代入する変数を用意。（上記ではres）


- `配列.concat(要素)`
    - concatは指定した配列の後ろに要素を足す


**▼上記処理を段階的におうと以下のようになる**

| 処理回数 | newArr | elem | 処理結果 |
|:-:|:--|:--|:--|
| 1  | []  | [1, 2]  | [1, 2]  |
| 2  | [1, 2]  | [3, 4]  | [1, 2, 3, 4]  |
| 3  | [1, 2, 3, 4] | [5, 6]  | [1, 2, 3, 4, 5, 6]  |

よって、最終的に [1, 2, 3, 4, 5, 6] が返る。


<br>
##returnの有無
reduceの処理で`{ }`をつける場合はreturnが必要。ない場合は不要となる。

```js:return必須
res = arr.reduce( (newArr,elem) => {
  return  newArr.concat(elem)
}, [] )
```

↑↓　どちらも同じ処理

```js:return不要
res = arr.reduce( (newArr,elem) => 
   newArr.concat(elem)
, [] )
```

これは、アロー関数で処理結果が一つの値のみを返す場合`{ return }`が省略可能なため。

処理結果の中に複数の式が入る場合や、処理が長く塊が見にくい場合などに、{ }を使う。




<br>
##多次元配列の場合
reduce & concatは多次元配列でも利用できる。
多次元配列の場合は、各の要素の　`[ ]`を一つ取り除く（次元を一つ下げる）処理となる。


```js:３次元→２次元
arr = [[[1,2]],[[3,4],[5,6]]]

res = arr.reduce( (newArr,elem) => 
   newArr.concat(elem)
, [] )

console.log(res) //[[1,2],[3,4],[5,6]]
```

<br>
**▼3次元を１次元にする**

3次元配列を1次元にしたい場合は、reuduce & concatの処理結果に、再度reduce & concatをかければいい。

```js:
arr = [[[1,2]],[[3,4],[5,6]]]

res = arr.reduce( (newArr,elem) => 
            newArr.concat(elem), [] 
            ).reduce( (newArr2, elem2) => 
            newArr2.concat(elem2), [] )

console.log(res) //[1, 2, 3, 4, 5, 6]
```


<br>
##異なる次元の要素が含まれる場合
異なる次元の要素が混在していてもreduceは使用可能。

この場合、reduce & concat 1回につきカッコが一つ外れる。カッコがない要素はそのまま出力される。

**▼例**

`[1, [2,3,[4,5]],[6,7,[8,9],10]]`

　↓ reduce & concat

`[1, 2, 3, [4, 5], 6, 7, [8, 9], 10]`

```js:
arr2 = [1, [2,3,[4,5]],[6,7,[8,9],10]]

res2 = arr2.reduce( (newArr,elem) => 
   newArr.concat(elem)
, [] )

console.log(res2) //[1, 2, 3, [4, 5], 6, 7, [8, 9], 10]
```


**▼処理の流れ**

| 処理回数 | newArr | elem | 処理結果 |
|:--|:--|:--|:--|
| 1  | []  | 1  | [1]  |
| 2  | [1]  | 2, 3, [4, 5]  | [1, 2, 3, [4, 5]]  |
| 3  | [1, 2, 3, [4, 5]]  | 6, 7, [8, 9], 10 | [1, 2, 3, [4, 5], 6, 7, [8, 9], 10] |
Laravelでprivateなディレクトリを作成する

なんか良い見本がなくて試行錯誤したのでメモ。

## やりたいこと

/private以下のすべてのリソースは、認証された状態でないとアクセスできないようにする。SPAで作った管理画面的なアプリケーションを、認証されていない人に見せたくなかったため。

## 実装

```php
# routes/web.php

// private_web中でAuthenticateミドルウェアを適用している
Route::group(['middleware' => ['private_web']], function() {
    Route::get('/private/{path?}', 'PrivateController@index')->name('private')->where('path', '.*');
});
```

```php
# app/Http/Controllers/PrivateController.php

namespace App\Http\Controllers;

use App\Consts;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use League\Flysystem\FileNotFoundException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

class PrivateController
{

    public function index(Request $request, $path = null)
    {
        try {
            // リソースはstorage/app/private以下に配置する想定
            $storage_path = 'private/' . ($path ?: "index.html");

            // 拡張子からMimeTypeを取得する。
            // 拡張子がない、あるいは未知の場合は対象のファイルを調べてMimeTypeを取得する。
            // Storage::mimeTypeより拡張子を優先するのは、Storage::mimeTypeだと
            // css等のMimeTypeをtext/plainにされてしまい、ブラウザでCSSが適用されなくなったりするため
            $matches = [];
            $mime_type = null;
            if (preg_match('/\.(\w+)$/', $path, $matches)) {
                // EXT_TO_MIMEの中身はこちらから拝借 https://gist.github.com/raphael-riel/1253986
                $mime_type = Consts::EXT_TO_MIME[$matches[1]] ?? null;
            }
            if (!$mime_type) {
                $mime_type = Storage::mimeType($storage_path);
            }

            $headers = [ 'Content-Type' => $mime_type ];

            return Storage::response($storage_path, null, $headers);

        } catch (FileNotFoundException $e) {
            throw new NotFoundHttpException($request->path() . " is not found.", $e);
        }
    }
}
```
プロジェクトを大失敗させたくないあなたに

# 枕
#### はじめまして
嘘です。実は去年のアドベントカレンダーも書いているのではじめましてではありません。

AFグループのとあるサービスで開発マネージャをやっております。Qiitaのプライベートアカウントは初々しい昔の自分丸出しなので公開できません。よろしくお願いします。

さて、今年が仮にコロナ禍でなかったとしても年末年始は自宅待機＆作業予定だったので、そんな恨み節を込めて今年は書かせていただこうかと思います。

恨み節を書いたところでMAYDAYはやってくるのですが、
どうせ来るなら糧になるよう、ポジティブな記事にしようと書き始めの今の今は思ってます。

**P.M.A!!**



#### 書きたいこと
P.M.A!!とか書いておきながら早速なんですが、エンジニア経験が長くなってくると

- プロジェクトがスケジュール通りに進まない
- 要求事項と実装が若干違っていた
- 全く意図しない想定外の挙動をしている
- なぜか動いている

など大なり小なりよくあると思います。
その規模が大きくなればなるほど
「**このプロジェクト失敗だね**」と言われ
ポンッ、と肩に手を置かれる可能性は高まります。

そこで

風邪をひいたり、仕様変更があったり、予定していない状況になった場合でも、最終的にプロジェクトオーナーや依頼主が納得した状態になるようなプロマネtipsを書ければなーと思います。
※プロマネ以外の人でも概念を理解してもらえれば人生tipsになるかと


# 本編

まずは

#### 1. プロジェクトの失敗ってなんだっけ？
複数日や複数人に渡るプロジェクトでは
プロジェクトの失敗と言うと、ざっくりこんな感じの結果が浮かびます。


```
    - Q)　リリースしたけどバグだらけ
    - C)　予算以上の開発コストが発生してしまう
    - D)　納期に間に合わない
```
要は、**当初予定していたGOALからズレること**です。

#### 2. プロジェクトが失敗するのはなぜ？
誰しもがプロジェクトを失敗したくないと考えているのに、なぜプロジェクトは失敗してしまうのでしょうか。

```
- プロジェクトの失敗原因の一例
    - スケジューリングがそもそも甘い、無理をしている
        - 雑な見積りで「できる」って言っていませんか？
        - 納品物の種類、提出タイミングは合意されてますか？
        - ドキュメントレビューはちゃんとしてますか？されてますか？
    - 設計が悪い
        - ドキュメントは最後にまとめてコードから逆起こしなんて考えてませんか？
        - 細かい疑問は作りながら解決だ！なんて思ってませんか？
        - 課題管理を行い、複数人で合意までしていますか？
        - ドキュメントレビューはちゃんとしてますか？されてますか？
    - コーディングが悪い
        - 何も考えずに類似ロジックの使い回ししてませんか？
        - 影響範囲は特定できていますか？確認はしていますか？
        - コードレビューはちゃんとしてますか？されてますか？
    - テストが悪い
        - 少し疑問が出ても自分の解釈でOKにしていませんか？
        - エビデンスは取ってますか？
        - ドキュメントレビューはちゃんとしてますか？されてますか？
```
これらは一例ですが、開発工程毎に違った理由の原因があると思います。
しかも大体、**本人はやっているつもり**、だったりします。

#### 3. プロジェクトを失敗させないためにはどうしたら良い？
```
    - レビュー
    - 課題管理
    - エビデンス
```
↑で書いてしまいましたが、上記のような **複数人による合意** が必要なタスクを真面目にルールに沿って実施する事です。
合意形成をしっかりやれば、少なくとも大きな失敗にはなりません。
**本人はやっているつもり**、も第三者の目を入れる事で軌道修正されます。

#### 4. ではなぜプロジェクトの大失敗が往々にしてあるのか
簡単です。

```
    - レビュー
    - 課題管理
    - エビデンス
```
がおざなりだからです。
もっと細かく言うと、ドキュメントやコーディング時も適宜複数人と認識を合わせる事で、スケジュールや仕様の方向が若干ずれた時に最小限で軌道修正できます。例のアレみたいに。
![mini-4wd.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/926812/dfc0e460-df78-29da-9a18-6236d8b701e2.jpeg)

大げさと思われるかもしれませんが

```
- 目次
- 大項目
```

↑を書いたタイミングでまずレビューをしてもらい、合意してもらう事でプロジェクト関係者全員が同じ方向に進んでいる事の確認と、合意がある事でリスクヘッジ、責任分担もできる事になります。

# まとめ
趣味や個人でなく、複数人による開発をしていると

```
- こんな質問して怒られないかな、笑われないかな
- レビューしてもらって指摘されたら落ち込んじゃう
- スケジュールが遅れているなんてお客様に言ったら怒られちゃうかも
```
こんなはたから見ればどうでも良いことが、本人にはプレッシャーだったりする事があります。
実際、私はありました。今でも全部は払拭できていないと思います。
しかし、社会人としてチーム開発をする以上は個人ではなくチームの結果を最重要項目として考え、
逆にレビューをしてもらう事で自分のミスをチームのミスにヘッジできるという考えをオススメしたいと思います。

以上、聞くは一時の恥聞かぬは一生の恥、でした
本人負担ゼロの携帯電話「つながる電話」を作って運営しているという話

2017年にふとしたきっかけで困っている妊婦さんたちを手助けする助産師さん、看護師さん、お医者さん、社会福祉士さんたちの団体が手作りで運営していた電話相談サービスにTwilioのコンタクトセンターを寄贈したところ、皆さん社会起業家として大活躍されて、今ではなんと[特定非営利団体として公共の事業としての妊娠葛藤相談を受け付けるサービスを提供する](https://piccolare.org/)までに成長したというすごい体験をしたのですが、2020年には逆に皆さんのお力を拝借して新たにまたTwilioを使って今度は生活が困窮された方を電話で支援するサービスを立ち上げました。

[「つながる電話」プロジェクト](https://umbrellafund.tokyo/tsunagarudenwa)

[コロナ禍で困窮され「携帯電話」を失っている方々へ本人負担ゼロで電話をお渡しする「つながる電話」プロジェクトを開始。誰もがすまいや仕事へつながることができる社会の実現へ](https://prtimes.jp/main/html/rd/p/000000001.000061703.html)

[コロナ禍で携帯電話を失った方へ本人負担ゼロで電話を提供する「つながる電話」](https://www.mdn.co.jp/di/newstopics/74122/)

現代の社会では電話を受けられることが就職や住居の契約といった生活の根本となるサービスを受けるための最低条件となっています。しかし、経済的な事情や暴力などの被害から逃れてきた方々にとって電話の契約は敷居が高く難しいものであるため、本人の努力だけでは現状から脱出するための最初の一歩を踏み出すことさえままならないという事情があります。

そこで、各支援団体の皆さまと一緒に、事情のある皆さんに携帯電話を使ってもらおうというのがこのサービスです。

開発にあたってはいくつかの制限事項をもうけました。まず、社会的に弱い立場に置かれてしまいがちな人たちが安全に利用できるよう、発信先についてはこちらで指定した番号にしか電話をかけることができません。データ通信専用のSIMを利用することで通話は全て運用側のサーバでコントロールしています。

サーバ側は運用の人手があまりかけられないので、AWS上にAPI GatewayとLambdaで実装して基本的なサーバ管理の手間を省くことによりランニングコストを下げています。この構成の場合、通話数が一定数を超えるとコストがリニアに増えていくことになりますが、現在のところ特に問題とはなっていないようです。

[iOS向けSDK](https://www.twilio.com/docs/voice/voip-sdk/ios)を利用した電話といえば[Sansan社さんの事例などがあります](https://buildersbox.corp-sansan.com/entry/2020/11/04/110000)が、仕組みとしてはだいぶ似たものになっていますね。iOSの電話帳まわりはAPIが非公開のものも多くあまり自由にできない難点がありますが、通話の受発信については電話状況がしっかりしていれば問題はないようなので（逆に格安SIMで電波状態が悪いと当然ながら厳しいことがあります）、ビジネス利用ももっと広がる可能性があると思います。特に日本はTwilioのSMSが基本的にいまだに国際SMSだったりするのでiOS/AndroidのSDKを使った面白いサービスを作って通知はAPNsやFCMに任せてしまう方が何かと便利かもしれません。

この手のプロジェクトって米国のTwilioだと経済的に支援を受けるプログラムがあったりするんですが、日本だとメールで申し込むことになっているのになかなか返信がなかったりして、誰もサポートしてくれそうにないし困ってるんですよね。またどっかのハッカソンにでも潜り込んで賞金をもらって寄付してしまおうかな。

さて、電話が結構うまくいっちゃったので、実はもうこの次のプランも着々と進めています。今度はwifiをなんとかしようというのがテーマです。こうご期待。