マイ備忘録

あくまで個人の意見、メモです。

スクラムを始めてみての感想

転職して1ヶ月半ぐらい経ちました。 技術的にもチーム運営的にも新しいチャレンジをさせてもらっているので、頑張って結果を出して行きたいと思います。

さて、この1ヶ月半人生初のスクラムマスターをやっています。もともと「2週間のタイムボックスで開発をやってる」ぐらいの状況だったので、メンバーが増えてきたこのタイミングで少しスクラムっぽくやろうということになったので。比較的きちんとしたスクラムは自分も初めてやるので、やってみての感想や気づきをメモしておきます。

スクラムを始める前にやったこと

業務委託でサポートしてくれている方でスクラムの経験がある方にいろいろアドバイス頂き、以下のことをやりました。

スクラムでやることや簡単なルールを決める

  • バックログは今も使用しているZenHubを継続して使う
  • スプリントの期間
    • タイムボックは今まで通り2週間
    • 最初の月曜にプランニング、最後の金曜日にレトロスペクティブを行うということにした
    • レトロスペクティブからプランニングまでに時間があるが、その期間は次のスプリントに含めることに(レトロスペクティブとプランニングを同じ日にやるのはきついかなと...)
  • どのスクラムイベントをいつやるか
    • プランニング
    • デイリー
    • レトロスペクティブ
    • レビュー
      • 現段階ではやらないことに
  • スクラムイベントではどんなことをやるか(後述)
  • 1ポイントの基準
    • 今まで消化したタスクの中で、数行程度の修正だったものを"1"ということにして、チーム全体のコンセンサスを取った

そもそものスクラム開発の説明

  • 自分のスクラムに対する認識を整理するためにも簡単なドキュメントを作って、メンバーに共有しました github.com

所感

  • レトロスペクティブから次のプランニングまでの間は半日〜1日分ぐらいの稼働時間がある。アサインされているタスクが終わった人は、この期間のやることが無くなってしまう。まあ勉強とかすればいいのだが、この辺りは今後変えていくことになるかも。
  • レビューはそれぞれのissueのリリース前確認時にやってるから一旦なしになったが、UI/UX等の改善を考えると、全員でシステムを確認するレビューの時間をとってもよいかもしれない
  • ZenHubめっちゃ便利
  • スクラムの説明資料にアジャイルソフトウェア開発宣言のことも書いたけど、意外と知らない人が多く、説明してよかったと思った

スクラムを始めてみて

スプリントの途中から始めたので、デイリーの改善からやりました。

デイリーでやっていること

  • バックログの更新共有
    • Issueのパイプライン(New, ToDo, InProgress, Test, Review, Done, Closeを用意している)更新は個人で行うようにしているので、それの共有。昨日やったこと、今日やることの代わり。
  • 新規Issueの確認
    • 新しいIssueが登録されていれば全員でその内容を確認し、見積もりを行う
    • 優先度の高い場合もあるので、必要であればスプリント計画の見直しを行う
  • その他共有、相談等

所感

  • 開発チーム以外も含めてデイリーをやっていたけど、開発チームだけの時間を設けることでコミュニケーションは増えた。スコープを小さくすることは大事。
  • みんなバックログの更新をやってくれて嬉しかった。前職は全部一人でやってたし。
  • 見積もりはまだまだ課題がある。最終的なポイントの決定ロジックは明確なルールがなく、自分のさじ加減(平均を採用したり、上を採用したり、などなど)
  • その他共有はまだ業務連絡みたいなものが多いけど、技術的なトピックスとかをみんなが話すような雰囲気になっていけばいいなと思う

プランニングでやっていること

途中だったスプリントが終わって(レトロスペクティブも次のスプリントからということにしていた)、初めてのプランニングになりました。 ざっくり以下のアジェンダで進めることにしています。

0. 前回のスプリントで消化しなかったIssueを今回のスプリント(マイルストーン)に移しておく
1. プロダクト状況共有
2. new issueの見積もり
3. 今回のスプリントでやるIssueを決めて、マイルストーンを設定していく
4. マイルストーンに登録された未アサインタスクに関してアサインを決める
5. 微調整(多い少ない等、自己申告してもらう)

0. 前回のスプリントで消化しなかったIssueを今回のスプリント(マイルストーン)に移しておく

これは事前準備として、プランニングの前にやっていること。ZenHub上の作業です。 結構消化できてないIssueが残ってたりするんですよね。

1. プロダクト状況の共有

プロダクトオーナー的な立場の人も参加してくれているので、ビジネスの話は必ず共有してもらいたい。のでこの時間を取ってます。 ビジネス側でウォッチしているKPIや、検討中のビジネス展開などを共有してくれるので、非常に有意義だと思ってます。 たった2週間でも、結構状況は変わるんですね。

2. new issueの見積もり

デイリーでNewIssueはチェックしてるとはいえ、プランニングの前に新しいものが出てくるもの。なのでそれのポイントを出します。 初回はIssueの整理をしておらず、見積もりがされていない昔から残っていたIssueが大量にあったので、それの見積もりだけでプランニングの時間が終わってしまった。 2回目移行はプロダクトオーナーがIssueの整理をやってくれて、デイリーでのNewIssueチェックもワークしてきたのでこの問題な無くなったけど、大変だった。。

3. 今回のスプリントでやるIssueを決めて、マイルストーンを設定していく

大体80〜90ポイントぐらいを基準にしてますが、現状もっと増えてしまっている。 すぐにリリースできないようなタスクが多くて、Reviewなり、リリース待ちの状態で残っててそれがそのまま持ち越されてしまう、ってところが原因なのかなと。。 改善の余地あり。

4. マイルストーンに登録された未アサインタスクに関してアサインを決める

仕掛り中のもの以外は基本的にはアサインがないため、アサインしていく

5. 微調整(多い少ない等、自己申告してもらう)

アサインした結果、偏りがある場合微調整を行う。 個人が何ポイント持っているか、までは個人攻撃になる恐れがあるので、極力自己申告してもらうようにする。(個人単位では見ないほうがよいとアドバイス頂きました。確かに。)

所感

  • ものすごく課題に感じているのが、事前準備で消化しなかったIssueをそのまま次に移していること。Issueの設定がわかったのかもしれないけど、依存関係とかがすごく多くてまとめでじゃないとリリースできないものが結構おおい。全部着手しているので、それをまとめてマイルストーンを変更すると、すごいポイントがすでにやることとして加算されてしまう(実際は8割ぐらい完成していたりするのに)。何とかしたいけど、どうするのが正解なのだろうか。こういった状況にならないように適切なIssueに分割なりするのがプランニングなんだろうけど...
  • タスクアサイン時のルールと言うか意識というか、現状は個人の成長を意識したアサインにはなっていない。できそうな人をアサインしている状況なので、当然アサインされるタスクの量に偏りが出るだろうし、モチベーションにも影響するかもしれない(いつも簡単なタスクばかり回される...みたいな意見がでそう)。ここも改善ポイントだなと。

レトロスペクティブでやっていること

振り返りのやり方はいろいろあるけど、日本でよく使われているKPTをベースとすることに。 ざっくり以下のアジェンダで進めることにしています。

1. 今回のレトロスペクティブの目標共有
2. 振り返るためのデータを集め
    - Keep出し
    - ZenHub上のデータ共有
    - Problem出し
3. 改善のためのアイディア出し
    - ZenHubのデータも参考にし、Keep/ProblemからTryを出す
4. 出たアイディアから何をやるか決める
5. レトロスペクティブの振り返り

進めることにしているといっても、まだ1回しかやってませんが...。 コロナの影響で在宅勤務になったため、今はペンディングしている状況。ただ、流石に振り返りがないのは良くないとチーム内からも意見がでてきたので(いや、嬉しい限りです)、今のスプリントではやります。

1. 今回のレトロスペクティブの目標共有

振り返る上で何も思いつかない人もいるので、今回のスプリント内でのトピックスについての振り返りを考えてみませんか?というアナウンスをする。 もちろんトピックス以外でも全然OK。初回のときは以下のような例を上げた。

- 1スプリントで消化できるポイントの目安
- ポイント消化を向上させることができるような取り組み
- ZenHubの運用方法

2. 振り返るためのデータを集める

ポジティブなことを最初に行ってもらうために、Keepから考えてもらうようにしている。 そしてZenHub上での計測値と合わせて、Problemを出す。

3. 改善のためのアイディア出し

Keep/Problemに対するTry出し。ZenHubのデータを踏まえてTryを出せるようになればいいのだが、まだ難しそう。

4. 出たアイディアから何をやるか決める

改善策として上がったTryのうち、何をやるかきめる。 Issueとして取り組まなければならなそうなものは、1〜2個ぐらいに絞って次回のスプリントで出来るようプロダクトオーナーと交渉する。 それ以外のものはチームのルール的なものに入れる(増えすぎるとよくないけど...)。

5. レトロスペクティブの振り返り

今回のレトロスペクティブの総評と、フィードバックをもらうようにしてます。

所感

  • アジェンダには書いてないけど、なぜ振り返りをやるのかの共有は最初にやったほうがよい。腑に落ちない人もいるかもしれないし。
  • 1人1人に発言してもらうので、時間がすぐにオーバーする。なのでタイムキープが凄く大切。
  • 改善案はいいことしかないから、その中からどれを選ぶかきちんと決めること
  • 次からリモートになるから、うまくやれるかな。

全体を通しての感想

  • 全てにおいて、事前準備は大切です。アジェンダは事前に作って印刷し、それを見ながらファシリテートしてました。これがなかったら辛かった。
  • 目下の課題はプランニングの改善
    • 80〜90ポイントぐらいのタスク量でスプリント開始したい。
    • 個人の成長も考えた上でのアサインもやっていきたい。そのためにはメンバーそれぞれが何をやりたいのかを把握しないといけないけど。
  • スクラムとかファシリテートとかの本は流し読みしかしてないので、自分自身ももっとうまく回せるように努力しなければ

といった感じです。これからも頑張っていきます。

Webアプリで処理中に外部実行したコマンドは接続を切るとどうなるか

若いメンバーに説明しないといけなかったので、メモしとく。

テスト用のコード

実行されるWebアプリの処理は下記(環境変わってrailsいじるようになった)。 systemでsleepコマンドを実行する。 systemはlinuxのsystemコマンドを実行する(rubyのドキュメントにsystemコマンドのリンクあったし...)。

pubs.opengroup.org

test_controller.rb

class TestController < ApplicationController
  def index
    system(`sleep 100`)
    render status: 200, json: @controller.to_json 
  end
end

確認手順

  1. ブラウザでサーバ(http://localhost:3000/test/index)にアクセスする
  2. ブラウザを閉じる
  3. ps -ef, pstree -pでプロセスを確認

ちなみに、dockerで環境作ってます。

結果

$ ps -ef

UID        PID  PPID  C STIME TTY          TIME CMD
user         1     0  0 22:08 ?        00:00:01 puma 3.12.2 (tcp://0.0.0.0:3000)
user        79     1  0 22:13 ?        00:00:00 sleep 1000

$ pstree -p

ruby(1)-+-sleep(79)
        |-{ruby}(51)
        |-{ruby}(52)
        |-{ruby}(53)
        |-{ruby}(54)
        |-{ruby}(55)
        |-{ruby}(56)
        |-{ruby}(57)
        |-{ruby}(58)
        |-{ruby}(59)
        |-{ruby}(60)
        |-{ruby}(61)
        |-{ruby}(62)
        |-{ruby}(63)
        |-{ruby}(64)
        `-{ruby}(78)

ということで、接続切ってもプロセスは動いている。

なんで

systemコマンドはforkして子プロセスを生成し、生成された子プロセスがexecを使ってshでコマンドを実行する。

execl(<shell path>, "sh", "-c", command, (char *)0);

つまり、rubyがsystemコマンドで子プロセス(sh)を生成し、さらにshが子プロセス(sleep)を生成して実行する。 shは子プロセスを生成したらすぐに終了するので、sleepの親プロセスは、親の親であるrubyになる、という感じ。

HTTPについて

社内の勉強会用にざっくり書いた

github.com

HTTPについてまとめてみるかなと思ったのはmozaic.fmの影響です。 jxckさんには(一方的に)本当にお世話になってます。 毎回楽しみにしております。

また、@shibu_jpさんのReal World HTTP ミニ版(O'Reilly Japan)も大変参考させてもらいました。 www.oreilly.co.jp

フル版も買います。

Androidアプリつくった

アプリ開発の流れを経験しておきたいのと、(個人的に)便利だろうなと思うものを考えたので作りました。

play.google.com

あまり作業時間を確保できなかったのもありますが、まあ時間かかりました。 アプリ開発は大変だということがよく分かりました。

このアプリは早速使っていきます。

pythonでfitting

簡単な回帰モデルを作らないと行けなくなりそうなので、事前確認。 pythonはド素人なもので。

環境構築

こういうテスト環境はdockerでやりたいので、以下を参考にさせて頂きました。

Alpine Linuxにnumpy, scipy, scikit-learn, pandasを入れた - Qiita

Dockerfile

FROM alpine:latest

RUN apk --update-cache \
    add musl \
    linux-headers \
    gcc \
    g++ \
    make \
    gfortran \
    openblas-dev \
    python3 \
    python3-dev \
    freetype-dev \
    libjpeg-turbo-dev \
    libpng-dev

RUN pip3 install --upgrade pip
RUN pip3 install numpy \
    scipy  \
    scikit-learn \
    matplotlib \
    pandas

RUN mkdir /app

build command

docker build ./ -t python-test

script準備&実行

docker run -it --name python-test-container python-test
docker cp ./test.py python-test-container:/app/test.py
docker start python-test-container
docker exec python-test-container python3 /app/test.py
docker cp python-test-container:/app/plot.png plot.png

データ的に反比例の関数になるはずなので、scipy.optimizeのcurve_fitを使う。python、すごく便利ですね。

import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit

def fitfunc(x, a):
    return a/x

x = np.array([それっぽい適当なデータ])
y = np.array([それっぽい適当なデータ])

param, cov = curve_fit(fitfunc, x, y)
list_y_fit = []
for num in x:
    list_y_fit.append(param[0] / num)

array_y_fit = np.array(list_y_fit)
plt.plot(x, y, marker="o", linestyle="None")
plt.plot(x, array_y_fit, marker="")
plt.savefig('/app/plot.png')
print("a = " + str(param[0]))
plt.show()

結果はこんな感じ。

f:id:takata3:20190425224841p:plain

証明書とか

とある事情で使っていたクライアント証明書の期限が切れたので、発行手順まとめとく(あくまで何をやってるかだけ)。 この辺あんまわかってないから整理も兼ねて。

構成は認証用のproxyサーバとしてnginxを前段に立てていて、認証成功したらバックエンドのサーバにproxyしてる。 で、このproxyサーバがオレオレサーバ。そこで発行したクライアント証明書をクライアント端末にインストールする形となる。


HTTPSでの通信の流れ(主にSSL/TLSハンドシェイク)

作業とは関係ないけどメモがてら。

0. 最初
  • ブラウザでhttps://xxxxにアクセスすると、Webサーバの443ポートにTCPで接続する
    • TCPの3wayハンドシェイクのあと、SSL/TLSハンドシェイク開始
1. クライアント -> サーバ
  • 3wayハンドシェイク後に続けてクライアントからClientHelloを送る
    • 対応している暗号スイートや鍵交換アルゴリズム、鍵生成に使用する乱数など、必要な情報をサーバに送る
2. サーバ -> クライアント
  • ClientHelloを受信後に問題なければServerHelloを送る
    • SSL/TLSプロトコルばーじょんや、合意した暗号スイートやサーバ側の乱数などをクライアントに送る
  • 続けてサーバ側の証明書を送る(ServerCertificate)
  • Diffie-Hellmanであればサーバ側からサーバ鍵交換メッセージを送る(ServerKeyExchange)
  • 必要であればサーバからクライアント証明書のリクエスト(CertificateRequest)
  • ServerHelloDoneを送る
    • サーバ側のHelloが終わったことを示すメッセージ。これを送った後、サーバはクライアントからのリクエストを待つ。
3. クライアント -> サーバ
  • クライアント証明書を送る(ClientCertificate)
    • サーバからの要求があれば送る
  • クライアント側で生成したmaster secret or pre master secretをサーバに送る(ClienetKeyExchange) -クライアント証明書を送っていれば、その証明書に対する署名データを送る(CertificateVerify)
  • 以降の通信が暗号化されることを通知(ChangeCipherSpec)
    • 実際にはTLSハンドシェイクメッセージではなく、独立した TLS プロトコルコンテンツ種別
    • ハンドシェイクレコードの中のメッセージではない
  • クライアントがサーバ認証に成功し、共通鍵を共有できたことを通知する(Finished)
4. サーバ -> クライアント
  • クライアントからのChange Cipher Spec を受信したサーバも、以降の通信が暗号かされることを通知(ChangeCipherSpec)
  • クライアントに共通鍵を共有できたことを通知する(Finished)

以上でハンドシェイク完了

参考

TLS Protocol Version 1.2

サンプル トランザクションおよびパケット交換による SSL の概要 - Cisco

HTTPSコネクションの最初の数ミリ秒

SSLのはなし|Wireless・のおと|サイレックス・テクノロジー株式会社

https://www.digicert.co.jp/welcome/pdf/wp_ssl_negotiation.pdf



クライアント証明書作成


0. サーバ側の秘密鍵、公開鍵、証明書署名要求(CSR)準備

すでに用意してあった。 ちなみに、CSRはサーバ側の公開鍵と秘密鍵のハッシュが含まれている。証明書署名要求はこの情報を認証局に送る作業。

1. プライベート認証局の証明書作成

オレオレサーバなのでサーバが認証局も兼ねている。 サーバと同様に認証局秘密鍵(cakey.pem)と公開鍵&証明書(cacert.pem)を作成する(openssl.confの設定は済んでた)

2. プライベート認証局の署名入りサーバ証明書作成

認証局秘密鍵CSRを使って署名入りのサーバ証明書を作成。 ちなみに、署名とは改ざんを防ぐためにサーバからもらったダイジェスト(ハッシュ値)に対して認証局秘密鍵を使って暗号化を行うこと。

3. クライアント証明書の作成

クライアント証明書用の秘密鍵CSRを作成

4. プライベート認証局の署名入りクライアント証明書作成

認証局秘密鍵CSRを使って署名入りのクライアント証明書を作成。 作成した証明書をPKCS#12形式にフォーマットに変換する。

あとは作成した鍵やら証明書やらを所定のディレクトリに配置して作業完了。

proxyサーバの設定

以下のような設定

ssl on;
ssl_certificate 'サーバ証明書のパス';
ssl_certificate_key 'サーバ証明書(中に含まれている公開鍵)の秘密鍵';
ssl_client_certificate 'クライアント証明書用のCA証明書のパス';
ssl_session_timeout 'SSLセッションキャッシュのタイムアウト設定'; 
ssl_verify_client on;  //  クライアント証明書を要求する(ハンドシェイク時にサーバからCertificateRequestが送られる)
ssl_verify_depth '証明書のチェーンを何階層までたどるかを設定';
ssl_protocols '対応SSLプロトコルバージョン';
ssl_ciphers '対応/非対応の暗号化スイート';
ssl_prefer_server_ciphers on; // サーバ側の暗号化スイートの設定を優先する



その他

SSLKEYLOGFILE

SSLKEYLOGFILEとは、TLS 通信時に使用した鍵情報のダンプ先となるファイルパスを指定するための環境変数

Wireshark で HTTP/2 over TLS の通信をダンプする方法 · GitHub

firefoxの65でこの環境変数を設定したけど全く出力されなかった。 どうもNSS_ALLOW_SSLKEYLOGFILEの設定がdisableになったっぽい。

1519209 - Disable NSS_ALLOW_SSLKEYLOGFILE

なのでfirefoxの62をダウンロードしたら動いた。

Wiresharkで覗いたらTLS1.2(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)だったので以下のフォーマット。

CLIENT_RANDOM <client hello random(32byte(=64byteの16進数))> <master secret(48byte(=96byteの16進数))>

client hello randomはSSL/TLSハンドシェイクのClientHelloで送信されるclient生成の乱数。

master secretはClientRandom、ServerRandom、PreMasterSecretによって生成されたセッションキー(共通鍵を生成する元データ)。 このセッションキーをサーバ/クライアント間で共有し、暗号化/復号に利用する。 クライアントがサーバに対して実際に送信するのはPreMasterSecret。PreMasterSecretと乱数情報からmaster secretが作られる。

TLS Security 5: Establishing a TLS Connection | Acunetix

DH鍵交換でもWiresharkでSSL/TLSを復号化したい - 逆さまにした

PFSなTLS通信を復号する