いづいづブログ

アジャイルコーチになりたい札幌在住SEです。アジャイル札幌スタッフ&ScrumFestSapporo実行委員。Like:パクチー/激辛/牡蠣/猫/初期仏教

Scrum Fest Osaka 2019に行ってきました

f:id:izumii-19:20190225121226j:plain:w400

2/22(金)-23(土)で開催されたScrum Fest Osaka 2019に行ってきました。
3週間前に娘が右腕骨折、そして前日の震度6弱地震と、まるで見えない何かに行くことを阻まれているかのような不幸続きで直前までほんとに行けるのかどうか危うい感じでしたが、無事行けてよかったです。

このエントリーでは特にわたしの印象に残ったことを書き留めたいと思います。

www.scrumosaka.org

基調「公」演がすごい

いきなり2日目の話で恐縮ですが、基調公演がすごかったんです。 最初にオープニングムービーが流れて、「基調講演にオープニングムービーなんて凝ってるなぁ」と思っていたところに、まさかのピアノ生演奏。*1

オープニングムービー&ピアノ生演奏から始まる基調講演ならぬ基調公演。この時点でこの後始まる基調公演に対してもう期待しかないです。

ピアノと共に及部さんハイタッチイン!
グラサンした及部さんが8.6秒バズーカーに見えるのは私だけでしょうか。そしてグラサンをしたきょんさんはYOSHIKIに見えるのは私だけでしょうか。
スピーチ前の演出だけですでにこの懲り様。ここまでの準備だけでも相当大変だったと思います。すごいです。楽しいです。

基調公演の内容は書ききれないので特に自分の印象的だったことだけをいうと、すごい人達も最初は普通の人だったということです。これは私にとってはすごく大事な発見。

私が初めて及部さんの名前を聞いた時は「モブプロのすごい人」と聞いていたし、きょんさんのことは「きょんさんすごいグッとくるプレゼンする人」と聞いていたので、会う前から「なんだかすごい人達」だと思ってたし、実物の2人は間違いなくすごい人でした。

だけどプレゼンの内容は

  • 僕たちは普通の人
  • やめたくなることや投げ出したくなることが、これまで何度もあった
  • でも、他人ではなく自分が変わろう、うまくいかない運命を自分の手で変えてやろうと思って進んできた

というやうな凡人にはグッとくる内容ばかりで1行でまとめるのは恐縮なのですが、それでも無理やり1行でまとめると、

普通の僕たちはめちゃくちゃ失敗や苦労して何度も挫折しかけたけど、その先を見たいという思いでここまで一歩一歩進んできて今がある

というお話でした。

ただ「諦めが蔓延している中でこの人達の才能の蕾を開花させたい」という気持ちで行動できることは誰にでもできることではないので、やはりこういう部分は普通の人にはないものを持ち合わせているんじゃないかと思います。 とても良い話でした。

等身大のセッションが良い

セッションは2トラックで走るのですが好きなセッションをチョイスします。みなさん等身大の内容でとても聞き応えがありました。個人的には成功例ばかりを語っていなかったというところがとても良かったと思っています。
やはり多くの現場ではうまくいくことよりもそうじゃないことで悩んでいたりするので、こういう悩みを抱えているのは1人ではないんだと思えると安心感が湧くし、基調公演のテーマだった楽しさと勇気につなげることができると思いました。

私は最近アジャイルについて人に教えたり広めたりすることが多くなってきた反面、開発から離れることが増え「今開発もしていない自分が、アジャイル開発のなにがしを人に伝えられるのだろうか」ということがずっと気になっていました。自分のアジャイル開発経験はもう過去のものになりつつあるのです。

でも同じジレンマを抱えているという人と「1つのことに力を入れると違うことができなくなるのは悪いことではないんじゃないか」という話ができてなんだか安心しました。
アジャイルコーチと呼ばれる人達はこの辺についてどう思っているのかをもっと聞けばよかったと、北海道に戻ってきてからちょっぴり後悔しています。

楽しませよう感がすごい

スタッフの皆さんのおもてなしを随所に感じました。

◆旅するAgile本箱

まず入り口には旅するAgile本箱
この本箱はいろいろ旅をするみたいなので、(パスポートの入国スタンプのように)旅した場所でスタンプを残していけると旅してる感がでて素敵かなぁと思いました。 ちなみに私がちら読みして気になったのはファシリテーショングラフィックという議論の見える化について書かれている本。こうやってちら見できるのが楽しいです。

◆Welcome Talk

2日間とも最初にWelcome Talkがあったのでよくありがちな「知らない人達が会場に集まったときに感じるやや緊張感のある空気」を今回は感じませんでした。 北海道のイベントだとどうしてもちょっと雰囲気が固くなりがち。こんな雰囲気いいなぁ。

◆Networking Party

1日目はすべてのセッション終了後にNetworking Partyがあり、豪華なお寿司とオードブルとビールが振る舞われ、知らない人どうしで気軽に話ができるようにセッティングされていました。

f:id:izumii-19:20190225183649p:plain:w180 f:id:izumii-19:20190225184329p:plain:w180 f:id:izumii-19:20190225183738p:plain:w180

お酒大事。ジュースだと知らない人にえいっと話しかける勇気がでない。ビールならできる。
私もお寿司を取ろうと思ってうろついていたところを声かけていただいて名刺交換して話していたら、「僕函館にいました!」とか「おととい札幌にいました」とか、親近感がわく話がたくさんできて一気に距離感が縮まった感じがします。
知らない人と友達になれるのはテンションがあがります。

◆懇親会

Networking Partyの他にも座ってゆっくりと交流できるように懇親会が用意されていました!
大阪名物串揚げをつまみながら。

f:id:izumii-19:20190225184105p:plain:w400

◆Coffee/Tea Break

疲れがたまる午後3時ころにCoffee/Tea Breakの時間があります。スタバのコーヒー飲み放題!

◆及部さんのお誕生日

及部さん2/22お誕生日だったということでケーキとHappyBirthdayソングの大合唱。こんなサプライズされたらめちゃくちゃ嬉しいですね。ケーキもとても美味しかった(私は誕生日じゃないけど食べた)。

弁当が超絶うまい

2日目にはお弁当が出るのですが、せっかく北海道から来たので大阪観光兼ねて食べに出られたらよかったかなぁと思っていました、最初は。
ところがこのお弁当タイムが想像以上にステキでした。豪華なお弁当4種類から好きなものを選べるようになっていて、見本が置いてあるのですがどれもこれも美味しそう!
私が選んだお弁当はこれです。

f:id:izumii-19:20190223113253j:plain:w400

もうめちゃくちゃ美味しくて食べ終わってからも「美味しいのでもう1個食べたい」と思っていました。それくらい美味しかったので大満足でした。
手前にある大根の明太子和えはサッパリしていて娘のお弁当にもいいかなぁとか、詰め方盛り方もきれいなので、毎日お弁当作る派としては眺めて良し、食べて良しの◎です。
北海道でお弁当を振る舞う時もこのくらい美味しいお店のお弁当屋さんにお願いしたいなぁ。

まとめ

正直書ききれないですが、来年もまた行きたいと思えるようなとても良いイベントでした。 久しぶりに会った人達に覚えていてもらえたこと、新しい人達と知り合いになれたことがとても良かったです。 札幌でもこんな盛り上がるイベントにしたいなぁと思いました!

f:id:izumii-19:20190225182357p:plain:w400

*1:これがメチャクチャ上手い。自分もピアノ10年やってたのですがあれだけ長時間演奏しながら最後までクオリティ保つのってかなり集中力いると思うんです。

Gitをコマンドから操作する #3 サルわかプルリク編

Gitについて学んだことの自分用メモ。主にGitをコマンドから実行する方法について学んだ。 参考サイトはここのプルリク編
自分向けのメモなのでまとめかたは雑。そのうちきれいに。

プルリクエス

簡単に言うと、開発者のローカルリポジトリでの変更を他の開発者に通知する機能のことで、機能追加やバグ修正を他の係者に通知したり、ソースコードのどこを修正したのかをわかりやすく表示する機能。

ソースコードに関するコミュニケーションの場を提供する。

プルリクエストは、Git自身の機能ではなくGitHubが最初に提供した機能。今では、ほとんどの主要なGitホスティングサービス(GitHub、BitBucket等)やツールで利用できる。

プルリクエストの手順

Githubでもプルリクエスト手順は以下の通り。

プルリクエストを送る人の作業

1)(準備)トピックブランチを作成し任意の変更を行う。ここでは「add-sort-func」というトピックブランチを作成しsort.jsファイルに対してコードの変更を行い、リモートリポジトリにプッシュしておく。

2)対象のリポジトリの「Compare & pull request」をクリック。

f:id:izumii-19:20190105092250p:plain:w400

3)「base」のブランチはプルリクエストをマージする対象のブランチ(=マージ先)。
「compare」はプルリクエストブランチ(=マージ元)。

f:id:izumii-19:20190105093133p:plain:w400

プルリクエストのタイトルとコメントを記入して「Create pull request」ボタンをクリックするとプルリクエストが作成される。

f:id:izumii-19:20190105094117p:plain:w400

プルリクエストを受け取った人の作業

1)「Files changed」タブから変更内容を確認する。レビューして指摘があればここでソースコードに直接コメントを入れる。

f:id:izumii-19:20190105094518p:plain:w400

2)問題なければマージを行う。

f:id:izumii-19:20190105094850p:plain:w400

3)プルリクエストが成功した通知が表示される。プルリクエスト用のブランチが必要なければ「Delete branch」ボタンをクリックしてブランチを削除する。

f:id:izumii-19:20190105095040p:plain:w400

枝の状態を確認したいとき

リポジトリの「Insights」-「Network」から確認できる。 f:id:izumii-19:20190105095623p:plain:w400

Gitをコマンドから操作する #2 サルわか発展編

Gitについて学んだことの自分用メモ。主にGitをコマンドから実行する方法について学んだ。 参考サイトはここの発展編
自分向けのメモなのでまとめかたは雑。そのうちきれいに。

ブランチ

統合ブランチとトピックブランチという二種類のブランチを使った運用方法について。

統合ブランチ

統合ブランチとは、リリース可能な状態を常に維持しておくブランチで木の幹のようなイメージ。通常はmasterブランチを統合ブランチとして使用し、Jenkins等のCIツールを使用した自動ビルドやテストもこのブランチを使って行う。

バグ修正など何か変更を行う際は、この統合ブランチを分岐元としてトピックブランチを作成する際は作成してから対応を行う (直接統合ブランチを変更してしまうと「リリース可能な状態を常に維持しておく」というルールから逸脱してしまうため)。

トピックブランチ

トピックブランチとは、機能追加やバグ修正といったある課題に関する作業を行うために作成するブランチ。木の枝のようなイメージ。複数の課題に関する作業を同時に行う時は、その数だけトピックブランチを作成する。

HEAD

HEADとは現在使用しているブランチの先頭を表す(デフォルトではmasterの先頭を指している)。HEADが移動することで使用するブランチが変更される。

ブランチの統合

ブランチの統合には、mergeを使う方法とrebaseを使う方法がある。

けど、文字よりも図を見たほうが圧倒的に理解しやすいのでここを見るとよい。

merge

mergeを使用すると、複数の履歴の流れを合流させることができる。 mergeにはfast-forward(早送り)マージをする方法としない方法がある。

fast-forwardマージ

masterブランチとそこから分岐したブランチBがあるとした場合、 Bがmasterでの変更をすべて含むときに行われるマージをfast-forwardマージという。*1

つまりブランチBの分岐後に、元ブランチ(masterブランチ)において変更がないときに行われるマージのことである。

この場合元ブランチをブランチBの先頭へ移動すれば良いだけなので非常に簡単に統合することができるが、ブランチBで変更が別ブランチとして残らないので履歴の追跡がしにくくなる。

non fast-forwardマージ

masterブランチとそこから分岐したブランチBがあるとした場合、 masterブランチとブランチBそれぞれに変更が入っていてfast-forwardマージができない場合はnon fast-forwardマージを行うことになる。 non fast-forwardを行うと、新しくマージコミットを作成して合流させる。

non fast-forwardマージはオプションで選択できるので、fast-forwardマージが可能な場合でもあえてnon fast-forwardマージを行うということもできる。 non fast-forwardマージのメリットはブランチがそのまま残るので、そのブランチで行った作業の特定が容易になるところ。

rebase

masterブランチとそこから分岐したブランチBがあるとした場合で、ブランチBをmasterブランチにrebaseすると、ブランチBの履歴がmasterブランチの後ろに付け替えられる。そのため履歴は一本化される

この時ブランチBとmasterブランチで競合が発生する可能性があるため、競合はそれぞれ修正する必要がある。

また、rebaseしただけだとmasterの先頭の位置はそのままなので、masterブランチからブランチBをマージして、ブランチBの先頭まで移動する必要がある。

ブランチ作成

git branch コマンドにブランチ名を指定するとブランチを作成できる。以下の例では"issue1"というブランチを作成。
ブランチ名を指定しない場合はブランチの一覧が表示される。

$ git branch issue1
$ git branch
  issue1
* master

ブランチ切り替え

ブランチを切り替えるにはcheckoutコマンドでチェックアウトする。

$ git checkout issue1
Switched to branch 'issue1'

ブランチのマージ

ここではissue1ブランチをmasterにマージする。マージするにはmergeコマンドを使う。
mergeコマンドで指定したブランチが、HEADの指しているブランチに取り込まれるので最初にmaster(マージ先になるブランチ)をチェックアウトし、その後mergeコマンドで"issue1"ブランチを指定して実行する。

$ git checkout master
Switched to branch 'master'
Your branch is up to date with 'origin/master'.

masterブランチにいることを確認。

$ git branch
  issue1
* master

mergeを実行。

$ git merge issue1
Updating fcc386a..161ad06
Fast-forward
 myfile.txt | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 myfile.txt

ブランチ削除

brauchコマンドに-dオプションを付けて実行。

$ git branch -d <branchname>

リモートリポジトリにあるブランチを削除するにはpushコマンドに--deleteをつける。

$ git push --delete origin issue1
To https://github.com/izumii19/gitTutorial.git
 - [deleted]         issue1

*1:デフォルトの設定はfast-forwardマージになっている。

Gitをコマンドから操作する #1 サルわか入門編

Gitについて学んだことのメモ。主にGitをコマンドから実行する方法について学んだ。 参考サイトはここの入門編
自分向けのメモなのでまとめかたは雑。そのうちきれいに。

Git

「Git」は、ソースコードのバージョンを管理するツールのことで正確には「分散バージョン管理システム」のこと。Git以外にもCVSSubversionがあるが近年広く受け入れられているのがGit。

GitとGithubの違い

Gitはソースコードのバージョンを管理する「ツール」のことで、Githubは、Gitを利用した開発者を支援する「Webサービス」。

インストールと初期設定

  • インストールはここから
  • .gitconfigファイルにユーザー名とメールアドレスを設定
$ git config --global user.name "<ユーザ名>"
$ git config --global user.email "<メールアドレス>"

使い方

ローカルリポジトリ作成

Gitの管理下にしたいディレクトリ(この場合はtutorial)に移動してinitコマンドを実行する。

$ cd tutorial/
$ git init
Initialized empty Git repository in /Users/izumi/tutorial/.git/

バージョン管理の状態を確認する

※(準備)tutorialディレクトリに簡単なコメントを書いたsample.txtを置いておく。

バージョン管理の状態を確認するにはgit statusコマンドを実行する。

ステージング

git statusコマンドで状態を確認すると追跡対象外のファイル(Untracked files)があるのでIndexに登録する。これを「ステージングする」という。

f:id:izumii-19:20181228130245p:plain:w400

ステージングするにはaddコマンドを実行する。*1

$ git add <file>

git statusコマンドでもういちど状態を確認する

f:id:izumii-19:20181230152416p:plain:w400

“Changes to be committed” 欄に表示されている、つまりステージされているということがわかる。

コミット

git commitコマンドを実行する。mオプションを付けると1行のコミットメッセージを付けることができる。

実際の運用ではコミットコメントをつけずにコミットすることはないのでmオプションは必須のつもりで覚えておくとよい。

$ git commit -m "first commit"
[master (root-commit) b5803da] first commit
 1 file changed, 1 insertion(+)
 create mode 100644 sample.txt

リポジトリの変更履歴を確認する

git logコマンドを実行する。

$ git log
commit b5803daf1349ff3c6a531cc2a9710d561d58526a (HEAD -> master)
Author: izumi <メールアドレス@gmail.com>
Date:   Sun Dec 30 15:31:56 2018 +0900

    first commit

リモートリポジトリ作成

リモートリポジトリを追加するにはremote addコマンドを実行する。

$ git remote add <name> <url>

<url>にはリモートリポジトリのURLを指定し、<name>にはリモートリポジトリの別名(短い名前)を指定する。

これはリモートリポジトリにアクセスする際、長いURLをいちいち打たなくても良いようにするためで"origin"を指定するのが一般的である。*2

f:id:izumii-19:20181230170413p:plain:w400

プッシュ

リポジトリをプッシュするには、pushコマンドを実行する。

$ git push -u <repository> <refspec>...

<repository>にはプッシュ先のアドレスを指定する(先程リモートリポジトリに"origin"という名前をつけたはずなのでそれを指定)、<refspec>はプッシュするブランチを指定する。

以下、実行結果。

$ git push -u origin master
Enumerating objects: 10, done.
Counting objects: 100% (10/10), done.
Delta compression using up to 4 threads
Compressing objects: 100% (5/5), done.
Writing objects: 100% (10/10), 862 bytes | 862.00 KiB/s, done.
Total 10 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), done.
To https://github.com/izumii19/gitTutorial.git
 * [new branch]      master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.

f:id:izumii-19:20181230170711p:plain:w400

リポジトリのクローン

$ git clone <repository> <directory>

<repository>はクローンするリポジトリ名、<directory>はクローンする先になるディレクトリ名を指定する。 ためしに「tutorial2」という名前のディレクトリ名でリモートリポジトリをクローンする。

$ git clone https://github.com/izumii19/gitTutorial.git tutorial2
Cloning into 'tutorial2'...
remote: Enumerating objects: 10, done.
remote: Counting objects: 100% (10/10), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 10 (delta 1), reused 10 (delta 1), pack-reused 0
Unpacking objects: 100% (10/10), done.

コミットコメントのコツ

  • バグ修正や機能追加などの異なる意味を持つ変更はできるだけ分けてコミットする。 (後から履歴を見て特定の変更内容を探しやすくするため。)
  • コミットコメントの標準の書き方

1行目 : コミットでの変更内容の要約

2行目 : 空行

3行目以降 : 変更した理由

*1:パラメータに「.」を指定すると、すべてのファイルをインデックスに登録することができる。

*2:Gitはプッシュやプルの実行時にリモートリポジトリ名を省略すると、originという名前のリモートリポジトリを使用するため、リモートリポジトリにはoriginという名前を付けるのが一般的。

Cookie

HTTPと関連が深いCookieについて学習した。

Cookieとは

Cookieの正式名称は「HTTP Cookie」である。 HTTPというのはステートレスなプロトコルであるため状態を管理することができない*1。これはHTTPが「単にファイル転送を行うために開発されたため、同じURLへのアクセスならその状況によらず同一の資源を提供する」という考えに基づくものである。

一方で、World Wide Webが普及につれ状況によって異なる内容のページを提供したいというニーズが生まれてきた(例えば「ショッピングサイトにログインしてカートに商品を登録していく」のような使われ方)。 しかしHTTPだけでは状態を管理することができないため、それを実現する仕組みとして1994年にネットスケープコミュニケーションズ社によって提案・実装されたのがHTTP Cookieである(以下全て「Cookie」と記述)。

CookieはHTTP/1.0以降から使用することができる。*2

Cookieによる状態管理

Cookieでは次のようにサーバとクライアント間の状態を管理し、サーバとクライアント間の通信において1回目と2回目で処理が異なる。

1回目

  1. ブラウザ(クライアント)がWebサーバーにリクエストを送信すると、Webサーバーはブラウザに対してレスポンスを返す。 この時、Webサーバーはレスポンスヘッダーに「Set-Cookie:」から始まる情報を付加して返却する。「Set-Cookie:」は「Cookieを保存してください」というサーバーからの指示である。

  2. ブラウザはサーバーからの指示に従い、送られてきたCookieの情報を指定された期間だけパソコンに保存する。この時、ブラウザ側は送られてきたCookieの情報の中身を理解する必要はなく、ただの文字の羅列としてしか認識しなくてよい。

2回目以降

  1. ブラウザ側では、同じWebサーバーに対してリクエストを送信するのが2回め以降の場合、保存しておいたCookieの情報をリクエストヘッダーに自動的に付加して送信する。 ブラウザ側は、Cookieが保存されていれば常に「このようなCookieがあります」とサーバーにリクエストを送る仕組みになっている。この時もブラウザ側はただの文字の羅列としてしか認識していなくて良い。

  2. Webサーバー側は、ブラウザから送信されたCookie情報を処理(=Cookie情報を分解して解釈し、HTMLに情報を混ぜ込んで返す)を行う。

つまり「HTML/1.0以降でCookieが使用可能になった」というのは「Cookieの情報を送受信する仕組みができた」ということであり、実際にはWebサーバーがCookie情報を解釈して適宜処理を行う必要がある。

Cookieの種類

HTTP Cookiesには Persistent Cookie(パーシステントクッキー)と呼ばれるものと Session Cookie(セッションクッキー)と呼ばれるものの2種類ある。

Session Cookie

Session Cookieはサイトの閲覧中にのみ一時的に保存され、ブラウザを閉じるとユーザーのデバイスから削除される一過性のCookie

Persistent Cookie

Persistent Cookieはユーザーのコンピューターに保存されブラウザを閉じても削除されない。 Persistent Cookieはブラウザの削除オプションを使用して削除することができる。

Cookieの注意点

Cookieの利用はアクセスした瞬間に必要な情報が表示されるという点で便利ではあるが、使い方を注意しないと第三者に情報を盗まれる危険性がある。 多くのユーザーの目に触れるような環境では、必要がなくなったタイミングでCookieの情報を削除する、自分の信頼するWebサイトにだけCookieを使用するようにするなどの注意が必要である。

セッション

セッションとは、一連の処理の始まりから終わりまでのこと。 例えばネットショッピングの場合、ログイン⇒商品をカートに入れる⇒購入のような同一利用者からの一連のアクセスを1つのセッションとして扱う。

Cookieを使ったセッション管理

上記のように同一利用者からのアクセスを関連性のある一連のアクセスとして扱いたい場合、Cookieを使ってセッション管理を行う。

具体的には、Cookieに一意の値を入れリクエストするときにこの値をCookie入れて送ってもらうことで識別する。以下に例をあげる。

  1. ブラウザはWebサイトにログインし、ユーザIDとパスワードをWebサーバに送信する。
  2. サーバはユーザIDとパスワードから「セッションID」を生成し、「Set-Cookie:」に追加してブラウザへ送信する(例:Set-Cookie: PHPSESSID=028a9x...)。この時なりすましを防ぐためセッションIDは特定しにくい値にする必要がある。
  3. 以降ブラウザがWebサーバにリクエストを送る際、セッションIDを含んだCookie情報を送信することでセッションの維持ができるようになる。

結局のところ「セッションを維持する間は、識別可能な一意の値をやりとりする」ということをCookieを使って行っているということなので、例えばCookieを使わずにリンクのURLに値を記述してリクエストしてもらったり、フォームに値を記述してリクエストしてもらうという方法をとることも可能といえば可能。

ただし、Cookieを使う方法と比べて情報が漏洩する可能性が高いため、Cookieを使ってセッション管理するのが一般的である。

*1:ブラウザがサーバに立て続けに2回リクエストを送ったとして、 サーバには、1回目のリクエストと2回目のリクエストはまったく独立したものとして扱う。

*2:HTTP/0.9ではメソッドはGETしか存在せず、それに対するレスポンスもただHTMLを返すだけという非常に単純な作りだった。HTTP/1.0では、メソッドはGETのほかにPOSTなども使用できるようになり、レスポンスもレスポンスヘッダーやレスポンスステータスを返せるようになった。Cookieの情報はレスポンスヘッダーに含まれる。

HTTPの基本1 #2 telnetでGETとPOSTを試してみる

はじめてのアドベントカレンダー Advent Calendar 2018 - Adventarの12/24の記事です。 読み物でもないし完全に自分がやったことのメモでしかないんですが、初めてtelnetでHTTPメソッドを実行する、ということをやった結果ほぼ1日を費やす羽目になるくらいはまってしまい、せっかくなのでブログにしました。

mactelnetをインストールする

とりあえずtelnetコマンドを実行してみる。

$ telnet
-bash: telnet: command not found

ないって。telnetを使うには入れないとだめらしい。

ということでtelnetをインストールするんだけど、先にHomebrewを更新して最新にしておく。
何かをインストールする前にはおまじないのようにこの2つのコマンドをセットで実行しておくのがいいと思う。

$ brew update
$ brew upgrade

でインストール実行

$ brew install telnet

telnetを実行する。OK。

$ telnet
telnet> 

GETリクエストを送信

接続先はGET/POST練習用に用意されたサイトを使用した。

telnetでWebサーバーに接続】

telnethttps通信はできずhttp通信になるため、ポート番号は80番を使用する。 (TCP/80 : HTTP、TCP/443 : HTTPS

$ telnet dummy-bootcamp-fjord-jp.herokuapp.com 80
Trying XX.XX.XX.XX...
Connected to XXXXXXX.route.herokuapp.com.
Escape character is '^]'.

telnetの後に接続するホスト名かIPアドレスを指定し、ポート番号の「80」を記述する。 Escape character is '^]'.が出てきたら入力待ち状態になっているのでOK。
telnet」の後ろに「http://dummy-bootcamp-fjord-jp.herokuapp.com」と書くのは間違い。指定するのはホストかIPアドレスなので余計なことを書いちゃだめなのに、なにも考えずURLコピペしていたのでまずここで1ハマり。

【リクエストラインを記述】

GETリクエストを送信する。

GET /articles/1 HTTP/1.1

GETメソッドの後にパスを指定する。トップページにアクセスする場合は「/」だけでOKだけど今回は「articles/1.html」のページに対してGETリクエストを送る。最後にHTTPバージョンを記載(今回は2.0で通信できないため1.1で実行)

【リクエストヘッダを記述】

Host: dummy-bootcamp-fjord-jp.herokuapp.com

HTTP/1.1要求メッセージ送信用のメソッドで唯一必須。ホスト名を指定する(telnetで接続する時に書いたホスト名と同じ。)
まさか必須だと思わなくて、GETだけを一生懸命送信していてエラーになりまくりだった。HTTP/1.1で要求メッセージを投げるときは必ず必要!!ここで2ハマり。

そして3ハマり目が最後にEnterを2回押さないとだめだということ(1回目で空行入力、2回目で実行)。 1回だけしかEnterを押していなかったのでずーーーっと次入力待ち状態だったらしいんだけど、そんなの知らないからこっちもずーーーとまってた。

f:id:izumii-19:20181223001414p:plain:w400

【実行結果】

f:id:izumii-19:20181223001750p:plain:w400

レスポンスのステータスが200なので成功している。

POSTリクエストを送信

【リクエストラインを記述】

POSTリクエストを送信する。

POST /articles HTTP/1.1

POSTメソッドの後にパスを指定する。今回は要求を送って新しくページを1つ作るのでパスの指定は「/articles」までにする。後はGETのときと同じ。*1

【リクエストヘッダを記述】

Host: dummy-bootcamp-fjord-jp.herokuapp.com
Content-Length:48

Hostの指定はGETと同じ。
「Content-Length」はこの後のメッセージボディで記述するクエリの文字の長さを指定する(1byte文字テキストの長さ)。詳しくはこの後のメッセージボディに記述する。

【メッセージボディを記述】

今回は以下のように「Title」に"izumi"、「Body」に"body Comment"と表示されるようにしたい。

f:id:izumii-19:20181223003700p:plain:w400

なのでクエリは以下のように記述する。

(1行空けること)
article[title]=izumi&article[body]=body Comment

アイテム名は既に誰かによって作成済みのサンプルページがあったので、そのページのHTMLコードを表示してTitleに表示しているアイテムは「article[title]」、Bodyに表示しているアイテムは「article[body]」であることを確認した。けどこのアイテム名を探す方法をなかなか思いつくことができなかったせいで4ハマり。

f:id:izumii-19:20181223004029p:plain:w400

そしてこのarticle[title]=izumi&article[body]=body Commentの文字列が1バイト文字48個なのでリクエストヘッダには「Content-Length:48」と書く必要がある。
ここがわからなくて5ハマり…。

最後にEnterを押して実行する。

【実行結果】

f:id:izumii-19:20181223005150p:plain:w400

f:id:izumii-19:20181223005746p:plain:w400

レスポンスのステータスが「302 Found」になっている。どういう意味だろう。 一応思ったとおりのものはできているようだけど、ちゃんと理解できてない気がするなぁ。

*1:正直ちゃんとこの辺理解してない。

HTTPの基本1 #1 HTTPとは

はじめてのアドベントカレンダー Advent Calendar 2018 - Adventarの12/23の記事です。 読み物でもないし完全に自分がやったことのメモでしかないんですが、初めてtelnetでHTTPメソッドを実行する、ということをやった結果ほぼ1日を費やす羽目になるくらいはまってしまい、せっかくなのでブログにしました。

しかし何も知らないとちょっと勉強しただけで色んなことが吸収できるので収穫が大きいんだけど、ハマるとハマる。ほんとにハマる。

HTTPとは

HTTPは「HyperText Transfer Protocol」の略で、Webサーバとブラウザ(=クライアント)間でウェブページを送受信するためのステートレスなプロトコル

実際は、以下のようなテキストメッセージのやりとりで成り立っている。

・クライアントはサーバーに対し、要求メッセージを送る

・サーバーはクライアントからきた要求に対し、応答メッセージを送る

ちなみにメッセージに必要なメソッド名やステータス番号は以下のサイトが参考になった。

HTTP入門

ステートレスとは

ステートレスは読んで字のごとく(state+less)で「状態を持たないということ」。 例えば、ブラウザがサーバに立て続けに2回リクエストを送ったとして、 サーバには1回目のリクエストと2回目のリクエストはまったく独立したものとして届き、前はどうだったかという状態は保持することができない。
HTTPがステートレスなプロトコルであるということがCookieに深く関わっているのだが、Cookieについては後ほど勉強して記載するため今はふれない。

要求メッセージ

クライアントがサーバーに対して送るメッセージ。

例えばブラウザで Webページを開きたい場合、ブラウザはサーバに以下のような要求メッセージを送信する。

GET / HTTP/1.1
Accept: image/gif, image/jpeg, */*
Accept-Language: ja
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (Compatible; MSIE 6.0; Windows NT 5.1;)
Host: www.xxx.zzz
Connection: Keep-Alive

解説

要求メッセージは以下のような構成をもつ。

  • リクエストライン
  • リクエストヘッダー
  • メッセージボディ(POSTメソッドなどで使用)

【リクエストライン】

GET / HTTP/1.1

HTTPメソッド、パス名、「HTTP/バージョン」の順番に書く。「GET」メソッドを例にあげているがよく使うのは「GET」と「POST」である。2つの違いについてはここがわかりやすかった。
パス名は通常/aaa.html のようなスラッシュで始まるパス名や、http:// などで始まる URL が指定される。バージョンは現在は1.1または2.0が主流*1

Chrome拡張機能を使うとHTTP/2.0で通信を行っているかどうか簡単に調べられる。*2

f:id:izumii-19:20181222093949p:plain:w300

青になったらHTTP/2.0で通信しているということ。

【リクエストヘッダー】

Host: www.xxx.zzz
Accept: image/gif, image/jpeg, */*   
Accept-Language: ja
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (Compatible; MSIE 6.0; Windows NT 5.1;)
Connection: Keep-Alive

要求ヘッダであるHostはHTTP/1.1で唯一の必須ヘッダなのでこれは必ず書かなければならない。

あとのヘッダは必要に応じて書く。 1行1行が要求メッセージなので、この例だと6つの要求をサーバーに投げていることになる。

書き方はメソッドにより異なるが「Accept」の例だとメソッド名、ブラウザが受信可能なデータ形式MIMEタイプ)の順番に書く。アスタリスクは「すべて」を意味するので、この場合だと「GIF や JPEG、その他どんな形式のデータでも受信可能である」という意味になる。*3

【メッセージボディ】

使用するHTTPメソッドによって使用する場合としない場合がある。
GETメソッドでは使用しないが、POSTメソッドではサーバー側に送信するデータ(クエリ)をメッセージボディに記述する。

リクエストヘッダとメッセージボディの間には1行空行が必要なので忘れないこと。 この空行がないと、リクエストヘッダとメッセージボディの境界がどこなのかが認識できず、リクエストを送信してもうまくいかない原因になる。

応答メッセージ

サーバーがクライアントに対して送るメッセージ。

例えばブラウザ側から「 Webページを開きたい」という要求(前述した例)があった場合、サーバは以下のような応答メッセージを送信する。

HTTP/1.1 200 OK
Date: Sun, 11 Jan 2004 16:06:23 GMT
Server: Apache/1.3.22 (Unix) (Red-Hat/Linux)
Last-Modified: Sun, 07 Dec 2003 12:34:18 GMT
ETag: "1dba6-131b-3fd31e4a"
Accept-Ranges: bytes
Content-Length: 4891
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: text/html

<!DOCTYPE html>
<html>
  :
</html>

解説

応答メッセージは以下のような構成をもつ。

  • レスポンスライン
  • レスポンスヘッダー
  • メッセージボディ

【レスポンスライン】

HTTP/1.1 200 OK

HTTP/バージョン、ステータス番号、補足メッセージの順番に記述される。 補足メッセージにはOKやNot Found などステータス番号の意味や補足メッセージが返される。

【レスポンスヘッダー】

Date: Sun, 11 Jan 2004 16:06:23 GMT
Server: Apache/1.3.22 (Unix) (Red-Hat/Linux)
Last-Modified: Sun, 07 Dec 2003 12:34:18 GMT
ETag: "1dba6-131b-3fd31e4a"
Accept-Ranges: bytes
Content-Length: 4891
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: text/html

1行1行が応答メッセージなので、この場合だと9つの応答が返ってきている。

【メッセージボディ】

レスポンスヘッダとメッセージボディの間に1行空行があり、その後続けて要求されたファイルの中身が表示される。

*1:HTTPバージョンが違うとなにが違うのかはここを見るとよい。HTTP/1.0, HTTP/1.1, HTTP/2の違いとは?【ネットワーク】 | 学生エンジニアのプログラミング

*2:「HTTP/2通信されているか?」をブラウザで手軽に判別する方法

*3:じゃあ「/」だけ書けば?って思うかもしれないですが、書き方の学習のために今こうしているというだけ。