叫ぶうさぎの悪ふざけ

うさぎが目印のWebエンジニアが、得たことや思ったことを言の葉に乗せて叫ぶ場所です。

学習記録:12月7日(金):Webフレームワークに依存しない、PHP製のシンプルなSQL マイグレーションツール「Mig」を使ってみた

これは 俺のインプットアウトプット記録 Advent Calendar 2018 の7日目のエントリーです。

こちらのブログ、Webフレームワークに依存しない、PHP製のシンプルなSQL マイグレーションツール「Mig」を作った。 を拝見し、宣言通り使ってみました。

元ブログでやってなかったこと

使い方は製作者さまのブログの通りで、それをなぞっただけなので、特に新しいことはしていませんが、あえてブログにないことをしたと言えば、以下のポイントかなと思います。

  • インストールまでの道筋を全部書いた
    • 趣味で行間を埋めただけですが…
  • 個人の趣味で作ったテーブルの根拠を書いた
    • COLLATE=utf8mb4_bin とか
    • 金額カラムには DECIMAL 使うといいよと公式で言ってたとか
  • データベース接続設定ファイルの記述にデータベース名を入れ忘れた
    • 個人的にミスったのでメモした
  • CREATE TABLE, DROP TABLEのスペルミスをしていた
    • 注意書き程度にコンテンツに追加
    • 12/07追記:製作者さんにブログを修正していただきました

前提

もろもろちょっと古いですが、MySQLがサクッと試せる環境が今んところこれしかなかったのでご容赦を。

あと、vagrant使ってますので、コマンドは全て vagrant ssh した後になります。

$ cat /etc/system-release
CentOS Linux release 7.3.1611 (Core) 
$ mysql --version
mysql  Ver 14.14 Distrib 5.7.19, for Linux (x86_64) using  EditLine wrapper
$ php -v
PHP 7.1.8 (cli) (built: Aug  2 2017 12:13:05) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies

インストール

単純にMySQL5.7の検証用に作ったものだったんでcomposerから。

composer

$ curl -sS https://getcomposer.org/installer | php
All settings correct for using Composer
Downloading...

Composer (version 1.8.0) successfully installed to: /home/vagrant/composer.phar
Use it: php composer.phar
$ sudo mv composer.phar /usr/local/bin/composer
$ composer
   ______
  / ____/___  ____ ___  ____  ____  ________  _____
 / /   / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___/
/ /___/ /_/ / / / / / / /_/ / /_/ (__  )  __/ /
\____/\____/_/ /_/ /_/ .___/\____/____/\___/_/
                    /_/
Composer version 1.8.0 2018-12-03 10:31:16
(以下略)

Mig

そして本体をインストール。ここからはブログにもある通りです。

$ composer global require arakaki-yuji/mig
Changed current directory to /home/vagrant/.config/composer
Using version ^0.3.3 for arakaki-yuji/mig
./composer.json has been created
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 4 installs, 0 updates, 0 removals
  - Installing symfony/polyfill-mbstring (v1.10.0): Downloading (100%)         
  - Installing symfony/contracts (v1.0.2): Downloading (100%)         
  - Installing symfony/console (v4.2.0): Downloading (100%)         
  - Installing arakaki-yuji/mig (0.3.3): Downloading (100%)         
symfony/contracts suggests installing psr/cache (When using the Cache contracts)
symfony/contracts suggests installing psr/container (When using the Service contracts)
symfony/contracts suggests installing symfony/cache-contracts-implementation
symfony/contracts suggests installing symfony/service-contracts-implementation
symfony/contracts suggests installing symfony/translation-contracts-implementation
symfony/console suggests installing psr/log-implementation (For using the console logger)
symfony/console suggests installing symfony/event-dispatcher
symfony/console suggests installing symfony/lock
symfony/console suggests installing symfony/process
Writing lock file
Generating autoload files

パスを通す

みなさんの環境に合わせてくださいね。 適当に作ってしまった環境なので僕は以下のパスを通しました。

$ export PATH=$PATH:$HOME/.config/composer/vendor/bin

設定ファイル作成

ここは作者さまの通りに。

$ pwd
/home/vagrant
$ vim mig.config.php 

設定ファイルの中身はこんな感じ。 注意点としては、 db_dsn に設定する内容は db_name まで設定しないとPDOでコケます。

詳しく言うと、接続先のデータベース名を指定しないと invalid data source name になりますので、以下のようにhostとdb_nameを設定してください。

<?php
return [
    'db_dsn' => 'mysql:host=localhost;dbname=mamy1326',
    'db_username' => 'root',
    'db_passwd' => 'mSbXeWZyGz4R',
    'migration_filepath' => 'migrations',  // migrationファイルを保存するディレクトリ名
];

次にmigrationファイルを保存するディレクトリを作っておきます。

$ mkdir migrations
$ ls -la migrations
合計 12
drwxrwxr-x  2 vagrant vagrant   88 127 02:18 .
drwx------. 9 vagrant vagrant 4096 127 02:18 ..

これで準備は完了です。

初期化を実行

コマンドを実行し、migration用のテーブルができていることを確認します。

$ mig-cli init
Initialize for manage migration.
=================

Already created migrations table.

次に実際のテーブルを確認します。

$ mysql -u root -p mamy1326
Enter password: 
(中略)
mysql> show tables where Tables_in_mamy1326='migrations';
+--------------------+
| Tables_in_mamy1326 |
+--------------------+
| migrations         |
+--------------------+
1 row in set (0.00 sec)

無事、migrationテーブルが作成されていることがわかります。 一応、create tableも確認します。 中身も空っぽですね。

mysql> show create table migrations\G
*************************** 1. row ***************************
       Table: migrations
Create Table: CREATE TABLE `migrations` (
  `id` bigint(20) NOT NULL,
  `applied_at` int(11) DEFAULT NULL,
  UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

mysql> select * from migrations;
Empty set (0.00 sec)

migrationファイル作成

実際のテーブル名をつけて、migrationファイル作成コマンドを実行します。 今回はmigrationテーブルで差分を確認したいので、2つテーブルを作成します。

# migrationファイル作成(1テーブル目)
$ mig-cli create items
Create a new migration file.
=================

create migrations/20181206174917_items.up.sql
create migrations/20181206174917_items.down.sql

# migrationファイル作成(2テーブル目)
$ mig-cli create item_details
Create a new migration file.
=================

create migrations/20181206180443_item_details.up.sql
create migrations/20181206180443_item_details.down.sql

# 作成を確認
$ ls -la migrations
合計 6
drwxrwxr-x  2 vagrant vagrant 4096 127 02:49 .
drwx------. 9 vagrant vagrant 4096 127 02:18 ..
-rw-rw-r--  1 vagrant vagrant    0 127 02:49 20181206174917_items.down.sql
-rw-rw-r--  1 vagrant vagrant    0 127 02:49 20181206174917_items.up.sql
-rw-rw-r--  1 vagrant vagrant    0 127 03:15 20181206180443_item_details.down.sql
-rw-rw-r--  1 vagrant vagrant    0 127 03:15 20181206180443_item_details.up.sql

SQLをファイルに書き込む

CREATE TABLE, DROP TABLEをそれぞれファイルに書き込みます。 ブログの内容ですと、 IF EXIST になっていますが、正しくは IF EXISTS です。

12/07追記:製作者さんにブログを修正していただきました!

テーブル作成

itemsテーブル

$ vim migrations/20181206174917_items.up.sql

若干僕の趣味で、PKは bigint(20) unsigned だったり、絵文字を識別したいので COLLATE=utf8mb4_bin だったりします。

CREATE TABLE IF NOT EXISTS `items` (
  `item_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `item_name` varchar(255) NOT NULL,
  `created_at` datetime NOT NULL,
  PRIMARY KEY (`item_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

item_detailsテーブル

$ vim migrations/20181206180443_item_details.up.sql

こちら金額が入ってるだけですが、金額を扱う場合は DECIMAL または NUMERIC を推奨、とMySQL公式でも記述があります。

CREATE TABLE IF NOT EXISTS `item_details` (
  `item_detail_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `price` decimal(10,3) NOT NULL,
  `created_at` datetime NOT NULL,
  PRIMARY KEY (`item_detail_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

テーブル削除

itemsテーブル

$ vim migrations/20181206174917_items.down.sql
DROP TABLE IF EXISTS `items`;

item_detailsテーブル

$ vim migrations/20181206180443_item_details.down.sql
DROP TABLE IF EXISTS `item_details`;

migration実行

実際に実行し、テーブルを作成します。

テーブルが存在しないことを確認

$ mysql -u root -p mamy1326
Enter password: 
(中略)
mysql> show tables where Tables_in_mamy1326 like 'item%';
Empty set (0.00 sec)

migration実行

$ mig-cli migrate
Start migration.
=================

Migrate migrations/20181206174917_items.up.sql
Migrate migrations/20181206180443_item_details.up.sql

テーブル作成を確認

$ mysql -u root -p mamy1326
Enter password: 
(中略)

# テーブル作成確認
mysql> show tables where Tables_in_mamy1326 like 'item%';
+--------------------+
| Tables_in_mamy1326 |
+--------------------+
| item_details       |
| items              |
+--------------------+
2 rows in set (0.00 sec)

# テーブル定義確認
mysql> show create table items\G
*************************** 1. row ***************************
       Table: items
Create Table: CREATE TABLE `items` (
  `item_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `item_name` varchar(255) COLLATE utf8mb4_bin NOT NULL,
  `created_at` datetime NOT NULL,
  PRIMARY KEY (`item_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin
1 row in set (0.00 sec)

mysql> show create table item_details\G
*************************** 1. row ***************************
       Table: item_details
Create Table: CREATE TABLE `item_details` (
  `item_detail_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `price` decimal(10,3) NOT NULL,
  `created_at` datetime NOT NULL,
  PRIMARY KEY (`item_detail_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin
1 row in set (0.00 sec)

無事に作成されました。

migrationテーブル確認

ここまでで2つのテーブルを作成したので、管理しているmigrationテーブルをみてみます。

$ mysql -u root -p mamy1326
Enter password: 
(中略)

mysql> select * from migrations\G
*************************** 1. row ***************************
        id: 20181206174917
applied_at: 1544120647
*************************** 2. row ***************************
        id: 20181206180443
applied_at: 1544120647
2 rows in set (0.00 sec)

idが migrationファイル名の年月日時分秒 になっていることが確認できます。

rollback実行

2つのテーブルを作りましたが、rollbackするとファイル単位で実行されているようですね。

$ mig-cli rollback
Rollback a migration.
======================

Rollback migrations/20181206180443_item_details.down.sql

migrationテーブル確認

Rollback migrations/20181206180443_item_details.down.sql とあるように、該当する年月日時分秒のレコードが削除されているのがわかります。

mysql> mysql> select * from migrations\G
*************************** 1. row ***************************
        id: 20181206174917
applied_at: 1544120647
1 row in set (0.00 sec)

実際にテーブルも削除されていますね。

mysql> show tables where Tables_in_mamy1326 like 'item%';
+--------------------+
| Tables_in_mamy1326 |
+--------------------+
| items              |
+--------------------+
1 row in set (0.00 sec)

再度migration実行

さっきDROP TABLEされたmigrationファイルが実行されています。

$ mig-cli migrate
Start migration.
=================

Migrate migrations/20181206180443_item_details.up.sql

migrationテーブル、実際のテーブルも作成されていますね。

mysql> melect * from migrations\G
*************************** 1. row ***************************
        id: 20181206174917
applied_at: 1544120647
*************************** 2. row ***************************
        id: 20181206180443
applied_at: 1544121133
2 rows in set (0.00 sec)

mysql> show tables where Tables_in_mamy1326 like 'item%';
+--------------------+
| Tables_in_mamy1326 |
+--------------------+
| item_details       |
| items              |
+--------------------+
2 rows in set (0.00 sec)

連続でrollback

1つずつ、年月日時分秒を遡ってrollbackが実行されるようです。

$ mig-cli rollback
Rollback a migration.
======================

Rollback migrations/20181206180443_item_details.down.sql
$ mig-cli rollback
Rollback a migration.
======================

Rollback migrations/20181206174917_items.down.sql

テーブル、レコードも消えていますね。

mysql> select * from migrations\G
Empty set (0.00 sec)

mysql> show tables where Tables_in_mamy1326 like 'item%';
Empty set (0.00 sec)

使ってみて

非常にお手軽に導入できて、直接SQLを記述できて素晴らしいと思いました。これなら何にも依存せずに使うことができそうです。

PostgreSQLにも対応してくれたら個人的には嬉しいです!!

migrationは便利だけど、フレームワークに依存するよなーSQL直接書きたいよなーって思っていた僕にはとてもいいものに思えました。

現在のところはフレームワークの流儀にのっとって、フレームワークのmigrationを使っていますが、もしレガシーな運用をしているプロダクトに出会ったら、便利に使えそうだなって思ったりしてました。

また、ここに掲載しなかったいろんなパターン(CREATE TABLEの後にALTER TABLEなど)を試してみて、migrationってシンプルに運用できるよな、でもなんども実行するもんじゃないし、最初に設計って重要だよな、って改めて思ったりしてました。

おわりに

OSS活動されているかたって本当に尊いなって思います。 以前、吉祥寺.pm で fujiwara さんがされていたLTを思い出しました。

業務などで使う便利なツールを、業務の活動の範囲でOSSにしてしまう。

こんな活動に通じるものがあるよなあって思ったし、自分が何かOSSを提供できるかどうかはわかりませんが、作ったもので便利そうなものがあれば、積極的にGitHubで公開などできたらなって思わせていただきました。

いやー楽しかった!

学習記録:12月6日(木):ぺちオブ参加日誌2 -オブジェクト指向のいろはとモブプロ-

これは 俺のインプットアウトプット記録 Advent Calendar 2018 の6日目のエントリーです。

昨日のエントリーである 学習記録:12月5日(水):ぺちオブ参加日誌 -これほどわかるOOPの解説は今までなかった- に引き続き、本日 【ぺちオブ】第二回オブジェクト指向のいろはを輪読とか写経する会 に参加してきました。

今回初めての

  • Qiitaの記事を著者さん監修でモブプロする

の体験記を、日が変わらぬ熱いうちに綴ってみたいと思います。

はじめに

先日参加した 【ぺちオブ】初心者向け!第四回オブジェクト指向を1から勉強してみよう会、 前々から興味を持っていた 第二回ボトムアップドメイン駆動設計 に引き続きの参加でした。

なんとこの時点で僕は存じ上げていなかったのですが、Qiitaの記事と 第二回ボトムアップドメイン駆動設計 の講義をしてくださったのが @nrs さんで、同一人物だったってことです。

昨日、 hiro@miraito さんと会話していて知りました。100人以上の前でDDDのお話を体系立ててわかりやすく話してくださった人がいる場でのQiitaの写経とモブプロ。

非常に刺激的かつ、あたたかみに溢れる場所で、部屋が少々暑かったのはエアコンのせいだけじゃないなって思いました。

また、モブプロというのも初めてで、これは今回初参加グループのファシリテーターをしてくださった おーひら モブプロ本売ってまっせ! さんの記事 モブプロで技術書を攻略する! に詳しいです。

参加してみて

最高でした。(今月2回目)

ちょっと遅れての参加だったんですが、ほんとなんでしょうね。ぺちオブのみなさんは本当に丁寧かつポジティブというか、もうなんども言いますが あったかい んですよ。

参加すれば歓迎され、コメントすれば褒められ、コードが書ければ盛り上がり、動いたら踊りだしかねない。 そりゃあポジティブに楽しめるってものです。

生きるってことの本質ってこういうことだよな、って思わせてくれます。

勉強会の進みかた

Qiitaの記事の写経を、モブプロで実施していきます。まさに モブプロで技術書を攻略する! の中に書かれていることを実践してくださっていました。

やったことを列挙してみます。

予習なし

  • 記事を読んでないこと前提

1行ずつ輪読する

  • グループ7人(だったと思う)が1行ずつ読む
  • これが抽象化なのだとあとで知ることになります
  • 多くの文章を読ませない

わからないをそのままにしない

モブプロでコードをPHPに変換して動かしながら進める

  • Qiitaの記事はC#で書かれている
  • その場でPHPに変換して、動かしながらやる
  • みんなで小さな章に区切ってコードを書いていく

会の終わりに振り返りをして締める

  • みんなが何を持ち帰れたかみんながわかる
  • みんな笑顔
  • 最高じゃん?

僕が得られたこと

濃密な時間の中で得られたことはたくさんあるんですが、箇条書きにしてみます。 これも全部 モブプロで技術書を攻略する! に書いてありそうなので、せっかくなので引用しながら。

ポイント1. すべてを声に出して読む

これ本当に重要で、自分の声に出すだけじゃなく、他人の声で聞く。見る、聞く、交代する。僕が一番強く思ったのは、これぞ輪読の抽象化なのだと思いますが、 自分の読んでいる部分にのみ集中できる ということです。

つまり、OOPの目的である 抽象化による本質への集中(でいいのかな) をやっているってことです。

ポイント2. とにかく表明する

すでに書いちゃったんですけど、質問、わからないこと、思ったことだけでなく、他人がどう思っているのか。その場でとにかく表明してしまうんですよね。

わからないので知りたい。僕はこう思った。あなたはどう思いますか。

感想だけでもいいし、良いこと言ったら 最高! とか言い合うわけです。決して宗教じゃないんですよね。いろんな人の考え方から、多角的に1つずつ自分の中にインプットされていくのが重要なんだなって思いました。

感情の共有も含め、非常に大事なことなんだってことを体験させてもらいました。

ポイント3. 予習をしない

僕は記事を1行も読んでいませんでした。またそういったかたも多くいらっしゃいました。

人間は予習をしない

とは おーひら モブプロ本売ってまっせ! さんの言葉でもありましたが、まさに予習をしない(必要としない)前提で会が進んでいきます。

なぜかというと、予習しないことでまっさらな自分で参加できる。 そこには自分の偏った認識ではなく、ファシリテーター、執筆者含め、体系立てた情報が多角的にインプットされる。

自分が綺麗にフォーマットされていくんだなってことを気づかせてくれました。 シンプルな輪読会なら、事前に予習したほうが捗るかもしれません。でもこの会の目的は違う。なんの敷居もない。そこにあるのはただ シンプルかつ莫大なインプットがある ってことでした。

予習しないというのは今まで考えたこともなかったことなので、目から鱗でした。

他の特徴

とにかく時間はかかります。今日は オブジェクト指向のいろは のclassの途中 まで進んで終了でしたし、ここまで2時間半かかっています。

が、これはその場にいる13人(だったかな)全員の体験なんですよね。13人13様が、みんなで共有できる。13人のことが13人でわかるんです。

これがもしチームでやれてたりしたらすごい力になると思うし、きっと元々はそれが目的だったんだろうなってことがわかったりもしました。

モブプロってすげぇな、をこんな短時間で体感できて、多くのことを持ち帰ることができた。 いやこれってすごいことだと本当に思います。

聴講しながら書いたコード

モブプロにも参加しましたが、話を聞きながら僕も手を動かしたかった。 なので聴講しつつ話をしつつ、大急ぎで書いて手元で動かしたコードがこちらです。

<?php

class Writer {
    const WRITE_TYPE_CONSOLE = "console";
    const WRITE_TYPE_FILE = "file";
    private $writeType;
    private $data;

    public function __construct(string $writeType, array $data)
    {
        $this->writeType = $writeType;
        $this->data = $data;
    }

    public function write(): void 
    {
        if($this->writeType == self::WRITE_TYPE_CONSOLE) {
            $this->writeConsole();
        }
        else if($this->writeType == self::WRITE_TYPE_FILE){
            file_put_contents('write.txt', $this->data);
        }
        else {
            throw new Exception("writeType:" . $this->writeType . PHP_EOL);
        }
    }

    private function writeConsole():void
    {
       echo("Data:".PHP_EOL);
       foreach($this->data as $element) {
           echo("- {$element}".PHP_EOL);
       }
    }

    private function writeFile():void
    {
        file_put_contents('write.txt', $this->data);
    }
}
$writer = new Writer($argv[1], ['hoge', 'fuga']);
$writer->write();

おわりに

最後は会を締め、会議室の現状復帰をし、後片付けをして撤収。 軽くご飯組と帰る組で分かれたんですが、なぜかハイタッチの嵐をいただきまして。

ぺちぱーだからぺちぺち

和むじゃないですか。なんか自分が人気者になったような錯覚に陥って妙に照れ臭かったです。 なんだよもうそんなんあるんだったら手を洗っておくんだったわ、って思いました(汚いわけじゃないですw)

執筆者の @nrs さんも ついつい解説したくなる とのことで本当にありがたいなって思うとともに、こういう オブジェクト指向に特化 した会を 連続して実行する っていうのは少なくとも僕の行動範囲では全くありませんでした。

が、昨日も言ったかもしれないんですが、ここまでの時間と知識と経験を使って惜しげも無くインプットをいただける。そんな場を作って楽しくやっていく。

なんの気後れも必要ない。なんならなんの用意も必要ない。欲しいと思う人に、欲しいだけの全てを分けてくれる。

あー。エンジニア諦めなくてよかったなー。こんな人たちがいるんだなー。受けた恩は後ろに続いてくれ人に送っていいかなきゃなー。

改めて、僕の目標や信念を改めさせてもいただきました。

あと、最後に紹介したいことタイムを作ってくれたので、僕が主催にいる エンジニアの登壇を応援する会 の告知をさせていただきました。

また、直近のイベントである 読書の技術を勉強する会 #1 や、年末12月27日の エンジニアの登壇を応援する忘年LT大会 の紹介をさせていただきました。

僕はぺちオブとはまた違った角度で、誰かの背中を押し続けていきたいし、いずれ理解や経験が積み重なったら、その積み重なりをぺちオブに返還したいなあって思ってもいます。

今後も参加していくし、まだのかたはぜひ参加してみてください。最高だぞ!

というわけで、本日の諸々の手配をしてくださったみなさま、ありがとうございました!

学習記録:12月5日(水):ぺちオブ参加日誌 -これほどわかるOOPの解説は今までなかった-

これは 俺のインプットアウトプット記録 Advent Calendar 2018 の5日目のエントリーです。

ところで去る12月1日(土)、10時〜16時くらいまで、【ぺちオブ】初心者向け!第四回オブジェクト指向を1から勉強してみよう会 に参加してきました。

というわけで、参加ポエムを綴ります。

最初に言うと、ポエムが綴れるようになるくらい最高の方々と内容と時間だったってことです。

はじめに

オブジェクト指向プログラミング (Object-oriented programming) と言われ続けて個人的に25年。

今の今まで、自分の中にすんなり入ってくるタイミングが全くありませんでした。

それは僕自身の理解力や技術力、知識、経験など、いろんな要素が不足していたとともに、階段を上がるタイミングを得られなかったんだなって思います。

積み上がった知識はある。しかし…

僕としても最近はLaravelを使った設計思想だったり、DDDだったり、いろんな意味で オブジェクト指向についての知識が自分の中に蓄積 されているのを感じていました。

しかし実務で感じられるレベルではまだない。何か丁寧かつ体系的にインプットできる場所はないものか…。そう思っていた矢先に見つけたのが、この 【ぺちオブ】初心者向け!第四回オブジェクト指向を1から勉強してみよう会 でした。

僕のOOPへの階段はここから上がったんだと思います。

参加してみて

最高でした。

詳しくはぺちオブの主催のみなさんが用意し、更新し続けてくださった これからオブジェクト指向を学ぶ方へ送りたい旅のしおり (後日まとめて公開される予定とのことです) を読めば一目瞭然。これだけで本ができるし、絶対売れると思います。

具体的な振り返り

僕自身の言葉で振り返り、噛み砕くエントリーは、また別で作りたいと思います。おそらくですが、準備してくださり、回を重ねるごとに情報が蓄積・追加されていく過程を僕の理解でなぞることになると思います。

当然、今まで積み上げてくださった時間以上に、僕自身時間をかけなくてはアウトプットできない情報量でした。

ぺちオブで得たインプット・アウトプットの輪廻の中に自分の身を置かねば、と強く思っている次第です。

勉強会の進みかた

SOLID原則を1つずつ1日かけて紐解いていくスタイルだったのですが、

  • 毎回初参加の人向けと振り返りのために
  • 前回までやったことを丁寧に解説

してくれるんですね。僕は第四回ですので、第三回までの「O、D、S」までは参加していません。 が、参加したのと同等かそれ以上の時間と情報でスッと理解できる内容でした。

何と言っても、振り返りに3時間近くかけている。これがどれだけありがたいことで、かつどれだけすごいことか…。

hiro@miraito さん曰く 勉強会が終わった後に追加される内容の方が多い とのこと。 なんなんだよ最高だよ。これぞ集合知

今までにない体験をさせていただきましたし、こういうスタイルで多くの人に何かしら情報を発信できる乗って本当に最高だな(語彙力)ってずっと思ってました。

自分が8ヶ月続けてきた学習スタイルも、巡り巡って 知ったことを丁寧に積み上げていく 形に落ち着いたので、個人としてもすごく入りやすかったです。

改めて最高だったところ

なので、僕が改めて語ることは本当に感想くらいしかないのですが、それでも何が最高だったかを列挙したいのでしてみます。

  • まず言葉を解説。言葉がわからないと進めないよね
    • 何より解説や内容以上に、みんなあったかい
  • 概念理解から入り、丁寧に解説してくれた
    • 具体性を紐解いていく 徹底したトップダウンスタイルで説明してくれた
  • 解説のドキュメントが充実している
    • 1回ずつの積み重ねや前提、ターゲットなど非常に丁寧
  • SOLID原則を1つずつ、5種類を5日かけて丁寧に
    • 講義を受ける側が5日かかるということは
    • 準備してくれる皆さんはその何倍もの時間をかけてくれている
    • それを自発的にやってくれている
    • お金を払ってもやってくれそうにないくらいの濃密さ
  • オブジェクト指向の学習という旅
    • 学習とは知らない土地にいく旅
    • しおりがあった方が快適だし楽しめる
    • そのしおりですよ、と
  • 特にぺちオブを体現していると思われる言葉たちを引用します

このしおりを持って実際にオブジェクト指向の学習という旅出るとこのしおりだけでは伝えきれなかった事も含めて様々な実体験をするでしょう。そして、その旅を終えた頃にはようやく、オブジェクト指向設計やプログラミングが体感できるようになる事かと思います。

そしてその暁に、またそれぞれの新たなしおりが作成されていると非常に嬉しいです。

雰囲気

これまた最高でした。

プレゼンター

hiro@miraito さんでした。また話が丁寧、かつ言葉を紐解いていってくれるのでわかりやすいことこの上なかったです。

これまでのOOPの説明のなかで(書籍も含めて)最高でした。 また声も優しくて素敵。

hiroさんの言葉、僕が言うのもなんなのでご本人の言葉を紹介させていただきます。

特別講師

れおりん 🦀 🐘YYPHP さん。どんな質問もmsec単位ではっきり返してくれました。 しかも根拠も解説してくれるし、講義中にライブコーディングでサンプルコードを提示してくれる。

メインプレゼンターがhiroさんだったからなのだと思いますが、ほとんど言葉を挟まずに静かにその場にいらっしゃいました。が、質問が出ると即座に反応してくださる。

hiroさんのトークとれおりんさんの解説、相乗効果が半端ではなかったです。

質疑応答

話の途中でも頻繁に質問が飛び交い、回答がどんどん得られる。(ライブ配信も行っていました)

僕も何度か質問させていただきましたし、質問だけじゃなく、確認という意味で「自分で理解したことはこういうことだけど、あっていますか?」という問いかけにも丁寧に答えていただきました。

おわりに

完全に感想文になってますが、それくらい最高だったってことでした。 他にも会場を手配して準備してくださったかた、当日案内してくれたかた、などなど、その場を形成してくださった全てのかたに感謝しています。

また、自分の中に蓄積されていた知識や経験が少しずつJOINされていく感覚をはっきり味わうことのできた時間でした。 その証拠に、次に参加した 第二回ボトムアップドメイン駆動設計 の内容が理解できるんですよね。

まだまだ実践には至ってないですが、言っていることがわかる。これもまた初めての体験でした。

本当は振り返りとして、学んだことを丁寧に書き留めてアウトプットしたいのですが、まだ自分の中の情報が整理しきれていません。

振り返りは次の機会にしたいと思います。

明日の 【ぺちオブ】第二回オブジェクト指向のいろはを輪読とか写経する会、土曜日の 【ぺちオブ】初心者向け!最終回オブジェクト指向を1から勉強してみよう会 も参加するのでよろしくお願いします!

学習記録:12月4日(火):[sftp] ユーザーの作り方

これは 俺のインプットアウトプット記録 Advent Calendar 2018 の4日目のエントリーです。

以前、sftpユーザーを作って提供する機会があったのですが、意外と情報が少ないことに気づきました。

ファイル転送プロトコルであるsftpですが、Webサーバーへ様々なファイルをアップロードする際など、まだまだ利用されているのが実情だと思います。

また、sftpだけでなく、ftpを利用するシーンもあることですし、この情報は有用なのでは?と思い、手取り足取りsftpユーザーの作り方を解説してみます。

前提

  • ubuntu16で実行
  • Webサーバーへのコンテンツアップ目的
  • アップロードできるディレクトリに制限を設ける
  • sftpユーザー作成にまつわる作業は全てコンソール上から実施

設定の流れ

  • sftp用ユーザー作成
  • ユーザーのグループ設定
  • ssh鍵作成
  • sftpできるディレクトリ制限
  • sftp先を制限する(DocumentRoot配下のみ許可)
  • sftp確認

対象者

  • 提供したサーバーに対し、直接ファイルアップロードのニーズがある方
  • 古いシステムをメンテナンスしている方
  • 鍵認証についてざっくり知りたい方
  • コンソール怖いという方(コワクナイヨ

sftp設定

新規ユーザー作成

  • sample-sftp というユーザーを作ります
$ sudo useradd sample-sftp
$ sudo passwd sample-sftp
新しい UNIX パスワードを入力してください: 
新しい UNIX パスワードを再入力してください: 
passwd: password updated successfully

# ユーザー用のディレクトリを作成
$ sudo mkdir /home/sample-sftp

sftpユーザーのグループ指定

次にsftpユーザーの所属グループを設定します。 今回はnginxで動いているDocumentRootに対し、コンテンツをアップすることが目的なので、条件を以下とします。

  • sftp接続後のディレクトリは変更しない
    • /home/sample-sftp のまま
    • 理由は後述の openssl(chroot)によるディレクトリ制限 のため
# DocumentRootの持ち主であるnginxユーザーをみる
$ id nginx
uid=112(nginx) gid=116(nginx) groups=116(nginx)

# sftpユーザーをnginxのグループに追加する
$ sudo usermod -g 116 sample-sftp

# グループIDを確認する
$ id sample-sftp
uid=1001(sample-sftp) gid=116(nginx) groups=116(nginx)

無事にグループがnginxになりました。

SSH鍵作成

次にsftpで接続するための鍵を作ります。 その前に鍵を保存するディレクトリを作成します。

$ cd /home/sample-sftp
$ pwd
/home/sample-sftp
$ sudo mkdir .ssh
$ sudo chown sample-sftp:sample-sftp .ssh
ubuntu@ip-172-31-47-139:/home/sample-sftp$ ls -la 
合計 12
drwxr-xr-x 3 root        root        4096 124 22:37 .
drwxr-xr-x 4 root        root        4096 124 22:35 ..
drwxr-xr-x 2 sample-sftp sample-sftp 4096 124 22:37 .ssh

次に実際にsftpするユーザーにチェンジし、鍵を作成します。 鍵のファイル名はデフォルト、パスワードは設定しません。

$ su sample-sftp
パスワード:
$ cd .ssh
$ ssh-keygen -t rsa -b 4096
Generating public/private rsa key pair.
Enter file in which to save the key (/home/sample-sftp/.ssh/id_rsa): [press enter]
Enter passphrase (empty for no passphrase): [press enter]
Enter same passphrase again: [press enter]
Your identification has been saved in /home/sample-sftp/.ssh/id_rsa.
Your public key has been saved in /home/sample-sftp/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:3YlPDtl7NZ0wX6DbGu5B5Z4+C39amQfQ3GcBg9XjGwk sample-sftp@ip-172-31-47-139
The key's randomart image is:
+---[RSA 4096]----+
|            o++. |
|           . E.=.|
|            oo* B|
|         . = B+==|
|        S = O ++=|
|           B = =+|
|            O +oo|
|           . *..o|
|            . == |
+----[SHA256]-----+

生成された鍵ファイルを確認します。

$ ls -la
合計 20
drwxr-xr-x 2 sample-sftp sample-sftp 4096 124 22:43 .
drwxr-xr-x 3 root        root        4096 124 22:37 ..
-rw------- 1 sample-sftp nginx       3247 124 22:40 id_rsa
-rw-r--r-- 1 sample-sftp nginx        754 124 22:40 id_rsa.pub

次に、公開鍵(ドアノブの鍵穴みたいなもの)を authorized_keys というファイルに転記します。 なお、適切な権限に設定しないと認証に失敗しますので、合わせて設定します。

$ chmod 600 authorized_keys
$ chmod 700 ../.ssh
$ pwd
/home/sample-sftp/.ssh
$ ls -la
合計 20
drwx------ 2 sample-sftp sample-sftp 4096 124 22:43 .
drwxr-xr-x 3 root        root        4096 124 22:37 ..
-rw------- 1 sample-sftp nginx        754 124 22:43 authorized_keys
-rw------- 1 sample-sftp nginx       3247 124 22:40 id_rsa
-rw-r--r-- 1 sample-sftp nginx        754 124 22:40 id_rsa.pub

# suでチェンジしたユーザーからexit
$ exit

sftpできるディレクトリを制限

sftpアカウントで接続した際、ルートからなんでも見れて更新できては何かと困ります。 ゆえに制限をかけていきます。

  • sshd_configはバックアップをとっておき、何かあったらすぐ戻せるように
  • sshd_configに制限を追加
  • 再起動

まずバックアップを作成します。

$ pwd
/etc/ssh
$ sudo cp -rp sshd_config sshd_org_config

ユーザーの制限事項を追加します。

# /etc/ssh/sshd_configを開く
$ sudo vim sshd_config

/etc/ssh/sshd_configにユーザー制限を追加します。 ファイルの末尾に追加しました。

Match User sample-sftp
    ChrootDirectory /home/sample-sftp
    ForceCommand internal-sftp

次にsshを再起動して設定を反映します。

$ sudo /etc/init.d/ssh restart
[ ok ] Restarting ssh (via systemctl): ssh.service.

あと、僕は失敗した時のために、必ずすぐ戻すためのコマンドを先に用意してたりします。

mv sshd_config sshd_config_failed
mv sshd_org_config sshd_config
sudo /etc/init.d/ssh restart

DocumentRootの調整

DocumentRootで直接ファイルを操作されると何かと困(ry 以下の手順で sftpユーザーのhome配下のみ更新できる ように設定していきます。

  • /home/sample-sftp/htdocs の配下にアップロードしてもらう
  • /srv/www/www.mamy1326.jp/htdocs を上記のシンボリックリンクにする
  • これをやることで、 sshd_configに設定したChrootDirectoryの制限を回避できる

/home/sample-sftp/htdocsを作成し、sftp接続で書き込み可能にします。

$ pwd
/home/sample-sftp
$ sudo mkdir htdocs
$ sudo chown sample-sftp:sample-sftp htdocs
$ sudo chmod 755 htdocs
$ ls -la
合計 16
drwxr-xr-x 4 root        root        4096 124 22:57 .
drwxr-xr-x 4 root        root        4096 124 22:35 ..
drwx------ 2 sample-sftp sample-sftp 4096 124 22:43 .ssh
drwxr-xr-x 2 sample-sftp sample-sftp 4096 124 22:57 htdocs

次に、実際のDocumentRootにシンボリックリンクを作成します。

$ pwd
/srv/www/www.mamy1326.jp
$ sudo ln -s /home/sample-sftp/htdocs public
$ ls -la
合計 12
drwxr-xr-x 3 root root 4096 124 23:01 .
drwxr-xr-x 4 root root 4096  97 02:37 ..
lrwxrwxrwx 1 root root   24 124 23:01 public -> /home/sample-sftp/htdocs

sftp実行

これで準備は整いましたので、実際に接続し、意図通りにファイル操作ができるかを確認します。手順は以下です。

  • ローカルから接続
  • 書き込みできることを確認
  • 他のディレクトリに移動できないことを確認
  • sftpのみ(sshできない)ことを確認
  • コンテンツをアップして、DocumentRootにアップされていることを確認する

まずは先ほど作った秘密鍵をサーバーから取得します。 ファイルの設置や、適切な権限設定を実行しておいてください。

$ scp -i mamy1326.pem ubuntu@18.179.206.65://home/ubuntu/id_rsa id_rsa_sample-sftp
id_rsa                                                                                                                              100% 3247    54.4KB/s   00:00 
$ sudo cp id_rsa_sample-sftp ~/.ssh
$ sudo chmod 600 ~/.ssh/id_rsa_sample-sftp
$ ls -la ~/.ssh/id_rsa_sample-sftp
-rw-------   1 mamy1326  staff  3247 12  4 23:06 id_rsa_sample-sftp

準備は整ったので、実際に接続してみます。

$ sftp -i id_rsa_sample-sftp sample-sftp@18.179.206.65
Connected to sample-sftp@18.179.206.65.
sftp> 

無事に接続できたので、色々コマンドを実行してみましょう。

# /home/sample-sftp直下にはアップロードできない(root:rootなので)

# 一覧をみる
sftp> ls -la
drwxr-xr-x    4 0        0            4096 Dec  4 13:57 .
drwxr-xr-x    4 0        0            4096 Dec  4 13:57 ..
drwx------    2 1001     1001         4096 Dec  4 13:43 .ssh
drwxr-xr-x    2 1001     1001         4096 Dec  4 13:57 htdocs

# 場所を確認する。sftpユーザーからみてルートであることがわかる
sftp> pwd
Remote working directory: /

# 権限が与えられていない場所にputすると権限がなくて失敗する
sftp> put sample.pdf                    
Uploading sample.pdf to /sample.pdf
remote open("/sample.pdf"): Permission denied
sftp> 

次に、権限が与えられているディレクトリに移動し、ファイルをputしてみます。

# htdocs配下にはアップできる

sftp> cd htdocs 
sftp> put sample.pdf
Uploading sample.pdf to /htdocs/sample.pdf
sample.pdf                                                                                                                          100% 4007    54.2KB/s   00:00    
sftp> ls -la
drwxr-xr-x    2 1001     1001         4096 Dec  4 14:17 .
drwxr-xr-x    4 0        0            4096 Dec  4 13:57 ..
-rw-r--r--    1 1001     116        614935 Dec  4 14:17 sample.pdf
sftp> pwd
Remote working directory: /htdocs
sftp> 

最後に、実際にDocumentRootにファイルが設置されているか確認します。

$ ls -la /srv/www/www.mamy1326.jp/public/
合計 12
drwxr-xr-x 2 sample-sftp sample-sftp 4096 124 23:17 .
drwxr-xr-x 4 root        root        4096 124 22:57 ..
-rw-r--r-- 1 sample-sftp nginx     614935 124 23:17 sample.pdf

無事にアップされていますね。 これでめでたく、外部の人に制限されたアクセス状態で、DocumentRootを更新 できるようになりました。

Webブラウザから確認

DocumentRootにアップしたので、Webブラウザから見れることを確認しておきます。 そのうちインスタンスを停止しますが、現在こんな感じですね。

f:id:Mamy1326:20181205010630p:plain
さんぷるのPDF

連絡報告

あとはクライアントに、接続情報、鍵ファイル、制限事項などを連絡報告および共有します。 その結果として、クライアントが無事に接続でき、目的を達成できたことを確認して、クライアント向けの作業が完了、となるかと思います。

課題

ブラウザから確認

  • せっかくWebサーバー立てて、ドメイン名をとったので、ブラウザから確認できるようにエントリーに追記します。
    • やりました!

CyberDuck確認

おそらくクライアントは何かしらツールを使うと思うので、設定手順があると便利よね。

ドキュメント整備

実際の業務だと、作って終わりというわけではないと思います。 各種情報や鍵ファイルなどは適切な権限と場所に管理しておきましょう。

  • GoogleDriveにsftp用の鍵を置く
  • 同じくアカウント情報を置く
    • 情報(sftp)
      • IPアドレス
      • ユーザー名
      • 鍵のファイル名
      • 接続方法
      • コンテンツアップ先(フルパス)

やってみて

以上、実際にEC2インスタンスを立て、Webサーバー(nginx)を起動し、実行した結果です。

実際の業務では、単一の作業だけではなく、お客さんへのリリースや連絡、社内でのドキュメント整備など、付随する作業があると思います。

また、なぜそう設定するのか。 理由も含めて手順として残しておけたらいいですよね。

というわけで、僕の個人メモをもう一度再現し、実際に動いた結果といて公開してみました。

もう一度やれと言われたら暗記してる自信は皆無だし、未来の自分が今の自分に必ず感謝すると思うので、積極的に残していきたいですね。

学習記録:12月3日(月):【git stash】作業ブランチを作らず作業してしまった時の対処法

これは 俺のインプットアウトプット記録 Advent Calendar 2018 の3日目のエントリーです。

今日は MyNA(日本MySQLユーザ会) 望年LT大会2018@赤坂 に参加して多少酔っています。いやー楽しかった!次は僕もLTできるネタを持って行こう。

ところでみなさん、gitでうっかり 作業ブランチを作らず作業してしまった なんてこと1度はありませんか?僕はあります。

とはいえ他に同じようなエントリーは溢れていると思うので、備忘録とこれからの人にすんなり解説できるためにも、自分のブログに書いてみます。

前提条件

  • gitはコマンドから実行します
  • 仮に以下のプロジェクトがあったとします
$ pwd;find . | sort | sed '1d;s/^\.//;s/\/\([^/]*\)$/|--\1/;s/\/[^/|]*/|  /g'
/Users/mamy1326/dev/mamy1326/git_stash_test
|--app
|  |--controller
|  |  |--Fuga.php
|  |  |--Hoge.php
  • このプロジェクト、うっかりmasterに変更しちゃったよ
  • それをstashを使って作業ブランチへ移動し、merge
  • 無事に作業ブランチからadd, commit, pushして、PullRequestを出す

というところまで実施します。

正しい(と僕は思っている)方法

僕が実際にやってみて、他でも調べて、これが正解と思う内容を紹介します。

やっちまった

さあ修正が終わったぞ、と思って、 add, commit, push してさっさとPullRequestしちまおう!と思うじゃないですか。

$ git status
On branch master
Your branch is up to date with 'origin/master'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   app/controller/Fuga.php
    modified:   app/controller/Hoge.php

no changes added to commit (use "git add" and/or "git commit -a")

OKOK、さてブランチは…っと。

$ git branch
* master

( ゚д゚)ハッ! 作業ブランチ切ってないやないかーい!

そしてこの時、僕はまだstashを知らないわけです。

まず深呼吸して落ち着く

困った時に最初にやること。いや大事です。まず深呼吸しましょう。そのあと、できれば何に困っててどうしたいか紙に書きましょう。 絶対に解決できる方法がある。先人の知恵ってすごいんです。

まずは落ち着いて未来を信じましょう。

変更を保存する: git stashgit stash list

落ち着いたら以下のコマンドを実行します

$ git stash
Saved working directory and index state WIP on master: 2b38798 first commit.
$ git stash list
stash@{0}: WIP on master: 2b38798 first commit.

これにより、masterで実行した変更が一時的な保存リスト stash@{0} に保存されたことがわかります。

変更を確認する: git stash show

一応、保存された内容を git stash show で確認してみましょう。

$ git stash show stash@{0}
 app/controller/Fuga.php | 2 +-
 app/controller/Hoge.php | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

どうでしょう。変更した内容をちゃんと確認できるかと思います。 こうなれば、別のブランチに移動できます。

つまり、作業ブランチを作成することができるということです。

作業ブランチを作って移動: git checkout -b

Issueに基づいて作業することを前提としているので、Issue番号で作業ブランチを作成します。

$ git checkout -b feature/1 origin/master
Branch 'feature/1' set up to track remote branch 'master' from 'origin'.
Switched to a new branch 'feature/1'
$ git branch
* feature/1
  master

無事に作業ブランチを作成し、移動できたことがわかります。

一時保存した変更内容をmergeする: git stash apply

まずは一応、一時保存リストを確認します。 先程はmasterで確認しましたが、新しい作業ブランチでも見れることを確認しないと不安で胸が張ちきれそうです。

特に僕はブログなどの「わかる人にはわかる行間」がわからなくてハマることが多いので、1つずつ確認していきます。

$ git branch
* feature/1
  master
$ git stash list
stash@{0}: WIP on master: 2b38798 first commit.

先ほど保存した内容が、作業ブランチでも確認できます。

一応の一応、変更内容そのものも確認しておきましょう。

$ git diff stash@{0}
diff --git a/app/controller/Fuga.php b/app/controller/Fuga.php
index 173f17f..4f6b682 100644
--- a/app/controller/Fuga.php
+++ b/app/controller/Fuga.php
@@ -1,2 +1,2 @@
 <?php
-echo("fugafuga!!");
+echo("fuga!!");
diff --git a/app/controller/Hoge.php b/app/controller/Hoge.php
index 079d8f7..4a1f61a 100644
--- a/app/controller/Hoge.php
+++ b/app/controller/Hoge.php
@@ -1,3 +1,2 @@
 <?php
-echo("hogehoge!!");
-
+echo("hoge!!");

いやーつまんない修正例ですみませんね!でもちゃんと修正の差分も見れることが確認できました。

では落ち着いて、mergeしちゃいましょう。

$ git stash apply stash@{0}
On branch feature/1
Your branch is up to date with 'origin/master'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   app/controller/Fuga.php
    modified:   app/controller/Hoge.php

no changes added to commit (use "git add" and/or "git commit -a")

git stash で一時保存された内容がmergeされ、そのファイルのリストが表示されます。 これは git status を実行した時と同じです。

念の為 git status も実行します。

$ git status
On branch feature/1
Your branch is up to date with 'origin/master'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   app/controller/Fuga.php
    modified:   app/controller/Hoge.php

no changes added to commit (use "git add" and/or "git commit -a")

おんなじですね。

やっといつもの: git add, git commit, git push

ここまでくればいつものやつ。 落ち着いて git add, git commit, git push すればOKです。

まずは git add で追加します。

$ git add .

次に git commit します。コメントはご愛嬌。

余談ですが、コメントは英文にこだわっていた時期がありました。が、英語圏の人と仕事をしないなら、頑張って英文にするより、一目見てわかる日本語のコメントの方が良いと個人的に思っています。

ちなみに、commitコメントに Issue番号 を入れる ( #1 ) と、Issueに記録されていくので便利です。

$ git commit -m "#1 メッセージが寂しいので単語を多くする(ひどい)"
[feature/1 c094ec8] #1 メッセージが寂しいので単語を多くする(ひどい)
 Committer: まみー <mamy1326@gmail.com>
Your name and email address were configured automatically based
on your username and hostname. Please check that they are accurate.
You can suppress this message by setting them explicitly. Run the
following command and follow the instructions in your editor to edit
your configuration file:

    git config --global --edit

After doing this, you may fix the identity used for this commit with:

    git commit --amend --reset-author

 2 files changed, 3 insertions(+), 2 deletions(-)

そしてリモートブランチに git push します。

$ git push origin feature/1
Counting objects: 6, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (6/6), 502 bytes | 251.00 KiB/s, done.
Total 6 (delta 0), reused 0 (delta 0)
remote: 
remote: Create a pull request for 'feature/1' on GitHub by visiting:
remote:      https://github.com/mamy1326/git_stash_test/pull/new/feature/1
remote: 
To github.com:mamy1326/git_stash_test.git
 * [new branch]      feature/1 -> feature/1

gitを日常で使っている方にはおなじみのコマンドを実行してリモートブランチにpushし、PullRequestを出すだけです。

本当にお疲れさまでした。焦るとロクなことないですよね!

一時保存を消す: git stash drop

push、PullRequestしてmergeされたら stash で一時保存した内容は不要なので消しておきましょう。

ローカルもリモートも作業ブランチは削除する(mergeされたら不要だし残しておくべきではない)ので、masterブランチへ移動してから実施します。

# masterブランチへ移動
$ git checkout master
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
# 現在のブランチを確認
$ git branch
  feature/1
* master
# 一時保存リストを見る
$ git stash list
stash@{0}: WIP on master: 2b38798 first commit.
# 一時保存を消す
$ git stash drop stash@{0}
Dropped stash@{0} (ed610ef4a14ee816875b883ff558afac02303ddb)
# dropしたので消えている
$ git stash list

ついでにmasterも最新にしておけば、次の作業もスムーズですね。

$ git pull origin master
remote: Enumerating objects: 1, done.
remote: Counting objects: 100% (1/1), done.
remote: Total 1 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (1/1), done.
From github.com:mamy1326/git_stash_test
 * branch            master     -> FETCH_HEAD
   2b38798..9ad9e31  master     -> origin/master
Updating 2b38798..9ad9e31
Fast-forward
 app/controller/Fuga.php | 2 +-
 app/controller/Hoge.php | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

エントリーにしようと思った動機

そもそもなぜ記録を残して解説しようと思ったのか。

うっかりmasterブランチのまま、修正作業をしてました。で、stashコマンドを使い慣れていればいいんですけど、僕の場合は今回(数週間前)が初めてだったんですよね。

しかも20ファイル以上に修正入れてた。

で、深夜に作業しててひとりでめっちゃ焦って「どうすればええんや…」という脱力感と絶望感に襲われたので、同じような思いをこれからする人もいるかなーと思ったのと、一緒に働くメンバーにgitコマンドを教える機会がありそうなので、出来るだけ丁寧な形で残そうと思ったのでした。

人は誰しも焦る(と思いたい)

うわーこれどうすべぇ…と焦って、調べたらstashってコマンドあるじゃないですか。

で実行して作業ブランチ作って移動してmerge…しようと思ったらなんか怒られる。ブランチの移動もできない。

ニッチもサッチも行かなくなってしまってどう解決したかを記録しておこう、って思ったのです。

きっと1週間後、1ヶ月後、1年後の自分のためになるはず。そう思って どんな小さなことでも、困ったら記録に残す ことを徹底していたりします。

やってみて

こうしてエントリーにまとめてみて思うのですが、 git stash って毎日叩くコマンドでもないので、良い復習になりましたし、アウトプットするためにリポジトリ作って同じことを何度かやったので、もう2度と忘れないですね。

これは普段から発言しているんですが、 インプットとアウトプットの輪廻を作る ことで学習が継続されますし、質も上がりますし、自分の中に刻まれていきます。

かつ、もしかしたら誰かのためになるかもしれないし、内容次第では登壇テーマにもなりうる。

小さなことからコツコツと。 インプットしたら、どんな形でも良いのでアウトプットしよう って思っています。

というわけで、今回は超初心にかえるような内容となりましたが、1つのコマンドについて丁寧に解説するとこんなボリュームになるんだな、と改めて思うとともに、まずは自分にとって不明点がないように書くのって大事だな、ここまでやって初めて 他の人に解説できるようになる な、って思います。

誰かのお役に立てたら良いなと思いつつ、インプット・アウトプットやっていきましょう!

学習記録:12月2日(日):達人に学ぶSQL徹底指南書 第1部 魔法のSQL 1.CASE式のススメ

これは 俺のインプットアウトプット記録 Advent Calendar 2018 の2日目のエントリーです。

常日頃からSQL力(ちから)不足を感じていたところ、以前に購入して積ん読になっていた 達人に学ぶSQL徹底指南書 の第二版が出版されました。

最新のWindow関数も掲載されているということで見た瞬間に購入。しかしこのまま積ん読も怖い…。

と思っていたら、[秋葉原] 達人に学ぶSQL徹底指南書 輪読&勉強会 第1部 魔法のSQL で輪読会をやるということに。なんとありがたいことだ…。

ということで、これは参加しない手はない、読み進めよう!ということで進めています。

まずCASE式から

CASE式だけで24ページあります。正直あんまり使いこなしていなかった式からがっつり入るんだな、と思いつつ、読み進めていく。 これが非常に丁寧でわかりやすい。

  • なぜ必要なのか
  • どういう場面で使うのか
  • IFやDECODEと比べてどうなのか
  • 応用すると真価を発揮する
  • Oracleなどにもきてほしいね

ということが実際のデータとSQLを例に解説されていきます。

僕自身も実際にデータを作ってSQLを実行してやってみているんですが、ちょうど今の仕事でPostgreSQLを使っているので、そちらで試しています。

試したコードも貼っていこうと思うんですが、まずは読み進めということで、書籍に準ずる形でメモを残してます。

esa-pages.io

感想Tweet

いただいたリプ

なんとMySQLユーザー会副会長の 坂井 恵(SAKAI Kei) さん!

安心してください!第二版です!!!!

感想

書籍の導入部分に 実務でのSQLプログラミング半年〜1年 と書かれている通り、SQLの基本的な構文は一通りやっている前提なのかな、と思います。

その上で、じゃあどんな場面でどんな式を使うのか、という内容を歴史や実例を伴って解説してくれています。

まだまだ第1章の途中までしか読んでいませんが、ずっと前から名著と呼ばれる理由をしょっぱなから実感してます。

もしSQL力(ちから)を高めたい、雰囲気で使ってる部分をわかりたい、 プログラマのためのSQL を読んで難しすぎて投げ出した!って人は必読かなって思います。

あと、次のページに出てくるんですが、 WHERE句で条件分岐させるのは素人のやること、プロはSELECT句で分岐させる と明言されていて、非常に使い勝手のいいテクニックとのこと。

ひとつずつ基礎が身についていくこの感覚、すごく楽しいです。

インフラ勉強会は時間と場所を飛び越える

これは #インフラ勉強会 Advent Calendar 2018 の12月2日のエントリーです。

インフラ勉強会とは、有志が立ち上げ、運営している 日本最大級のオンライン勉強会&コミュニティ です。 そこで得られたこと、繋がり、可能性、感謝と僕なりの思いなどを書き綴ってみたいと思います。

インフラ勉強会はいいぞ。

はじめに

いろんなところで言っているのですけれど、僕は知識と経験が結びつかないままバラバラに進んできてしまってるところあるんですよね。

有り体に言うと色々足りない。

で、アプリケーションを作ることは、全てを知ることだと考えたんですよね。 ミドルウェア、OS、メモリ、CPU、ネットワーク、DNS、etc、全てが関わってくる真ん中にいるんじゃないかなって。

では、アプリケーションの周辺を知るにはどうすればいいか。独学には限りがあるし…。 そんな時、 #インフラ勉強会 を知ったんです。

有志が立ち上げたオンライン勉強会、しかも内容がすごく濃密。初めてみたときは結構衝撃を受けました。

インフラ勉強会とは

有志が立ち上げ、運営している 日本最大級のオンライン勉強会&コミュニティ です。 特徴を箇条書きにすると以下のような感じかな?

  • Discordのチャットと音声を利用する
  • 画面共有やスライド共有を利用する
  • 実際の環境構築もコマンドをみながら話を聞ける
  • 参加者は数千人
    • セッションの聴講者は多い時だと100人以上
    • Discordに登録して音声をONにするだけで参加できる

僕なりのいいと思うところ

いいなと思うところはたくさんあるんですが、パッと思いつくところを列挙してみます。

とにかく、 通常のリアル登壇とは違う良さがある と思います。 あと、とにかく登壇への敷居が低いです。

電車での移動中でも聴講できる

Discordというアプリを入れてオンラインで参加すれば、ネットワークさえあればどこでも聴講できるんですよね。しかもだいたい録画してくれているので、後から聴講も可能だったりします。

これがことさらに素晴らしい。イヤフォンで音声、画面でチャット、画面共有でスライドも見れるんです。

質問があれば Q をつけると質問botが拾って溜めておいてくれる

大抵のセッションに聴講者とのコール&レスポンスがあります。 登壇者にもわからないところがあれば、わかる人がサクッと補足してくれたりもする。しかもチャット&音声で。

初心者でもチャットの反応をみながら話を補足しつつ進めてくれるので、すごくわかりやすいんですね。

時間制限を緩くすることでセッションの持ち帰りを多くしている

1時間枠でも実際に話すのはだいたい30-40分が多く、先にも言ったようにコール&レスポンスに丁寧に時間を使っています。 なので、質疑応答、実際のデモ、余談など様々なバリエーションがあって、周辺知識も知りつつ進むことができることが多く、通常のリアルセッションと違って多角的に知識を得られます。

また、オンライン参加なのでどんな格好しててもいいし、何を飲んで食べていてもOKってところもいいですよね。

初めての登壇

インフラ勉強会を知った直後くらいに、定期的に LT大会があることを知ったんです。そこで個人的に「やってみたいなー」って呟いたんですよね、確か。 そしたら たけし さんに拾っていただいたんです。あれよと言うまにエントリーが決まり、LTの内容でもないし、テーマに即しているわけでもないのにトークさせていただくことに。

その時のNaccoさんのアナウンスがこちらでした。

スライドは作らず、esa-pagesで登壇しました。

敷居が低い

ほんと異常に低いです。むしろ「教えてくれ」という時間で何十人もの知見が集まることもあるくらいです。登壇という概念が良い意味で覆された瞬間でした。

カンファレンスなどの登壇とは違って、不特定多数の技術スタックを持つ人がカジュアルに集まれるオンラインという場ならではだなって思いますし、知見が集まって聴講者の知識が1段上がる。

そんな場が作れるのもすごいなって思います。

どんなことにも技術がある

また、輪読会や技術以外の話も多くて、例えばカレーの作り方、健康について、などなど、 どんなことにも必ず技術が存在する ってことの気づきをもらえたのは、インフラ勉強会という場所からでした。

時間と場所に縛られない

赤ちゃんを抱っこしたままトークする人もいらっしゃったりで、この後に書きますが 多様なワークスタイルの発信 にもなるんじゃないかなって思っています。

可能性の最大化に繋がっているんだな、っていつも感じます。

可能性の最大化

数多くのセッション、出かけなくとも、何かをしながらでも聴講できるんですよね。育児しながらトークもできちゃう。

育児しながらのおかーさんだってすごく苦労して時間とタイミングを合わせていると思うし、自分も少なからず育児に参加しているのでわかるところ多いのですが、とにかく 技術を持つ人すべての可能性を最大化している場所 だなって思います。

なによりインプット、アウトプットをしやすいし、自分の興味のある話題だけチョイスできるのもありがたいですし、なんと毎日何かしらのセッションがあるんですよね。本当に毎日続いてるっていうのは、僕が個人で行なっている学習と共通するところがあるんですが、それを組織単位で実行しているのがすごい。

AWSの先生など、各分野の専門家が必ずいますし、そんな人たちが集まって自発的にセッションを重ねていった結果なのはわかるんですけど、それにしてもすごいことだと思います。

働き方を変える

僕は(原則的に)フルリモートワーカーです。家族との時間も家事も育児も大事だし、移動時間は無駄なことも多いと思っています。

また、生き方と仕事が多様化している現在、働き方だけ多様化に対応できていないって思うんですよね。取り組んでいる企業も個人も数多いし、成功しているところがたくさんあるのもわかっているんですが、それ以上に 本来の目的を見失っている ケースってすごく多い。

つまり時間と人材を無駄にしていることってまだまだ多いと思うんです。

インフラ勉強会は オンラインコミュニティ ではありますが、そんな 働き方を変えるモデルケース になって行くのではないかな、と感じてもいます。

リモートでも登壇してコミュニケーションできるを学んだし、僕自身の現在のリモートワークにも活きていることたくさんあります。

しばらく離れていたけど…

DNSの話トークさせていただいたあと、しばらく離れてました。本業で色々思うところあったり、この頃から毎日の学習を続けるようになったり、環境の変化が多い時期でもありました。

まあ、いろいろあったんですよねー…。

でもそろそろ再開します!僕が見れていなかった間にも色々あったようだけれど、みんなにお世話になったのは変わらない。なら 恩を送っていく しかない。自分の持つ情報、技術を共有していく。

そんな気持ちで、2019年から色々やっていきます!

さいごに

そろそろ発足1周年、イベントの準備を進めてくださっているとのこと。

自分でもイベント主催側にいるので、その知見も含めて、雰囲気づくりにも貢献したいって思っています。

具体的には、今後カジュアルに登壇していくし、参加している人の背中を押したいし、みんなも登壇しよう!ってことも話していきたいなって思っています。

技術を持つ、これから持とうとする人、すべての可能性の最大化につながれば良いなと思っていますし、僕自身もそういう人たちの背中を押すことを人生目標に掲げています。

インフラ勉強会は時間と場所を飛び越えます。

今後は積極的に参加していこうと思います!