OmniAICreator/Qiita-1.07M huggingface dataset:
【ふくだ学習録】Docker入門 part6【25日目】

# ふくだ学習録とは？
ふくだが学習したことの備忘録。
目に見える形で残すことによってやる気を出す個人的な作戦です。
他人に見せるように書いているわけではないので、すごく読みにくいです。

### 読了した本
[データベースエンジニア養成読本 [DBを自由自在に活用するための知識とノウハウ満載!]](https://www.amazon.co.jp/dp/4774158062/ref=cm_sw_r_tw_dp_U_x_FPphEbQFPPQRM )
[ゼロから作るDeepLearning](https://www.amazon.co.jp/dp/4873117585/ref=cm_sw_r_tw_dp_U_x_y3UiEbF3P6EG7)
[PHPフレームワーク CakePHP 3入門](https://www.amazon.co.jp/dp/4798048577/ref=cm_sw_r_tw_dp_U_x_.YIjEbS1K4JY2)
[SQLアンチパターン](https://www.amazon.co.jp/dp/4873115892/ref=cm_sw_r_tw_dp_U_x_XlokEbJQK2N7P )

### 今読んでいる本

[Docker入門](https://www.amazon.co.jp/dp/480071091X/ref=cm_sw_r_tw_dp_U_x_xVlmEbN8ZTHZK)

# Docker入門

### docker run -it
コンテナ内でシェルを稼働させてコマンド操作するときのお決まりのコマンド。-iオプションと-tオプションの組み合わせ。
-iオプションは、コンテナ内で実行するプロセスの標準入力をオープンし続けるオプション。
-tオプションは、コンテナに仮想コンソールを割り当てて、それをコンテナ内で実行するプロセスの標準入力に接続するオプション。

### docker exac -it　と　docker run -it の違い
exacはあくまで起動中のコンテナに対しての操作なので、停止中のコンテナにコマンドしてもエラーになる。
runは起動するコマンドなので、停止中のコンテナに対して指定して起動&シェル操作することができるようになる。

### コンテナの「一時停止」と「稼働停止」の違い
コンテナは稼働が止まってしまうと、ボリュームなどに格納していない情報は揮発してしまう。
一時停止の場合は、あくまで稼働状態のまま、プロセスを停止することになるので、情報が揮発しない。
一時停止させるためのサブコマンドは`pause`。

### stopサブコマンドとkillサブコマンドの違い
stopサブコマンドは、稼働中のコンテナ内で最初に起動したプロセスに停止信号を送り、一定時間待つコマンド。一定時間（デフォルトでは10秒）待ったのちに、それでもプロセスが終了しなかった場合に、KILLシグナル（強制終了信号）を送信してプロセスを停止させる。
一方killサブコマンドは、初っ端からKILLシグナルを送る。

### initサーバーとは？
Linux（Unix）において、システムの初期設定やプロセス管理などを担当するサーバ。
主な種類としては、**SvsV init**,**Upstart**,**systemd**の３つがある。

Dockerサーバーの制御方法は、これらのどのinitサーバーを使用しているかでコマンドなどが変わってくる。
自分のLinux環境がどの環境で動いているのかを把握すべし！

### Dockerサーバー環境の初期化
Dockerサーバーは、取得したイメージや稼働したコンテナ関連のデータを、既定設定で`/var/lib/docker`ディレクトリ以下に配置している。このディレクトリ以下の内容を削除することにより、インストール直後の状態に戻すことができる。

インストール前の状態にしたいときは、`/var/lib/docker`ディレクトリごと決してしまえばいい。

### docker -H　を使用する場面
docekrサーバーとdockerクライアントを、別々のホスト上で稼働させたいときに使用する。

通常の運用（同一ホスト内で稼働させるとき）では、オーバーヘッドが少なく効率的に通信できるUNIXドメインソケットを使用した方がいいため、既定では特定のUNIXドメインソケットからのコマンドやデータを待ち受けるようになっている。

そのため、別々のホスト上で稼働させるとき、つまりTCP通信ポートを使用して通信する必要があるときは。`docker -H`で使用するTCPポートを指定する必要がある。

### DockerクライアントがTCP通信ポートを使用するようにする方法
`DOCKER_HOST`という環境変数に、使用したいDockerサーバーのIPアドレスやポート番号などを指定の形式で保存しておく。

### Dockerのストレージドライバ
ストレージドライバとは、コンテナのファイルシステムやイメージの差分管理のための手段を提供するドライバ。
Linuxで稼働するDockerサーバーは**「aufs」「btrfs」「zfs」「devicemapper」「overlay」「vfs」**の６種類のストレージドライバを切り替えて使用できる。（バージョン１．9時点）

現在使用中のストレージドライバは、次のコマンドで確認できる。

```console
$ docker info | grep "Storage Driver"
```

各ストレージドライバの特徴は下記サイトを参考にする。

[ストレージ・ドライバの選択](http://docs.docker.jp/v1.9/engine/userguide/storagedriver/selectadriver.html)
[Dockerのストレージドライバを理解する](https://qiita.com/NaotoHanaue/items/b9f395a63f7aae2a41b7)


# 今日の一言
以前にインフラ周りの本を読んでたおかげか、わからない単語とか知らない概念が少なくて、メモ書き減ってきた！
そして読むスピードも上がってきた！ええ兆候。寿司食いたい。
Mysqlのレプリケーションの状態を確認する

## Mysqlのレプリケーションステータスの確認コマンド

SHOW SLAVE STATUS によって返されるフィールドについて説明は参考に貼ってあるリファレンスを見る。

```
$ mysql -h {{ host }} -u{{ user }} -p -p -e 'SHOW SLAVE STATUS\G'

Enter password:
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: XXX.XXX.XXX.XXX
                  Master_User: sample-repl
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysqld-bin.000001
          Read_Master_Log_Pos: 14900000
               Relay_Log_File: relaylog.012729
                Relay_Log_Pos: 1000
        Relay_Master_Log_File: mysqld-bin.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB:
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 0
                   Last_Error:
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 14900000
              Relay_Log_Space: 4500
              Until_Condition: None
               Until_Log_File:
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File:
           Master_SSL_CA_Path:
              Master_SSL_Cert:
            Master_SSL_Cipher:
               Master_SSL_Key:
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error:
               Last_SQL_Errno: 0
               Last_SQL_Error:
  Replicate_Ignore_Server_Ids:
             Master_Server_Id: 1
                  Master_UUID: 3e11fa47-71ca-11e1-9e33-c80aa9429562
             Master_Info_File: /var/mysqld.2/data/master.info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
           Master_Retry_Count: 10
                  Master_Bind:
      Last_IO_Error_Timestamp:
     Last_SQL_Error_Timestamp:
               Master_SSL_Crl:
           Master_SSL_Crlpath:
           Retrieved_Gtid_Set: 3e11fa47-71ca-11e1-9e33-c80aa9429562:1-5
            Executed_Gtid_Set: 3e11fa47-71ca-11e1-9e33-c80aa9429562:1-5
                Auto_Position: 1
```
## 参考
[MySQL :: MySQL 5.6 リファレンスマニュアル :: 13.7.5.35 SHOW SLAVE STATUS 構文](https://dev.mysql.com/doc/refman/5.6/ja/show-slave-status.html)
Splunk8.xにいきなり！Upgradeする前に必ずチェック!

はじめに
---
- 7.2/7.3系から8.0にいつものノリでupgradeした結果痛い目に会った話です
- 痛い目とは？
    - 8.0upgrade後に**Splunk Webサービスが起動しない事象が発生**
    - 「Web interface does not seem to be available」
- 原因は？
    - 類似事象で困っているAnswerを発見
        - [Update to 8.0 - Web interface does not seem to be available](https://answers.splunk.com/answers/778947/update-to-80-web-interface-does-not-seem-to-be-ava.html)
        - [Splunk 8.0 upgrade has no web server running
](https://answers.splunk.com/answers/777309/splunk-80-upgrade-has-no-web-server-running.html)

>(以下、コメント原文)  
>>1. We removed 99% of the underlying AdvancedXML modules in Splunk 8.0. This means trying to make a custom module that inherits from one that no longer exists is going to fail. It sounds like search_activity still uses AdvancedXML, so in order for that app to work with 8.0 it would have to be ported.

>>2. When you have a python import exception in the appserver/splunkweb layer, CherryPy, the appserver/splunkweb, will not start. So, because 1 is failing on import, it breaks splunkweb.

### 要するに
- AdvancedXML modulesの99%を8.0ではカットしたので、それを使っている場合、失敗する可能性がある。事前に移行する必要あり。
- appserver / splunkwebレイヤーにPythonインポート例外がある場合、appserver / splunkwebであるCherryPyは起動しません。 
- おそらく私の環境のAppも依存関係に引っかかって上記事象にあたっていると思います。どのappが影響しているかが、以下のログから特定できればよかったのですが、私の場合App名が載っていなかったので原因の完全特定ができず。
    - /opt/splunk/var/log/splunk/web_service.log
- 対応策としては、原因と思しきAppsのフォルダをCLIから削除するのがベターなアプローチのようです。


## Splunk8からpyhton3系サポートを開始
- python2系の公式サポート終了(2020/01/01)に伴い、Splunk8.0からpython3に一部の機能は移行している（https://docs.splunk.com/Documentation/Splunk/8.0.0/Python3Migration/AboutMigration）


check項目
---
- 7.xから8.0にUpgradeする前に、どのAppを改修/更新しておかないと影響を及ぼしそうかcheckしてくれるappが公開されています
- [Splunk Platform Upgrade Readiness App](https://splunkbase.splunk.com/app/4698/)
<img width="639" alt="スクリーンショット 2020-02-05 9.06.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185759/e83ca8ff-e2d8-45ca-ce77-19658d580155.png">

まとめ
---
- 8.x系にupgradeする前に[Splunk Platform Upgrade Readiness App](https://splunkbase.splunk.com/app/4698/)でチェックを行いましょう。
PHP 変数の誤用

PHPを勉強中です。
サンプルプログラムを作成していて、思ったように動作しないことがあります。
いろいろ、さんざん調べた挙句、変数名が違っていることが往々にしてあります。
たとえば、$_SESSIONを＄SESSIONと記述していたりなどです。
PHPのビルトインサーバーやデベロッパーツールにエラーが表示されれば、助かるのですが、そのような方法は無いのでしょうか？
Google Cloud Platform (GCP)サービスの正式名称・略称・読み方まとめ#1(AI と機械学習/AI ビルディング ブロック)

Google Cloud Platform (GCP)のサービスで正式名称や略称はともかく、読み方がわからずに困ることがよくあるのでまとめてみました。


クラウド コンピューティング サービス  |  Google Cloud
https://cloud.google.com/?hl=ja

## Amazon Web Services (AWS)のまとめはこちら！

Amazon Web Services (AWS)サービスの正式名称・略称・読み方チートシート - Qiita
https://qiita.com/kai_kou/items/cb29d261c8acc49fd22a

Amazon Web Services (AWS)サービスの正式名称・略称・読み方まとめ #1 (コンピューティング) - Qiita
https://qiita.com/kai_kou/items/a6795dbab7e707b0d1a6


## まとめルール

### カテゴリ、並び順

公式サイトを参考にしました。
英語版を主として日本語訳を補助的に参考にしました。

Products & Services  |  Google Cloud
https://cloud.google.com/products?hl=en#product-launch-stages


### 正式名称

各サービスの製品紹介ページのタイトルを正式名称とみなしています。

#### 例

Compute Engine: Virtual Machines (VMs)  |  Google Cloud
https://cloud.google.com/compute/


### 略称

公式の製品紹介やドキュメントなどで省略表記されているものとしています。


### 読み方

正式名称の読み方について、よく利用されているものを主としています。


### 俗称

公式の製品紹介やドキュメントにはないけれど、記事やBLOGで頻繁に略記されているものとしています。

#### 例

- Compute EngineをGCS(Google Compute Engine)
    - 公式では略記されていなさそう


### 概要

サービス一覧ベージの概要を引用しています。

プロダクトとサービス  |  Google Cloud
https://cloud.google.com/products?hl=ja#product-launch-stages



間違いや、こんな呼び方あるよーなどありましたらコメントお願いします！


## AI and Machine Learning(AI Building Blocks) - AI と機械学習(AI ビルディング ブロック)

### Cloud AI building blocks

カスタムモデルや事前トレーニング済みモデルを使用して、アプリケーションに AI を簡単に搭載します。

- 正式名称: Cloud AI building blocks
- https://cloud.google.com/products/ai/building-blocks/
- 読み方: クラウド エーアイ ビルディング ブロック
- 略称: なし
- 俗称: なし


### Cloud AutoML

高品質なカスタム ML モデルを簡単にトレーニングします。

- 正式名称: Cloud AutoML
- https://cloud.google.com/automl/
- 読み方: クラウド オート エムエル
- 略称: なし
- 俗称: なし


### Vision AI

AutoML Vision と Vision API を使用して、画像やテキストなどから分析情報を引き出します。

- 正式名称: Vision AI
- https://cloud.google.com/vision/
- 読み方: ビジョン エーアイ
- 略称: なし
- 俗称: なし


### Video AI

強力なコンテンツ検出機能と魅力的な動画体験を可能にします。

- 正式名称: Video AI
- https://cloud.google.com/video-intelligence/
- 読み方: ビデオ エーアイ
- 略称: なし
- 俗称: なし


### Natural Language

非構造化テキストから有用な情報を引き出します。

- 正式名称: Natural Language
- https://cloud.google.com/natural-language/
- 読み方: ナチュラル ランゲージ
- 略称: なし
- 俗称: なし


### Translation

言語間の翻訳を動的に行います。

- 正式名称: Translation
- https://cloud.google.com/translate/
- 読み方: トランスレーション
- 略称: なし
- 俗称: なし


### Cloud Text-to-Speech

ML によってテキストを音声に変換します。

- 正式名称: Cloud Text-to-Speech
- https://cloud.google.com/text-to-speech/
- 読み方: クラウド テキスト トゥ スピーチ
- 略称: なし
- 俗称: Cloud TTS
  - 参考: https://qiita.com/maKunugi/items/90cbefe97887470fb328
  - 参考: https://www.openhab.org/addons/voice/googletts/


### Speech-to-Text

ML によって音声をテキストに変換します。

- 正式名称: Speech-to-Text
- https://cloud.google.com/speech-to-text/
- 読み方: スピーチ　トゥ テキスト
- 略称: なし
- 俗称: なし


### Dialogflow

デバイスやプラットフォームをまたいだ会話環境を構築します。

- 正式名称: Dialogflow
- https://cloud.google.com/dialogflow/
- 読み方: ダイアログフロー
- 略称: なし
- 俗称: なし


### AutoML Tables (beta)

構造化データに基づいた機械学習モデルをビルドおよびデプロイします。

- 正式名称: AutoML Tables
- https://cloud.google.com/automl-tables/
- 読み方: オート エムエル テーブル
- 略称: なし
- 俗称: なし


### Cloud Inference API (alpha)

型付き時系列データセットの関係付けを、迅速かつ大規模に実行します。

- 正式名称: Cloud Inference API
- https://cloud.google.com/inference/
- 読み方: クラウド インファランス エーピーアイ
- 略称: なし
- 俗称: なし
UUIDをHashidsに変換して戻してみた。

# 目的
DBでUUIDで生成したキーをもとにテーブル分割すると「table_dd6ee086-936c-4dae-bbd7-f94e4203d868」みたいに長くなるのが嫌でなんとか短くしたいです。
base64とかやってみたけど「+,/,=」みたいな記号のハンドリングがめんどくさかったです。
そこでhashidsという数値とアルファベットだけで変換してくれるライブラリがあったのでこれを使いました。
RustとRubyとPostgreSQLで使いたかったので、それぞれ試してみました。

# コード
## Rust
```rust:Cargo.toml
[package]
name = "test"
version = "0.1.0"
edition = "2018"

[dependencies]
uuid = { version = "^0.8", features = ["v4"] }
harsh = "^0.1"
```
```rust:main.rs
fn main() {
    let converter = harsh::HarshBuilder::new().salt("salt goes here!").init().unwrap();
    let my_uuid = uuid::Uuid::new_v4();
    println!("{}", my_uuid);
    let target = converter.encode_hex(&my_uuid.to_simple().to_string()).unwrap();
    println!("{}", target);
    let my_uuid = uuid::Uuid::parse_str(&converter.decode_hex(&target).unwrap()).unwrap();
    println!("{}", my_uuid);
}
```
## Ruby
```ruby:Gemfile
# frozen_string_literal: true

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

gem "hashids"
```
```ruby:main.rb
require 'securerandom'
require 'hashids'

uuid = SecureRandom.uuid
puts uuid
hashids = Hashids.new "this is my salt"
id = hashids.encode_hex(uuid.gsub(/-/,""))
puts id
decoded = hashids.decode_hex(id).downcase
uuid = "#{decoded[0..7]}-#{decoded[8..11]}-#{decoded[12..15]}-#{decoded[16..19]}-#{decoded[20..35]}"
puts uuid
```
## PostgreSQL
```sql
select 
	t3.src
	,t3.simple
	,t3.id
	,hashids.decode_hex(id := t3.id, salt := 'salt')::uuid as dst
from (
select 
	t2.src
	,t2.simple
	,hashids.encode_hex(hex := t2.simple, salt := 'salt') as id
from 
(
select
	t1.src
	,regexp_replace(t1.src::text, '-', '', 'g') as simple
from (
 select gen_random_uuid() as src
) as t1
) as t2
) as t3
```

# 結果
```text
3f44b2e6-d6c4-4d2e-9956-bb56bfd58032
gyBm1Kw7M9u8Ral478g6ixxRXZrB
3f44b2e6-d6c4-4d2e-9956-bb56bfd58032
```

ハイフンを抜くと4文字しか得しませんね😇

# 参考
[hashids](https://hashids.org/)
[PL/pgSQL implementation of Hashids](https://github.com/andreystepanov/hashids.sql)
手に馴染む道具(プログラミング言語)

# はじめに

> 作ったよ！ ⇒ [スクリプト言語 KINX（ご紹介）](https://qiita.com/Kray-G/items/ca08b6fb40d15dd0ec76)

職人は、自分の道具を使えば使うほど手に馴染んで使いやすくなっていく。プログラミング環境でもエディタなんかはそう。そしてプログラミング言語もそう。

プログラミング言語の老舗といえばCであり、多くの職業プログラマはCを通ってきているはず。

そうでもないか。

いや、ある程度のスキルを持っている人はCに精通しているし、アセンブラも分かるだろう。

その前提で、やはり言語仕様(文法)はCライクなものが手に馴染みやすいと思うんだ。そういった点で、JavaScriptは手に馴染みやすい。JavaScript系は割りと好きな部類だ。

## 本題

しかし、世の人気を二分するメジャー・スクリプト言語RubyとPython、どちらもCライクではない。なぜだ。慣れてしまえばそれまでなのだが。

動的型付け言語は散々な言われようだが、スキルさえ問題なければアドホックでスピーディーな開発では超絶な生産性を達成できると思うんだ。

JavaScriptでnode.jsでも良いのだか、あれはもう全くLightweightではないよね。挙動も独特だし。

なぜ動的型付け言語でCライクな汎用かつlightweightなスクリプト言語がない、もしくは人気が無いのか。

という気持ちだけ表明してみた。

本日は以上。
文系の私が「エンジニア組織」で人事をやってみたらとても良かった話

## はじめに
こんにちは。

今回は文系出身の私が、エンジニア組織で約半年働いてみてどうだったか？？というただの感想文です。

「エンジニア組織で働くことに興味あるけど、プログラミングはできないしなぁ。」などお考えの方の文系職の皆様には多少参考になるかもしれません。

## とりあえず自己紹介
名古屋の自社サービスを開発する企業で働いております。@Tooka_91と申します。一応副業も最近始めて、東京の企業でも、リモートで似たようなことをさせてもらっています。

職種は人事という形ですが、業務的にはエンジニア採用一本でやらせていただいております。大学までは、ゴリゴリの文系です(ゼミも哲学だし)。

新卒で、愛知県の自動車部品メーカーに入社。グローバルIT戦略というチームで働いておりました。(約1年半ぐらいですかねぇ。)

新卒の時はやりたいことが本当になかったので、ナゴヤが生んだ「名」企業という本から、行きたい企業を選んで入社しました。(学生さんはあまり参考にしないでほしい、、)

地元(名古屋)で働くことに異様に固執しておりますが、自分でもよく理由が分かっていません。(父が昔いた関西に住んでみたい。という願望はあるので、いずれ行きたい。)

## 前置き
今働く企業は、社員の約8割がエンジニアで構成される、まさに「エンジニア組織」です。

創業者のエンジニアで「誰でもフルリモートOK」「残業なし」「フレックスタイム制」などの働き方が確立しています。(入社した時は、すごすぎて腰ぬかしそうだった。)

前置きはこの辺で。

## では本題へ
では、本題へ入っていきます。文系のバックオフィス業務の人間が「エンジニア組織」へ入社して何がよかったのか？

### 常に努力するのが当たり前

技術の流行り廃りは本当に早いもので、常にキャッチアップが必要になります。そうなると、エンジニアさんは業務外でも結構な時間を使って、努力をされています。

休みの日にtwitterでQiitaの記事がバンバン飛んできたり、技術コミュ二ティの運営をしていたり、登壇をしていたり。

こういう周りの社員の動きを常に感じていると、自分もやらなきゃマインドになってきます。残業がほとんどないので、私も終業後に、最低2時間ぐらいは勉強の時間を確保して、何かしらの勉強をするようにしています。

### コミュニティ文化

技術コミュニティが多くあり、インプット・アウトプット・コミュニケーションを楽しくできるのが本当にいいなぁと思っています。

例えば、RubyKaigi / iOSDC / Droid Kaigi / Vue Fes / Designshipなど、各分野で楽しいお祭りがありますよね。

他にも技術勉強会が頻繁に行われており、「自分の努力してきたこと」を多くの人と共有する機会があるのがとてもいいなぁと思っています。

他社のエンジニアとも多く接点があり、自分を客観視する機会があるのもいいですよね。

私も楽しく勉強していきたいと思い、勉強会を2つ運営しています。(1つは立ち上げたばかりですが。)

これは、現職についてからの話なので、周りのエンジニアにはかなり影響受けています。

### 楽しそうに仕事をしている

自分の会社のエンジニアを見ていると本当に楽しそうに仕事をしているなぁと感じます。(笑い声がめっちゃ聞こえてくるので)

大変なこともあるとは思いますが、すごくいい空気感で働かせてもらっているかなと思います。

仕事は辛い思いをして、苦労して、頑張るものだ！と思い込んでいましたが、楽しく努力をして成果を上げていけばいいんだと思うようになりました。

## おわりに
以上になります。

ざっと簡単に書いてしまったので、思い出したことがあればまた追記していきます。
絵文字で桃太郎を書いてみた。👴⛰️🪓🌲、👵🏞️🧺👕、🍑→👶→👦、👦＋🗡️＋🍡→🏃、👦🍡→🐶🐒🐦、🌊🚣🌊→🏝→🏯、👦🐶🐒🐦⚔️👹、👹→☠️、💰＋👦↪️👴👵

#1　
🏞️🏞️🏞️🏞️🏞️🏞️🏞️🏞️🏞️🏞️🏞️🏞️🏞️🏞️
⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️
🌲🌲🌲🌲🌲🌲👴🪓🌲🌲🌲🌲🌲🌲
🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲
🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲

#2　
⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️⛰️
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
🟩🟩🟩🟩🟩👵🧺👕🟩🟩🟩🟩🟩🟩
🟦🟦🍑🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦
🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩

#3
🍑→👶→👦、

#4
👦＋🗡️＋🍡→🏃、
#5
👦🍡→🐶🐒🐦、
#6
🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲🌲
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
🟩🟩🟩🟩🟩🟩👦🐶🐒🐦🟩🟩🟩🟩
🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊
🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊
🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊
🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊

🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊
🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊
🌊🌊🌊🌊🏝🌊🌊🌊🌊🚣🌊🌊🌊🌊
🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊
🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊



🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊
🌊🌊🌊🌊🌊🌊⛰️🟩🟩🟩⛰️🌊🌊🌊
🌊🌊🌊🌊🌊🌊⛰️🟩🟩🟩⛰️🌊🌊🌊
🌊🌊🌊🌊🌊🌊⛰️🟩🏯🟩⛰️🌊🌊🌊
🌊🌊🌊🌊🌊🌊⛰️⛰️⛰️⛰️⛰️🌊🌊🌊
🌊🌊🌊🌊🌊🌊⛰️⛰️⛰️⛰️⛰️🌊🌊🌊
🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊
🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊
🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊

#7
🟩🟩🟩🟩🟩🟩🟩🟩
🟩👦🐶🐒🐦⚔️👹🟩
🟩🟩🟩🟩🟩🟩🟩🟩

#8
👹→☠️、
#9
💰＋👦↪️👴👵
おしまい
固定幅の親要素の子要素を横幅100%にするCSS

子要素をブラウザ横幅100%表示するCSSです。
レスポンシブデザインでコンテンツが固定幅、画像は横幅100%という場面で
多く使うためmixinで登録しておくと便利です。

#デモ
<p class="codepen" data-height="265" data-theme-id="dark" data-default-tab="result" data-user="harumi-sato" data-slug-hash="OJVLZLv" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="OJVLZLv">
  <span>See the Pen <a href="https://codepen.io/harumi-sato/pen/OJVLZLv">
  OJVLZLv</a> by harumi-sato (<a href="https://codepen.io/harumi-sato">@harumi-sato</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

#コード

横幅をブラウザ幅に設定=100vw
左右のmarginを-50vwで計算している。
（子の数値に影響されずスマートな解決方法ですね！:grinning:）

```SCSS:SCSS
//@include fullsize
@mixin fullsize {
  width: 100vw;
  position: relative;
  left: 50%;
  right: 50%;
  margin-left: -50vw;
  margin-right: -50vw;
}

.contents{
  width:600px; //固定幅
  margin:0 auto;
  background:lightgreen;
}

.child{
  @include fullsize;
  img{
    width:100%;
    height:auto;
  }
}
```

```HTML:HTML
<div class="contents">
  <p>テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。</p>
  <div class="child"><img src="//via.placeholder.com/350x150" alt=""></div>
  <p>テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。テキストが入ります。</p>
</div>
```

#まとめ

-50vwでマイナスmarginを設定するため、
子要素の幅に影響されず横幅100%に指定できる。
[Vue.js]配列の変更が検知できない理由の「JavaScriptの制限」って何よ！

タイトルの`JavaScriptの制限`はこちらに記載されているものです。
[リストレンダリング(注意事項) — Vue.js](https://jp.vuejs.org/v2/guide/list.html#%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A0%85)

要約すると、
配列に対して直接インデックスの設定、またはlengthプロパティを変更する場合、`view`は更新されません。

具体的な操作はこちら。
> インデックスでアイテムを直接設定するとき。例: vm.items[indexOfItem] = newValue
配列の長さを変更するとき。例: vm.items.length = newLength

その回避策が `Vue.set` か `Array.prototype.splice` を使用するというものです。
簡単にできる回避策なので、ふーんって感じで書き換えて終了なのですが、
`JavaScriptの制限`が気になったので調べてみました。

## ざっくり リアクティブシステム
Vue.jsの値の変更の検知の仕組みは、リアクティブシステム[^1]で実現されています。
ざっくり言うと、Vueインスタンス化の際にプロパティに対してリアクティブになるよう、よしなにやってくれるシステムです。

[^1]: [リアクティブの探求 — Vue.js](https://jp.vuejs.org/v2/guide/reactivity.html)

![data.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528526/a219e2ce-68ed-6895-fd47-ea0768261bfb.png)

こちらの図でいうと、プロパティの変更をgetter/setterをトリガーにしてWatcherで再描画してくれているということです。



## んで、`JavaScriptの制限`って何さ！
ヒントはここに書いてありました。
[リストレンダリング(配列の置き換え) — Vue.js](https://jp.vuejs.org/v2/guide/list.html#%E9%85%8D%E5%88%97%E3%81%AE%E7%BD%AE%E3%81%8D%E6%8F%9B%E3%81%88)
> 例えば、filter()、concat()、そしてslice() のような、元の配列を変更しませんが、常に新しい配列を返します。

リアクティブシステムは**新しい配列**を返してくれることを望んでいるんです！

### つまり
`JavaScriptの制限`というのは、`新しい配列を返さない操作`のことを言っているのです。

`vm.items[indexOfItem] = newValue`も`vm.items.length = newLength`も配列を返しません。

## なんだそれだけなのか
それだけなんです。
[リストレンダリング(変更メソッド) — Vue.js](https://jp.vuejs.org/v2/guide/list.html#%E5%A4%89%E6%9B%B4%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89)
ここに書かれているメソッドは新しい配列を返すから検知できるんです。

## まとめ
私の日本語を読む能力が低かったせいで、
`JavaScriptの制限`が配列の`置き換えの章`に掛かっていることに気づくのに時間がかかってしまいました。（汗）

お間違い等ございましたら、ご指摘いただけますと幸いです。:bow:
コマンドプロンプトからWinMergeを操作する


# はじめに

「WinMerge」はスクリプトや設定ファイルの差分を比較する際に重宝していますが、調べ物をしている最中にWinMergeをコマンドラインから操作する方法があることを知りました。

以下のようにコマンドラインでWinMergeを定期的に実行すれば、例えば「たまに更新されるファイルを比較して、更新を検知する」ということが可能になるかもしれません。

# 方法

* 以下のコマンドで2ファイルを比較して、その結果をファイルに出力することができます。
* 「1ファイルずつの比較結果」と「フォルダ単位での比較結果」で、得られる結果ファイルのフォーマットが異なる点に注意してください。
 * 1ファイルずつの場合：HTMLファイル。WinMergeの画面とよく似たフォーマットになっています。
 * フォルダ単位での比較結果 

```
> start WinMergeU {左パネルに表示するファイル/フォルダ} {右パネルに表示するファイル/フォルダ} /or {比較結果の出力先ファイル}
```

## 1ファイルずつの比較結果の例

* 1ファイルずつの比較結果の場合、以下の図のようにGUIで見やすい結果が得られます。
 * 逆に、この結果ファイルをプログラムで解析するのは少々面倒だと思います...

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/312166/214d995b-842a-16e7-3bdf-b2e11882d6b1.png)

## フォルダ単位での比較結果の例

* フォルダ単位での比較結果の場合、以下のように単なるテキストとして結果が出力されます。
 * HTMLで出力されたものよりは、プログラムで解析しやすいと思います。

```result.txt
C:\Users\NKOJIMA\Desktop\a と C:\Users\NKOJIMA\Desktop\b の比較
2020/02/02 18:17:14
ファイル名,フォルダ,比較結果,左日付,右日付,拡張子
..,,,,,
a.txt,,テキストファイルは同一です,  2020/02/02 18:11:37,  2020/02/02 18:11:37,txt
b.txt,,テキストファイルは同一です,  2020/02/02 18:11:44,  2020/02/02 18:11:44,txt
c.txt,,右側のみ: C:\Users\NKOJIMA\Desktop\b,  ,* 2020/02/02 18:16:03,txt
```


# その他

上記のコマンドを実行するとWinMergeが起動したままになってしまうので、処理が完了したら次のコマンドでWinMergeを終了させると良さそうです。

```
> taskkill /IM "WinMergeU.exe"
成功: プロセス "WinMergeU.exe" (PID 2600) に強制終了のシグナルを送信しました。
```

# 参考URL

* [Using WinMerge with other tools](https://manual.winmerge.org/en/Version_control.html)
 * [Using WinMerge with other tools - Command line](https://manual.winmerge.org/en/Command_line.html)
良いURIの設計とは

（Webを支える技術を読んで）WebサービスやWeb APIを作る上でのURI設計の指針についてまとめる。

- URIにプログラミング言語依存の拡張子を使用しない（.rb,.jspなど）
- URIに実装依存のパス名を利用しない（cgi-binなど）
- URIに言語のメソッド名を利用しない
- URIにセッションIDを含まない
- URIはリソースを表現する名詞とする

上の例外として、1つのリソースが複数の表現を持つ時、拡張子をつけることは推奨される。

```
例) 
http://example.jp/resource.html
http://example.jp/resource.json
```


#### 参考

[Webを支える技術 -HTTP、URI、HTML、そしてREST](https://www.amazon.co.jp/Web%E3%82%92%E6%94%AF%E3%81%88%E3%82%8B%E6%8A%80%E8%A1%93-HTTP%E3%80%81URI%E3%80%81HTML%E3%80%81%E3%81%9D%E3%81%97%E3%81%A6REST-WEB-PRESS-plus/dp/4774142042)
CSSメモ

#CSSメモ
タイトルままです。自分用メモですがもし誰かの役にも立てば幸いです。
対応ブラウザ等細かい部分は考慮していません。

##左右均等割

```html
<div class="between">
  <div class="left">
    <p>left<p>
  </div>
  <div class="right">
    <p>right</p>
  </div>
</div>
```

```css
.between{
  display: flex;
  justify-content: space-between;
```

##上下中央配置

```css
.item{
 display: flex;
 align-items: stretch;
```
PUN2 でUserId がnull になっている時の対処法

# 環境
- Windows 10
- Unity 2019.2.19f1
- Photon2 (Photon Unity Networking 2 2.16)

# 症状

```
public class NetworkInterface : MonoBehaviourPunCallbacks
{

    private void Start()
    {
        PhotonNetwork.ConnectUsingSettings();
        PhotonNetwork.JoinOrCreateRoom(_config.RoomName, new RoomOptions(), TypedLobby.Default);
    }

    public override void OnJoinedRoom()
    {
        Debug.Log("Room Max number: " + PhotonNetwork.CurrentRoom.MaxPlayers); 
        Player[] player = PhotonNetwork.PlayerList;

        // プレイヤー名とIDを表示.
        for (int i = 0; i < player.Length; i++)
        {
            Debug.Log((i).ToString() + " : " + player[i].NickName + " ID = " + player[i].UserId);
        }
    }
}
```

上記のコードでルームに数人が入る。最後に入室した人の場合、PhotonNetwork.PlayerList に全員登録されているはずなので、NickName とUserId がすべて入っているはずだが、UserId が自分のもの以外null になっている。

# 対策
RoomOptions を生成するときの、デフォルト値のままではなく、

```
public class NetworkInterface : MonoBehaviourPunCallbacks
{

    private void Start()
    {
        PhotonNetwork.ConnectUsingSettings();
        RoomOptions options = new RoomOptions();
        options.PublishUserId = true; // ★お互いにユーザＩＤが見えるようにする。
        options.MaxPlayers = 3; // ★最大人数もきちんと定義しておく。
        PhotonNetwork.JoinOrCreateRoom(_config.RoomName, options, TypedLobby.Default);
     }

    public override void OnJoinedRoom()
    {
...
    }
}
```

RoomOptions のPublishUserId はデフォルト値がfalse のようなので、true に変更してJoinOrCreateRoom すると意図通りUserId が見えるようになった。
ESP-IDF (Espressif IoT Development Framework): Hello World! 最初のプロジェクト

ESP32での開発はArduinoを使って行うかESP-IDFを使って行うかのどちらかである。Arduinoの方が開発が簡単であると言われるし、私もそんな印象である。が、より高度なことがしたくなった時にESP-IDFが必要になるのだそうだ。ということで、、まずはお決まりのHello Worldをやってみよう。

## 私の環境など

* OS: macOS 10.15 Catalina
* ボード: ESP32－DevKitC
* ESP-IDF: Version 4.1 (masterブランチの最新）

## 環境の構築

多くのサイトで書かれているので、この記事ではmacOSとLinuxのコマンドラインだけを記載する。下記コマンドを実行する前に必要なソフトをインストールしておくことをお忘れなく。詳しくは[本家のチュートリアル](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html)
を参考にされたい。

```
$ pwd
/Users/seiken
$ git clone --recursive http://github.com/espressif/esp-idf.git
$ export IDF_PATH=$HOME/esp-idf
$ cd esp-idf
$ ./install.sh
$ . ./export.sh
```

## 最初のプロジェクト

チュートリアルには、最初のプロジェクトとしてサンプルにあるhello_worldをコピーしてきて使う例が示されている。が、このディレクトリを見るといくつかのファイルが入っていて、すべてのファイルが必要なのか、完全な白紙のプロジェクトを作るためにはなにが必要なのかがわかりにくい。ということで、最低限必要なファイルはなにかを確認してみた。で、必要なのは下記二つのファイルだ。

* CMakeLists.txt
* main/CMakeLists.txt

上記二つのファイルのほかにソースコードが必要だ。mainディレクトリ以下にソースコードを置く。この例ではmain.cというファイルを置いたという想定で記述する。

ではやってみよう。

```
$ mkdir ~/src/FirstProject
$ cd ~/src/FirstProject
$ emacs CMakeLists.txt
```

``` CMakeLists.txt
cmake_minimum_required(VERSION 3.5)

include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(FirstProject)
```

```
$ mkdir main
$ cd main
$ emacs CMakeLists.txt
```

``` main/CMakeLists.txt
idf_component_register(SRCS "main.c"
                    INCLUDE_DIRS "")
```

```
$ emacs main.c
```

``` main/main.c
#include <stdio.h>

int app_main()
{
  printf("Hello ESP32 World!\n");
  return 0;
}
```

## ビルドとボードへの書き込み

いよいよプロジェクトをビルドしてみる。プロジェクトのトップディレクトリに戻って以下を実行する。

```
$ idf.py build
$ idf.py flash
```

これが最低限必要な作業だ。

## そのほか

チュートリアルには、プロジェクトの設定を行うmenuconfigが紹介されている。おそらくほとんどのプロジェクトではソースコードを記述していく前にこのコマンドを実行することになるとは思う。

```
$ idf.py menuconfig
```

以前のバージョンを使われていた方ならばcmakeとかmakeを直接呼び出す方法に慣れていらっしゃるかもしれない。ESP-IDFのV3.xからビルド手順が上記方法に変更になったようだ。細かいチューニングが必要ならばidf.pyのソースコードを読むコとになる。

## おまけ

間違いとかわかりにくいとか誤字とか脱字とか発見された方はぜひぜひお知らせください。
GCE 環境でMySQLのdocker-entrypoint-initdb.dが動かない時

マウントしたフォルダがPermission Denied、そんなはずはない！
777付与もしたけど動かない！そんなあなたに。

原因はSELinux。

```
chcon -Rt svirt_sandbox_file_t [マウント対象フォルダのパス]
```

これでディレクトリ単位で許可することができる。
再度 dokcer-compose upすれば

動きます
@IBOutlet名を変えることに伴う修正作業

tableViewCellのUIからLabelViewを@IBOutletで結びつけました。
(単に、UIをctrl+ドラッグでcodeに結びつけたと考えて大丈夫です。)

```TweetTableViewCell.swift
class TweetTableViewCell: UITableViewCell {
    // MARK: - properties
    @IBOutlet var nameLabelEX: UILabel!
    
    ~
```

結びつけた後に、outletの名前を、

nameLabelEX -> nameLabel

に変更したくなってしまいました。ここは、かっこよさよりもわかりやすさを取りましょう。

```TweetTableViewCell.swift(変更後)
    ~
    @IBOutlet var nameLabel: UILabel!
    ~
```
すると、 simulator起動後にエラーを吐くようになってしまいました。

```
TwitterClientPractice[41941:3854774]
 *** Terminating app due to uncaught exception 'NSUnknownKeyException', 
reason: 
'[<TwitterClientPractice.TweetTableViewCell 0x7fa8ed71d500> setValue:forUndefinedKey:]: 
this class is not key value coding-compliant for the key nameLabelEX.'
```
**reason:** 以下を直感的にみてみると、”nameLabelEX keyに該当するkeyValueがTweetTableViewCellクラス内にない”と言っているようです。

[こちら](https://qiita.com/tetsuya/items/cb5d6f64dd32c1453c35)のリンクを参考にUIファイルの方でSource Codeを開いてみましょう。(私の場合.xibファイル)

```TweetTableViewCell.xib
<connections>
    ~
    <outlet property="nameLabelEX" destination="tB0-V3-cWE" id="uKL-bu-ztr"/>
    ~
</connections>
```

あちゃ〜、TweetTableViewCell.swiftのクラス内で名前を変更しても、UIのTweetTableViewCell.xibの方では、変更前の名前で@IBOutlet接続を参照してますね。

```TweetTableViewCell.xib
<connections>
    ~
    <outlet property="nameLabel" destination="tB0-V3-cWE" id="uKL-bu-ztr"/>
    ~
</connections>
```
参照名を直したらエラーは解消されましたよ。

※@IBOutlet自体を削除した後、参照の方も接続を切らないと、、なのと理由は同じですね。
レスポンシブ設計　キホンの基本　part2~flex-wrap: wrap;

前回はレスポンシブのための一歩目をやりました⤵︎
https://qiita.com/zakaryo/items/ee0a799f4d1bb61f2517

今回は折り返しについてやっていきます。

いざdisplayをflexにし横並びにすることができたとしても、

そのままだと子要素のコンテンツが増えたときに、延々と詰め込まれてしまいうことになります。

こんな感じに。

```style.css
 .container {
display: flex;
}
.box {
width: 300px;
height: 300px;
margin: 10px 5px;
}
```
![スクリーンショット 2020-02-05 3.06.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/572382/3d85ffaf-e6dc-e483-cec8-3364c4106121.png)

本来300x300の正方形を並べたいのに、画面いっぱいに詰め込まれ縮んでしまいます。

そこで親要素にflex-wrap:wrap;を指定してみましょう。

```style.css
 .container {
display: flex;
flex-wrap: wrap;
}
.box {
width: 300px;
height: 300px;
margin: 10px 5px;
}
```
そうするとこうなります。
![スクリーンショット 2020-02-05 3.19.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/572382/e60b98b6-e804-5495-c4b1-02d14eb87bd6.png)

このように無理につめこまれるのではなくて、width:300px;が適用され

はみ出る分は一段下に落とされます。

さらに親要素にmax-widthを指定してあげれば１段に何個の子要素を入れるかを決めることができます。

```style.css
 .container {
display: flex;
flex-wrap: wrap;
max-width:700px;
}
.box {
width: 300px;
height: 300px;
margin: 10px 5px;
}
```

![スクリーンショット 2020-02-05 3.30.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/572382/b4af2ecf-a273-1e2e-042e-a078dd15a5d3.png)

実際は下に子要素の数分続いています。

以上のようにするとflexboxにおいて折り返しができるのではないでしょうか。
HTML <%○○>タグリファレンスの種類と書き方

###タグリファレンスとは
<%button>ボタンの作成
<%input>入力ホーム
<%body>文書情報・構造
<%!DOCTYPE>文書情報・構造

があったりします。

書き方としては

*HTML*

```html
<button type="submit" class="button1">
  <i class="fas fa-search"></i> 検索
</button>
```

*HAML*

```haml
%button{type: "submit", class: "button1"}
  %i.fas.fa-search>
  検索

または

%button.button1{type: "submit"}
  %i.fas.fa-search>
  検索
```

"type"で属性を持たせたり
"value"で値を指定したり
"class"でクラスを持たせて色の指定や、大きさを変更できるようになります。

##↓<%input>の例↓

*HTML*

```html
<label>
  <input type="submit" value="送信する">
</label>
```

*HAML*

```haml
%label
  %input{:type => "submit", :value => "送信する"}/
```

---
*参考文献*
[★HTMLタグリファレンス（ABC順)](http://www.htmq.com/html/)
[★HTMLタグリファレンス（目的別)](http://www.htmq.com/html/indexm.shtml)
[inputの使い方とtype属性の一覧をサンプル付きで紹介](https://webliker.info/39533/#toc_13)
[submitボタンのアイコンにアイコンフォント（Font Awesome）を使う](https://www.tsukimi.net/submit-button_font-awesome.html)
【SEO】レガシーなサービスのサイトスピードを16倍早くした話

# 前置き
運営しているサービスがかなりレガシーなので、負の遺産が多いです。

入社した頃からサイトの速度が遅いなと感じていながら、日々の業務を追われているうちに後回しになっていました。

それから半年たったある日、SEOに注力する方針となり上司からサービスのサイトの表示速度が遅いので、本日中に何とかしてほしいとのことでようやく時間を割いて対応することになりました。

# 環境
* PHP 5.2
* Breeze framework
* MariaDB 5.5.62

# 速度改善で要因特定にやったこと

* Chromeのデバックツールで表示速度を確認
* バックエンドかフロントエンドか要因を切り分け
  * バックエンドに時間がかかっていることが判明
* PHPのソースコード内に速度を図るコードを埋め込み
  * DBの処理に時間がかかっていることが判明

# 速度改善にやったことまとめ

1. **（効果：◎）DB：EXPLAINで実行計画を行い、INDEXを設定**
1. （効果：△）PHP：ロジックを修正（不要な処理を削除）
1. **（効果：◎）DB：EXPLAINで実行計画を行い、INDEXを設定**
1. （効果：△）PHP：ロジックを修正（取得系の処理改善）
1. **（効果：◎）DB：クエリキャッシュを有効にする**

DBの速度改善が効果絶大だったので、対応したことを後記していきます。

# DB：EXPLAINで実行計画を行い、INDEXを設定

FYI. [MySQLのIndexをはるコツ | Qiita](https://qiita.com/katsukii/items/3409e3c3c96580d37c2b)

```
-- インデックス削除
ALTER TABLE example_table_1 DROP INDEX user_id(user_id);

-- インデックス追加
ALTER TABLE example_table_2 ADD INDEX index_user_id(user_id);
```

# DB：クエリキャッシュを有効にする

DBを再起動せずに反映する方法

```
SET GLOBAL query_cache_size=64*1024*1024;
SET GLOBAL query_cache_limit=8*1024*1024;
SET GLOBAL query_cache_type=1;
FLUSH QUERY CACHE;
```

# 実施結果
サイトの表示速度がなんと「5800ms」から「350ms」になりました。
およそ16倍の速度改善をすることが出来ました。

……クエリキャッシュの威力半端ない！！

![スクリーンショット 2018-12-21 16.42.27 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288712/12ef1d4f-fb98-8058-b679-93b9a8603e02.png)

# 最後に

ちょっとした設定一つでこんなにもサイトの表示速度が変わるのは感動しました。
むしろ今まで放置だったのも良くないですが…（苦笑）
いま、動いているリソースで改善できることはまだまだありますね！

とはいえ、ミドルウェアのバージョンがそもそも古かったり、フレームワークが古かったり、サーバーのスペックが適切でなかったり……
根本的な要因もあるので、引き続き地道に改善していきつつ思い切った決断をする必要もありそうですね。
各DB環境の検証用Docker作ってみた

各DB環境の検証用Dockerを作ってみた
SQLServerはDockerと相性がわるかったので割愛

## 概要
ユーザーは`local`、DBは`DB`として作成
文字コードはUTF-8、タイムゾーンはミドルウェアによるのでDockerより指定
DBビルド時に実行したいSQLを「docker-entrypoint-initdb.d」に配置する

## 最低要件

### MacにDockerとDocker-composeをインストール

公式からDockerをワンライナーでインストール
https://github.com/docker/docker-install

公式からDocker Composeのインストール（最新版をインストール）
http://docs.docker.jp/compose/install.html


## My SQL
version 5.7
sql-modeのデフォルトは下記の通り

```
ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
```

### 接続手順

```bash
dc exec mysql bash
mysql> mysql -ulocal -plocal db

```

## Oracle
version 19.3.0-ee

こちらを参考にさせて頂きました

DockerでOracle Databaseを使う
https://qiita.com/gorilla0513/items/f22e8cce4e08da031abe

### Oracle DBのDockerイメージ作成
オラクルのコンテナを起動する前にDockerイメージを作成する。手順は下記の通り

Oracleの公式Docker Image
https://github.com/oracle/docker-images  

Oracle Databaseの公式Docker Image
https://github.com/oracle/docker-images/blob/master/OracleDatabase/SingleInstance/README.md  

DokcerにOracle Databaseの公式イメージがないので、Oracleが用意したimageをローカルで作成する

```
git clone https://github.com/oracle/docker-images.git
```

Oracle本体をDL、指定のフォルダに移動コピー（オラクルのアカウントを作成する必要あり）

```
cp ~/Downloads/LINUX.X64_193000_db_home.zip docker-images/OracleDatabase/SingleInstance/dockerfiles/19.3.0/
```

ビルドシェルを実行し、Docerイメージを作成

```
cd ./docker-images/OracleDatabase/SingleInstance/dockerfiles
sh buildDockerImage.sh -v 19.3.0 -e
```

OracleのDBに接続する

```
sqlplus sys/<your password>@//localhost:1521/<your SID> as sysdba
sqlplus system/<your password>@//localhost:1521/<your SID>
sqlplus pdbadmin/<your password>@//localhost:1521/<Your PDB name>
```

### 接続手順

```
dc exec oracle bash
oracle> sqlplus pdbadmin/SYS@//localhost:1521/PDB
```

- Oracleは他のDBに比べて概念が難しいため初期設定をどこまでするか難しい。。。
- テーブルを作成するにはまずユーザーが必要
MySQLで言うところのDBがOracleで言うユーザー（スキーマ）に近いと思われる
- TABLE SPACE、TEMPORARY TABLESPACEについてはこちらが参考になりそう  
[【ORACLEのお勉強#01】テーブル、表領域、データファイル、ディスクの関係](https://el.jibun.atmarkit.co.jp/yuu1/2017/08/oracle_oracle_redoundo_oracle_10oracle.html)  
- Oracleの権限についてはオブジェクト権限、システム権限があり、システム権限が与えられないとユーザーを作成してもテーブル作成できない。ひとまず定義済みDBAロールを付与。

## PostgreSQL
version 12.1
ロケールはDB作成時にしか設定できないので、Dockerfile起動時に設定

### 接続手順
```
dc exec postgres bash
postgres> psql -U local -d db
```

## Dockerコンテナ起動
```
dc down
dc build --no-cache
dc up -d
```

GitHubにあげてます
https://github.com/okdyy75/db-docker
エンジニア初心者と「集合と条件」

#はじめに
駆け出しソフトウェアエンジニアがソフトウェア開発と集合について大切にしなきゃなと気づいたことをメモしました。
簡単すぎることですが気づけば忘れてしまいそうなのでメモしました。
#集合と条件
集合とソフトウェア開発が密接に関係していることは有名だと思います。
なんせ駆け出しの自分がすぐにたどり着いたのですから、、、

簡単なことは中学高校で学んだことですので詳細は省きます。
集合の分野には色々な定理がありますが個人的にソフトウェアエンジニアとして常に心掛けたい関係式がこちら

```math
p=>q \equiv \lnot(p \land \lnot q)
```
何をいまさらと思うでしょうが一応簡単な説明を拙い図でします。
まず「pならばq」ということは、「pは必ずqに含まれる」ということ。この式が真であるということは、左図での赤い部分が存在してはいけないことになるので右図のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506489/da831da1-7085-1a69-ae46-b94f0b1b4dd9.png)



一方、上のような関係は「pであって、かつqでないものは存在しない」とも言えます。
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506489/534440cd-e39b-d5af-69b1-3a5c63600683.png)


この図(絵心がなさ過ぎてOneNote with Surface PenからPaintに切り替えました)
左図の黄色の部分が$p$、水色の部分が$\lnot q$を示しています。そして$(p \land \lnot q)$が右図の緑色の部分です。
この緑色が常に存在しないとき$p\Rightarrow q$が常に真となります。
かなりいい加減な説明ですが今回は厳密に証明することではなくイメージを掴むことが目的なので許してください。
これで上の関係式の内容がなんとなくイメージできるようになりました。
#具体的な理解
この関係式はとある問題を考えているときに別の視点を与えてくれます。

```math
p=>q \equiv \lnot(p \land \lnot q)
```
「$p\Rightarrow q$」は様々な場面で出てきますがこのpとqを漏れなくダブりなく(MECE)とらえるのは難しいです。
「ならば」というのがp、qそれぞれの全体像、またpとqの関係性をとらえにくくしているのだと思います。

一方右辺は否定文であることが特徴としてあります。つまり()内のことがあってはいけない=禁止されていると考えることができます。
より分かりやすく言うと
pであって、なおかつ qではないという条件(ルール)が禁止されていると考えます。
この手の問題でよくある例が「p=運転手、q=免許証がある」とした日本の交通ルールについての問答。
  
**左辺：運転手ならば、免許証がある**
  
  
これは日本の法律上、真でなければいけません。
また「運転手じゃないならば、免許証がある」も真です。別に運転していないならば免許証を持っていようがいまいが違反ではありません。
ということで「運転手じゃないならば、免許証がない」も真です。
表にすると以下のようになります(1:真 0:偽)

|p|q| p=>q |
|:--|--:|:--:|
|1|1|1|
|1|0|0|
|0|1|1|
|0|0|1|
上2つはわかりやすいですが下二つは直感的にはわかりにくいです。


一方、**右辺：「運転手であって、かつ、免許証がない」ことを禁止する**

となり、**このルールに違反したものを選ぶ問題と考えることができます。**2つの要素が満たされているかどうかをチェックするだけでいいのでかなり扱いやすくなった印象です。
ここでは「運転者である」「免許をもっていない」の2つの条件が同時に成り立った場合のみ偽、あと残りはすべて真とすればいい。

| p | q | $\lnot q$ | $p \land \lnot q$ | $\lnot(p \land \lnot q)$ |
|:---:|:---:|:---:|:---:|:---:|
|1|1|0|0|1|
|1|0|1|1|0|
|0|1|0|0|1|
|0|0|1|0|1|

左辺と右辺の違いは「真を探しだすか」、「偽を探しだすか」の違いなだけに見える。どちらが良いかは問題の性質にもよるだろうしもちろん片方の探索ですべてのパターンを列挙できればいうことなしです。
しかし武器は多いに越したことはないと思います。
#どこで役に立つか
このpとqはソフトでは状態の関係であり、アルゴリズムではインプット、アウトプット、条件の関係となります。
自分は普段アプリケーションの仕様作成、設計、実装を行っています。複雑なアプリケーションは様々なオブジェクト同士が互いに関連し合っています(できるだけ疎な関係にしようとはしていますが、、、)。
また動作フローなども何パターンもあり、それらすべてを考慮しないとバグの原因となります。

また自分はソフトウェアエンジニアになると決まったくらいから訓練も兼ねて競技プログラミングをやってます。
そこでも「このコーディングで果たして問題文のすべての条件をクリアしているか」といったことを考えるのは当然であり、難易度が高い問題ほどその工程の重要度、難易度は増します。

上で挙げたようなときに当たり前だけど漏れがないかを集合論的に考えることはとても大切だと思います。
もしかしたら日常でも何か役に立つかもしれないと思います。そしてモテるかもしれないです。
#まとめ

・集合の考え方はソフトウェア開発するにあたってとても重要な学問
・$p=>q \equiv \lnot(p \land \lnot q)$は問題のとらえ方に2つの視点を与える。
・この考え方はいろんな分野に応用できる、、はず
知っているようで知らないSwift5のアクセス修飾子

## はじめに
今回は、普段あまり意識しないアクセス修飾子について記事を作成していきます！
初心者でもわかりやすくまとめいるので覚えておくと便利です！
Swiftでは、バージョンによって意味が異なるので利用するときはSwiftのバージョンにも注意してください！
今回は、Swift5を利用して記事を作成しています。

##アクセス修飾子とは？
アクセス修飾子は、クラスや関数等にアクセス制限を設けるために利用します。

```swift:
//privateなどを以下のように利用します。
class HogeHogeViewController:UIViewController  {
    private let hoge: Int!
}
```

##アクセス修飾子の種類

```swift:SwiftModifierSample.playground

    //そのクラス間のみアクセス可能(Swift3からextension内でも利用できるようになりました。)
    private let macBook = "MacBook"

    //private(set)を利用すると、setはprivate、getはinternalの制限にすることができます。
    private(set) var airPods = "airpods"

    //一つのプロジェクト内のターゲットが同一であれば呼び出せる。継承やoverrideもできる。
    internal let iPhone = "iPhone"

    //同じfile内であればアクセス可能
    fileprivate let imac = "iMac"

    // 一つのプロジェクト内のターゲットが同一でなくても呼び出せるが継承やoverrideはできない。
    public var appleWatch = "appleWatch"

    //一つのプロジェクト内のターゲットが同一でなくても呼び出せるが、継承やoverrideもできる。
    open var  macPro = "macPro"

```
privateが一番制限が強く、openが一番制限が低いです。
private　-> private(set) -> internal -> fileprivate -> public -> open
アクセス制限は右に行くほど緩くなります。

##実際に使ってみる。


```swift:SwiftModifierSample.playground
class Apple {
    private let macBook = "MacBook"
    private(set) var airPods = "airpods"
    internal let iPhone = "iPhone"
    fileprivate let imac = "iMac"
    public var appleWatch = "appleWatch"
    open var  macPro = "macPro"
}

extension Apple {
    public func hoge1(){
        print(macBook)
    }

    func hoge2(){
        print(macBook)
    }

    private func hoge3(){
        print(macBook)
    }
}

let apple = Apple()
apple.iPhone
apple.imac
apple.macBook  //error: 'macBook' is inaccessible due to 'private' protection level
apple.hoge1()
apple.hoge2()
apple.hoge3()  //error: 'hoge3' is inaccessible due to 'private' protection level

```

publicやopenの修飾子は主にライブラリー等の作成時に利用されることが多い。
アクセス修飾子を記述しないとデフォルトでinternalが適応される。

##アクセス修飾子って必要なの？
個人アプリで開発していくならどちらでも良いと思いますが、チーム開発をしてる場合は、変数や関数にprivateをつけることで、クラス内部しか利用されていないことを、明示することができるのでコードレビューをしやすくなります。また、外部でアクセスできないようにすると似ている変数名を誤って呼び出すこともなくなります。逆にpublicをつけることでグローバル変数であること明示できるのでコードの読みやすさにつながります。

##参考
https://www.sejuku.net/blog/22679
https://qiita.com/GATA/items/90341f56a56ff584e756

##さいごに
今回は、Xcodeのplaygroundでサンプルコードを作成して[Github](https://github.com/tazima10827/-AccessModifier)にアップしました！
週一でQiita記事を公開していくのでいいねとフォローをよろしくお願いします！
【解決法】ターミナルでheroku config:set RAILS_MASTER_KEY=「マスターキー」を入力する際の「マスターキー」の値はどの数値を持って来れば良い？


## 結論：アプリ内のmaster.keyファイルを開いて、現れた内部の英数字を入力してください。

私はマスターキーを自分で設定するものだと思い、設定していました、、、


通りでエラーが出るわけです。


マスターキーは直接みることはできないので、Atomなどのエディタを使用しましょう。


これで2日使ってたとかアホすぎ、、、
HAML %buttonをつけてsubmitボタンにフォントオーサムのアイコンをつける

submitボタン(送信用ボタン)にフォントオーサムのアイコンをつけたい。
しかし以下のようにやってしまうと、うまく行きません。

```haml:_main_bar.html.haml
.form
    = form_for [@group, @message] do |f|
      .form__new-message
        .form__new-message__input-box
          = f.text_field :content, class: 'text', placeholder: 'メッセージを入力'
          = f.label :image, class: 'image' do
            = icon('fas', 'image', class: 'icon')
            = f.file_field :image, class: 'hidden'
        = f.submit '送信', class: 'submit-btn'         #今回見るのはここの行
        = icon('fas', 'paper-plane', class: 'plane')   #今回見るのはここの行
 
```

```sass:main_bar.scss
      .submit-btn {
        align-items: center;
        height: 50px;
        width: 100px;
        margin-left: 15px;
        padding: 0 20px 0;
        background-color: #38aef0;
        color: white;
        box-shadow: 1px 1px 2px #999999;
        border-style: none;
      }
      .fas.fa-paper-plane {
        color: white;
        font-size: 25px;
      }
```
このようになります。↓
紙飛行機が送信ボタンからはみ出てしまいました。

<img width="940" alt="スクリーンショット 2020-02-05 1.47.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538880/2c9d3ff8-f01c-18fc-da47-5faca3da9d2c.png">

なので、このように変更して紙飛行機を送信ボタンの中に入れます。

```haml:_main_bar.html.haml
  .form
    = form_for [@group, @message] do |f|
      .form__new-message
        .form__new-message__input-box
          = f.text_field :content, class: 'text', placeholder: 'メッセージを入力'
          = f.label :image, class: 'image' do
            = icon('fas', 'image', class: 'icon')
            = f.file_field :image, class: 'hidden'
        %button{type: "submit", class:'btn'}   #今回見るのはここの行
          %i.fas.fa-paper-plane　　　　　　　　　 #今回見るのはここの行
          .letter　　　　　　　　　　　　　　　　　 #今回見るのはここの行
            送信　　　　　　　　　　　　　　　　　　 #今回見るのはここの行
 
```

```sass:main_bar.scss
      .btn {
        align-items: center;
        height: 50px;
        width: 100px;
        margin-left: 15px;
        padding: 0 20px 0;
        background-color: #38aef0;
        color: white;
        box-shadow: 1px 1px 2px #999999;
        border-style: none;
        display: flex;
      }
      .fas.fa-paper-plane {
        color: white;
        font-size: 17px;
      }
      .letter {
        font-size: 16px;
        margin-left: 5px;
      }
```

無事成功( ＾∀＾)

<img width="940" alt="スクリーンショット 2020-02-05 2.07.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538880/cf572580-c23c-94f6-50c3-406d12aa2cd4.png">

できましたね！！

###↓↓変更した部分↓↓###

```haml:_main.html.haml
= f.submit '送信', class: 'submit-btn'
= icon('fas', 'paper-plane', class: 'plane')
```
の部分を

```haml:_main.html.haml
%button{type: "submit", class:'btn'} 
  %i.fas.fa-paper-plane　　　　　　　　　 
  .letter　　　　　　　　　　　　　　　　　 
    送信　　　　　　　　　　　　　　　　　　 
``` 
###↑↑変更した部分↑↑###

のように書き方を変えました！！

type属性では
submit（送信ボタン）
reset（リセットボタン）
button（汎用的に使える押しボタン）
が使用可能です！！
######`%button{type: "submit", class:'btn'}`  ここの`type: ""`の中身の部分の事です######
PHPの終了タグは「?>」を付けるか付けないかは判断しようねという話

◼️理由は終了タグを省略することでファイルの最後にある余空白文字が出力に影響することを防ぐ
◼️htmlでは改行コードを半角スペースとして認識する
◼️htmlテンプレートなどに記述する際は週s量タグは必要

参考：
https://thesaibase.com/php/end-tag
Mac バンドルの nano エディタを最新版にしてみた


GCPのトレーニング教材とかをやっていると、エディタは当たり前のように [nano](https://www.nano-editor.org/) を使っている。

そこで、zsh標準のエディタを nano にしてみようと思ったのだが、どうやらバンドル版はずいぶん古い（2.0.6）ようなので、まずは最新版にしてみる。

（参考１）
https://apple.stackexchange.com/questions/366966/how-do-you-update-the-default-version-of-nano-on-macos-x-without-using-the-homeb


## Mac バンドル版nanoをバージョンアップする

### アップデート前

```shell
% nano --version
 GNU nano version 2.0.6 (compiled 02:30:17, Nov  9 2019)
```

### アップデート手順

```shell
## まず ncurses で日本語化対応
% wget http://ftp.gnu.org/gnu/ncurses/ncurses-6.1.tar.gz
% tar -xzvf ncurses-6.1.tar.gz
% cd ncurses-6.1
% ./configure --with-shared --enable-widec
% make
% make install

## nano のアップデート
% curl -O https://www.nano-editor.org/dist/v4/nano-4.7.tar.gz
% tar xvzf nano-4.7.tar.gz
% cd nano-4.7
% ./configure --enable-utf8
% make
% make install
```

単純にアップデートすると日本語が使えなかったので、下記の手順を参考にした。

（参考２）
[[Mac] nanoのアップデートと日本語への対応 | WatchContents](https://watchcontents.com/wp-content/uploads/2017/08/Screen-Shot-2017-08-10-at-0.42.37.png)

### アップデート後

```shell
% nano --version
 GNU nano, version 4.7
 (C) 1999-2011, 2013-2019 Free Software Foundation, Inc.
 (C) 2014-2019 the contributors to nano
 Email: nano@nano-editor.org	Web: https://nano-editor.org/
 Compiled options: --disable-libmagic --disable-nls --enable-utf8
```

最新版かつ日本語が使える状態になりました。 :+1: 

## nano 設定

nano を自分好みに育ててみます。

- Syntax Hilight を導入
  - https://github.com/scopatz/nanorc
  - README記載のインストール手順どおりに実施

- `~/.nanorc`
    - マニュアルを見ながら必要な設定を書く
    - https://www.nano-editor.org/dist/latest/nanorc.5.html


結果、何の変哲もない設定ファイルですが、一応貼っておく。
https://github.com/shionit/dotfiles/blob/master/.nanorc

## 標準のエディタを設定

`~/.zshrc` に以下を追記する。

```.zshrc
export EDITOR='nano';
```

※筆者注：後で色々あって結局 vim に戻しました :sweat_smile: 


## nano情報

ここらへんを読んで nano の標準的な使い方を知っておこう。

- [GNU nano](https://www.nano-editor.org/)
  - [ショートカットキーのチートシート(公式)](https://www.nano-editor.org/dist/latest/cheatsheet.html)
- [nano - ArchWiki](https://wiki.archlinux.jp/index.php/Nano)
- [GNU nanoを使いこなす - Qiita](https://qiita.com/snct_hu/items/971d512c26dd8b3a3b3c)

## あとがき

> GCPのトレーニング教材とかをやっていると、エディタは当たり前のように [nano](https://www.nano-editor.org/) を使っている。

冒頭にこう書いたが、よくよく考えたらGoogleさんが vim vs emacs 戦争に巻き込まれないように Linux 標準エディタを使う手順にしただけかもしれない、と思えてきた。

### nano エディタの優位性？

nanoは、「モードの切替概念などがあり取っ付きが悪いvim」を避けるための直感的に使える簡易エディタ（Windowsで言うところの”メモ帳”）のポジションなんだという理解です。なので、既に vim をある程度使える人が、nanoを使う意義があるだろうか？を考えると、見つかりませんでした（笑

※私の理解が浅いだけかもしれないので、nano萌えな読者がいたら擁護コメントをお願いします。
あいみょんクイズをツールで作ってみた。

## はじめに
「Bar Chart Race」で知った「Flourish」 でまた遊んでみた。
　※https://qiita.com/hamham194/items/16a7e3660c940560ba54

こんどはクイズを作ってみた。

![あいみょんクイズ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384185/f0c3e0f4-560e-57e8-2bd4-4c7cc967d3dc.png)

## やってみた
実際はこちら ↓ 
https://public.flourish.studio/visualisation/1336850/

これまた簡単！と思いきや、は？なんか色々と表示がおかしい。。。
試行錯誤した結果、こんな機能制約あり。

 - 「media」に画像URLを張り付けると、ばぐる。
 - QuestionとAnswers&SourceのA列が揃ってないと、うまく機能しない。
 - 数値は、1 - 10 のように、-の間に半角をつけないといけない。
 - yesは、15のように範囲にしてはいけない？

## 結論
あいみょん好きすぎる。
と、ツール類は手を動かすに限る。いや、はい…。
VSCodeでTypeScriptを書く時、エクスプローラーに .jsと.d.tsを表示しない方法

## 方法

`setting.json`に下記を追記する。

```json
    "files.exclude": {
        ...,
        "**/*.js": { "when": "$(basename).ts" },
        "**/*.d.ts": { "when": "$(basename).ts" }
    }
```

## 参考元

- [Visual Studio Codeで \*\.d\.ts ファイルを非表示にする方法 \- 備忘録](https://kagasu.hatenablog.com/entry/2019/03/25/001309)
【Linux】firewalldの操作コマンドまとめ

CentOS7系のファイアウォールの操作コマンドは忘れたころに使うことがあるので、備忘録としてまとめます。

# 起動状態を確認

```
systemctl status firewalld.service
```

# 起動

```
systemctl start firewalld.service
```

# 停止

```
systemctl stop firewalld.service
```

# 全ての設定を確認

```
firewall-cmd --list-all

firewall-cmd --list-all-zones
```

# 有効な設定を確認

```
firewall-cmd --get-active-zones
```

# サービス設定を追加する

## サービス設定ファイルを作成する
```
cp /usr/lib/firewalld/services/http.xml /etc/firewalld/services/http-5000.xml
```

## サービス設定ファイルを編集する

```
vim /etc/firewalld/services/http-5000.xml 
# write 5000 to port, write tcp or udp from protocol
```

# サービスを追加する

```
firewall-cmd --zone=zone_name --add-service=http-5000 --permanent
```

# ゾーン追加

```
firewall-cmd --permanent --new-zone=sample
```

# ゾーン削除

```
firewall-cmd --permanent --delete-zone=sample
```

# 指定ゾーンのみ許可するサービスを追加

```
firewall-cmd --permanent --zone=sample --add-service=http
```

指定ゾーンのみ許可するサービスを削除

```
firewall-cmd --permanent --zone=sample --remove-service=http
```


# 指定ゾーンのみ許可するIPを追加

```
firewall-cmd --permanent --zone=sample --add-source=xx.xx.xx.xx
```

CIDR（サイダー）表記も可能

```
firewall-cmd --permanent --zone=sample --add-source=xx.xx.xx.xx/24
```

# 変更を反映

```
firewall-cmd --reload
```

# ログを確認する

```
tail -f /var/log/message
```
オフショアの開発会社と半年やりとりして地獄をみた。

## はじめに
弊社プロダクトの開発スピードアップを見込んで、とある国のオフショア企業の力を借りることになり、その開発ディレクティングを行いました。
結果的に契約期間の半年で打ち切りとなりまして、それにいたった過程・所感などをここに残しておきたいと思います。

## 契約期間
半年
（※そのうち、BSEとPGは5ヵ月）

## メンバー構成
* BSE（ブリッジシステムエンジニア）×１
    * 現地のPG、テスターへの仕様伝達・メンバー管理・請負企業側とのコミュニケーションが主な業務。
* PG（プログラマー）×5
    * 開発の実行部隊。皆日本語は未対応だが、英語は対応可能。
* テスター×4
    * 各チケット単位でテスト仕様書の作成・テストを実施。
* コンター×１
    * おそらく、コミュニケーターの略。現地語しか対応できないメンバーへの橋渡し役。こちらが作成したチケットの現地語翻訳や、テスターが作ったテスト仕様書の日本語翻訳の他、BSEが不在時の連絡役として対応。

## メンバー背景
PGの採用条件として理系大学を卒業していることが必須。コンターは外語大出身、テスターは文系学部出身など、大学の出身学部により職位は別れているようで、PGはテストをしないし、テスターは開発をしないなど完全分業体制であった。

（蛇足ではあるが、WEB案件はPGが取り組むにあたって価値の高い案件ではなく、モチベーションとしては高いものではなかったらしい。）

## メリットと感じた点
### 初回プルリクの作成が早い
平均的に、作業開始から１日でプルリクを作成していたので、スピードは早かった。

### BSEはいつでもビデオチャットでチャットよりも早い仕様の伝達ができる
チャットで意思の疎通が完全にできていなかった分、こまめにビデオチャットで対応できたのはよかった。

### テスターのテスト粒度が細かい
開発会社側のテスターだけでなく、弊社側でも仕様書の作成を行ったが、こちらはテスト専門にやっていた人間はいなかったため、どうしても、テストケースの粒度が粗くなってしまっていた。

その一方で、テスターは細かい粒度でテストケースを作成していてくれたため、テスト仕様書の品質向上に繋がった。

## 課題と感じた点
### 報告・連絡の意識が低い
日本ではありえないことだと思うが、BSEと連絡が全くできなくなる日が三ヶ月のうち二日あった。その理由は体調不良ではなく、私用の理由。BSE以外のチャットでのやりとりが皆無（おそらくPGはやりとりしないといったルールが開発会社側にあったようである。）であったため、その間はPGへの修正依頼が不可能となってしまった。

また、改善策としてBSEが不在時にCTOやコンターが代わりとなることを約束したものの、CTOやコンターも連絡が遅い・一切返信しないなどがあり、**一気に信頼度が落ちた。**

### 日本語の習熟度が低い
これは仕方がないこととはいえ、仕様をわかりやすく伝えるためにチケットやビデオチャットでのやり取りの際の文章量が多くなり、日本人PGと比較すると、明らかにコミュニケーションコストの差が大きかった。

また日本語非対応のテスターが作ったテスト仕様書をコンターが翻訳したものをチェックしたが、わかりにくい表現・日本語となっていない部分などが多く、その修正に2~3人で１０数日何時間と対応することになってしまった。

### プルリク 後の戻りが最低2~3回生じる
こちらの仕様書の不備、開発会社側の仕様書の低い理解度、PGのテスト未実施、BSEのテスト品質の低さが原因かと思われるが、一つのチケットがマージされOKとなるまで**最低２〜３週間かかってしまっていた。**

### Gitのフローを独自の運用方法以外受け入れない
githubの運用ルールを共有したものの、**一切守ってもらえなかった**。理由としては、他者で身につけた運用ルールの方が価値が高かったため、守る必要性を感じなかったというのがBSEの言い分であった。

こちらとしても、運用ルールの見直しをするべきであった。しかし開発会社としても、受注元の提示したルールには従う、もしくは新しい運用ルールを提案する姿勢を見せるべきだと思うが、ただこちらの意見を無視するだけだったので、**正直ありえないと感じた。**

### PGがテストをできない
開発会社社内で完全分業としていたため、最初テスターとは契約していなかったため、PGの作業確認・テストはほぼこちらの作業となっていた。PG自らが全くテストをしないせいか、その戻りは確実に２〜3回発生していた。
とりわけ顕著だったのが、デザインラフの画像ファイルを元に修正するチケットで、期待する機能の色になっていないのに完了報告をしたこと。目視で修正点を確認できるにも関わらず、それに気づかず（もしくは無視して）報告するのは正直理解し難い部分であった。

### BSEのテスト品質が低い
PGがテストできない分、BSEがテストを実施した上で報告しているということではあったものの、上記のデザインラフの件もあり、**BSEの作業チェックはあまり機能していないようだった。**

### テスターがアカウント作成ルールを守らない
該当プロダクトにログインできるアカウント属性が十数種類にも及ぶため、アカウント名にはルールを儲け入力・登録するように他の関連会社ともルールを守るように伝達した。

しかし、**12月末の契約最後までルールを守らず**、テスターがテストアカウントを登録してしまったため、「aa」などのクズデータアカウントが今もテスト環境で残ってしまっている。

### 日本と休日が異なる
これは仕方がない点ではあるが、日本の国民の休日はオフショア側にとっては関係なく稼働日であったため、こちらが休日の際も、BSEからの相談・質問に対応しなければならなかった。（と書いたものの、私自身休日稼働することに抵抗はないので一番課題点は低い。ただし、こちらからの返信が遅くなってしまったのは申し訳なかった。）

### インターン生を１人工のPGとして作業させていた
これはBSEが実際に契約完了前にこっそり教えてもらったことであるが、PG３人いたうち、1人はインターン生であり、全くの初心者であったらしい。これは**契約開始時に伝達はなかったことである。**

## 反省点
### 仕様書を用意していなかった
システム・機能が複雑になっているものの、これを外部の人に理解してもらうために十分なドキュメントを用意していなかった。また、作業フローに関しても契約後に用意したので、準備が遅く、これもコミュニケーションコストをあげる原因になっていた。

## まとめ
結果的に、100件以上のバグ改修・新機能開発対応とテスト仕様書の作成など助けられた部分は決して小さくはない。しかし、その反面コミュニケーションの難しさに苦しむことが多く、自分で改修した方が早いと感じる部分も多々あった。

今回の開発会社特有の問題点もあったものの、次回またオフショア企業と連携して作業を行う際は、コミュニケーションの壁がどれほどあるかを選定の時点で考慮すべきであり、かつ仕様を全く理解していない外部の人にも理解を助けるようなドキュメントを残すことは必須。