taisablog

taisa's engineer blog

Screen Shot 0030-11-20 at 14.45.54

投稿日:

-

執筆者:

関連記事

PyLadies Tokyo 3周年記念パーティーでLTしてきた

以前PyLadies Tokyo 3周年記念パーティーに参加してLTしてきたのでその参加メモ。基本的にこれから書く内容は以下の投稿とtogatterにまとまっている内容と似た内容になっているけど記録として書きます。 PyLadies Tokyo – 3周年記念パーティ に参加してきた PyLadies Tokyo – 3周年記念パーティ に参加してきた #pyladiestokyo – massa142’s blog PyLadies Tokyo 3周年記念パーティー Togatterまとめ PyLadies Tokyo 3周年記念パーティー PyLadies Tokyoとは? PyLadies Tokyo は,PyLadies の東京支部です。Pythonが好きな女性同士をつなぐために、よりPythonが好きになってもらえるように、活動しています。初心者の人が参加しやすい入門者向けイベントから熟練者がより楽しめるようなちょっと難易度の高いイベント、みんなでワイワイ発表するLT大会など、様々なテーマで毎月イベントを開催しています。どうぞお気軽にご参加下さい。 https://pyladies-tokyo.connpass.com/event/64367/ 普段は女性Onlyだけど今回は3周年記念イベントということで男性枠を設けてくれている。 PyLadies Tokyo – 3周年記念パーティ (2017/10/15 12:20〜) 参加動機 PyLadies Tokyoのメンバーと一緒にPyCon APAC 2017 in Malaysiaへ行って来たのがきっかけ PyCon APAC 2017 in マレーシア 参加レポ LTスライド PyConをきっかけに英語力を身につける New presentation (2017-10-14 21:18:42) 全体的な感想 この日は翌日にサービスローンチを控えているという状況だった為、会社から直行してLT終わって直帰するという非常に残念な状況だった。前半のLTしか聞けなかったけど、それでもLTは全部おもしろくてものすごく楽しめた。(お酒飲めなかったし食事もほとんどできなかったけど)スポンサーのRettyさん、Google Cloud Platformさんありがとうございました。

no image

2016年の振り返り

2017年になってもう3ヶ月が過ぎようとしているけど、今年初投稿なので今更ながら2016年の振り返りをする。 2016年前半 2016年前半はWeb業界に来て初めてWebサービスの受託開発をした。5年前にSIerからWeb業界に来て以来初めての受託開発だった。プロジェクト前半は若手エンジニア2人いたが、色々な都合により後半は自分1人になりそこからは1人最後までやることになった。 SIerにいた頃、小さめのプロジェクトであれば自分一人でやることはあったが、今回のような大きめのプロジェクトで0→1のサービス開発をマネージメントしながら開発するというのは初めてだった。ローンチ後は何事もなく稼働しているのでよくやったと思えたもののWebサービスの受託開発の難しさを思い知った。 Laravelについて 開発はPHP+Laravelを使った。初めて使ったフレームワークだったが、日本語ドキュメントがしっかりしているのでほぼそれだけで開発を進めることができた。 https://readouble.com/laravel/5.1/ja/installation.html 主なプラグインは以下を使った。 laravel-debugbar laravel-ide-helper Intellij Laravel-Plugin 2016年後半 サービス開発に戻り、戻ってからは主に以下のことをやった。 決済システム導入 CI環境の再整備 ステージング環境の整備と追加 PHPUnit+Phakeによるユニットテストの本格導入 サーバのオートスケール 決済システム導入 これは、受託開発が都合により伸びた為、設計までして他のメンバーに引き継ぐすることになってしまったが、その後、また引き継ぎ開発を進めていった。「決済」といったシステムを扱ったことで良い経験ができたように思う。 CI環境の再整備 サービスの拡大、人の入れ替わり、増加により以前自分で立てたJenkinsのCI環境が整備されずひどい状況になりつつあったので整備した。Jenkins2へのバージョンアップもこのタイミングで行った。 ステージング環境の整備と追加 人員に対してステージング環境があきらかに枯渇していたので再整備と追加をした。具体的にはシステムだけでなく運用者もリリース前テストで利用する為、ステージング環境利用待ちのようなものが発生している状況だった。また、いくつかのサービスがつながっていることもあり環境がブラックボックス化していたのを再構築しドキュメント化しつつ環境を増やした。テスト環境大事。 PHPUnit+Phakeによるユニットテストの本格導入 UnitTestも以前は書くよう推奨していたが形骸化している状況だった。また、新卒メンバーが入ってそもそもテストが書けないメンバーもいる状況だった。これに対して、ハンズオンを開催しある程度書けるところまで持っていき、それ以降はプロダクト開発時にフォローするという形で最終的にはメンバー全員が必ずUnitTestを書くというところまで持っていくことができた。また、テストが増える従って、修正時の確認コストが減り品質が上がってきている実感が得られた。 サーバのオートスケール アクセスが増え、ときに突発的に高負荷が来るという事象が増えてきて、その度にサーバをたて、デプロイスクリプトに新しいサーバを追加しデプロイするということをやっていた。それもいい加減面倒だし事前アナウンスがなければ対応ができないので、常にS3に最新ソースを配置しておき、あとは負荷検知により自動的にサーバを増やすという仕組みを導入した。 社外活動とアウトプット 2015年末に子供が生まれたことと2016年の前半の受託開発に忙殺されたことで全くできなかった。2017年は落ち着いて来たこともあり活動を増やす予定。 まとめ 2016年後半の取り組みに関しては、2017年から始めるスクラムの取り組みの為の下準備という意味合いもあり、テストや環境系の整備をメインに行った。これにより2017年からの取り組みをスムーズに始められたと思う。

Gitの参照 – HEADとheadsとtagsとremotes

Gitの参照についてまとめました。また別記事にてGitの内側について記載しています。 配管(Plumbing)と磁器(Porcelain)Git オブジェクト Gitの内側についておさらい 「git init」すると「.git」ディレクトリができるがその中についてがテーマ普段は使わない配管コマンドと呼ばれる下位レベルのコマンドがある4つのオブジェクトがある blobオブジェクト(ファイルに相当) treeオブジェクト(ディレクトリに相当) commitオブジェクト(commit情報を保持) tagオブジェクト(Tagを保持) Gitの参照って? ここで取り上げるGitの参照は「HEAD」ファイルと「.git/refs」配下のことを示します。「git init」した直後「HEAD」ファイルは「refs/heads/master」を参照し(初期化直後はなにも存在しない)、「.git/refs」配下には、headsとtagsディレクトリがあります。ブランチにcommitするとheads配下にブランチ名のファイルができ、HEADファイルはheads配下のブランチ名を参照します。 # masterにcommit後 # HEADファイル ref: refs/heads/master # refs配下の構造 └── refs ├── heads │   └── master └── tags Gitの参照の種類 Gitの参照の種類は次の通りです。 heads:作業中ブランチのcommitを参照tags:commitをわかりやすくする為の名前付け用remotes:リモートブランチのcommitを参照HEAD:作業中のブランチに対するシンボリック参照。HEADは基本的にheadsを参照しているので、他の参照と区別する為シンボリック参照と呼ばれます 動作確認の為の事前準備 次のような3つのcommitがあるリポジトリを用意しremoteへpushしておきます。 % git log –pretty=oneline master 1f36229bc26825222b191dcd63929392d9d8e2fd third commit 543ee947f5a865e1a998f793120667c3bf89fc80 second commit 23391397b4316d334e9293c4f7d1d601c1f24c4c first commit % git remote add origin git@github.com:taisa007/internal-git.git 次からはこのリポジトリを利用します。クローンする場合はこちらを利用してください。 構成 構成は次の通りです。「.git/refs」ディレクトリ配下にそれぞれheads, remotes, tagsというディレクトリが作られています。 % tree .git └── refs ├── heads │   └── master ├── remotes │   └── origin │   └── master └── tags Gitの参照の解説 「refs」配下にあるファイルはそれぞれ最後のcommitをファイルに記録しています。例えば現在masterは「third commit」にいますが「git log –pretty=oneline master」とすると次のようなcommit履歴が確認できます。 % git log –pretty=oneline master 1f36229bc26825222b191dcd63929392d9d8e2fd third commit 543ee947f5a865e1a998f793120667c3bf89fc80 second commit 23391397b4316d334e9293c4f7d1d601c1f24c4c first commit …

PHPによるDBUnit超入門

例えば簡単なWebサービスでMVCのフレームワークを使っていてビジネスロジックを書く用にコントローラとモデルの間にサービス層を追加して開発している場合、コントローラやサービスはモックを駆使しながらテストを書いていくことができます。ただ、例えばフレームワークをバージョンアップしたい、PHPをバージョンアップしたいなどの場合に既存のモデル層に影響がないかをテストで確認したいなんてことがあります。そのような場合には、DBUnitを導入してみてもいいかもしれません。ということで本記事ではPHPによるDBUnitの使い方を書いてみます。 事前情報 今phpunit/dbunitをインストールしようとすると以下の文言が出力されます。詳しくはこちらのissueに書いてありますが、どうもSebastianさんはdbunitのメンテナンスをやめるようです。ただそれを受けてforkしたプロジェクトが出てきているようなので大丈夫かと思います。今回はSebastianさんの純正dbunitを使っています。 Package phpunit/dbunit is abandoned, you should avoid using it. No replacement was suggested また、DBUnitに関する詳しい情報はマニュアルにありますのでご確認ください。https://phpunit.de/manual/6.5/ja/database.html#database.implementing-getdataset 作成したサンプルプロジェクト 今回は、dbunitの確認だけをしたいので、dietcakeのmessage-boardというサンプルプロジェクトを利用しました。今回作成したDBUnit用のサンプルプロジェクトは GitHub からダウンロードして確認できます。 git clone git@github.com:taisa831/phpunit-dbunit-sample.git cd phpunit-dbunit-sample composer install # mysqlサーバを立て`app/config/sql/board.sql`を実行する(SQLは下記に記載しています) # テスト実行 ./vendor/bin/phpunit PHPUnit 7.5.8 by Sebastian Bergmann and contributors. ….. 5 / 5 (100%) Time: 207 ms, Memory: 4.00 MB OK (5 tests, 14 assertions) アプリ用のDDLです。開発用DBとは違うのでboard_dbunitというテーブル名にしています。 — — — Create database — CREATE DATABASE IF NOT EXISTS board_dbunit; GRANT SELECT, INSERT, UPDATE, DELETE ON board.* TO board_root@localhost IDENTIFIED BY ‘board_root’; FLUSH PRIVILEGES; — — Create tables — USE board_dbunit; CREATE TABLE IF NOT EXISTS thread ( id INT UNSIGNED …

Golangを使ってJWTを15分で理解する

JWTとは JWT(ジョットと言うらしい)はJSON Web Tokenの略で、JSONをベースとしたアクセストークンのためのオープン標準 (RFC 7519) です。色々記事を見ましたが、最終的にWikipediaが分かりやすく一番参考にしました。https://ja.wikipedia.org/wiki/JSON_Web_Token JWTの構造 JWTは以下の3つの要素をピリオドで区切った文字列で構成されます。 ヘッダー 署名生成に使用するアルゴリズムを格納します。下記のHS256は、このトークンがHMAC-SHA256で署名されていることを示しています。署名アルゴリズムとしては、SHA-256を使用したHMAC (HS256) や、SHA-256を使用したRSA署名 (RS256) がよく用いられます。 { “alg” : “HS256”, “typ” : “JWT” } ペイロード 認証情報などのクレームを格納します。クレームとはペイロードに含める以下のような標準フィールド(クレーム)を指します。JWTの仕様では、トークンに一般的に含まれる7つの標準フィールドが定義されています。また用途に応じた独自のカスタムフィールドを含むこともできます。下記の例では、トークン発行日時を示す標準のクレーム (iat) と、カスタムクレーム (loggedInAs) を格納しています。 { “loggedInAs” : “admin”, “iat” : 1422779638 } 7つのペイロードの標準クレーム 署名 トークン検証用の署名です。署名はヘッダーとペイロードをBase64urlエンコーディングしてピリオドで結合したものから生成します。署名はヘッダーで指定された暗号化アルゴリズムにより生成されます。下記はHMAC-SHA256形式でのコード例です。 HMAC-SHA256(base64urlEncoding(header) + ‘.’ + base64urlEncoding(payload), ‘secret key’) JWTを使用するにあたって JWTはトークンが返され、それをローカルに保存して利用します(主にlocal storageやsession storageが用いられますが、セッションIDのようにCookieを用いる場合もあります。) 認証時にはAuthorizationヘッダーでBearerスキーマを利用します。またサーバー上に認証状態を保持しないステートレスな認証方式です。その為JWT単体ではトークンを無効にすることが出来ません。サーバーに状態を保持すれば可能ですが、その場合ステートレスの利点は失われることになります。さて、ここまではほぼ Wikipedia に書いてある内容そのままです。ここから実際にGo/GinのJWT Middlewareを使って実際の動作を確認してみます。 Go/GinのJWT Middlewareを使った動作確認 利用するJWT Middlewareについて ここでは、「https://github.com/gin-gonic/gin」 を使う前提で、次のMiddlewareを利用します。「https://github.com/appleboy/gin-jwt」。このMiddlewareは、auth_jwt.goの1ファイルでで構成されていて、「https://github.com/dgrijalva/jwt-go」 をGin用に薄くラップしたものです。jwt-goはトークンを作成したりパースしたり様々な機能が用意されています。 サンプルソース サンプルソースは、https://github.com/appleboy/gin-jwt/blob/master/README.md に載っているのでこれを元に確認します。処理は大きく「ログイン時にToken発行する」と「トークン認証&処理実行する」の2種類あります。 ログイン時にToken発行する ログイン時にTokenを発行する処理は、LoginHandlerです。Routerでは次のように定義しています。LoginHandlerではAuthenticatorとPayloadFuncが呼ばれる為、Middlewareにてこれらを実装する必要があります。 r.POST(“/login”, authMiddleware.LoginHandler) Authenticatorはログイン認証の為の関数です。例では固定値が設定されていますが、実際は主にDBから値を取得することになると思います。PayloadFuncはペイロードに含めるクレームを設定します。ペイロードには任意のクレームを追加可能なので、ログインIDとなるuserIDをセットしています。 // ログインに基づいたユーザの認証振る舞いをするコールバック Authenticator: func(c *gin.Context) (interface{}, error) { var loginVals login if err := c.ShouldBind(&loginVals); err != nil { return “”, jwt.ErrMissingLoginValues } userID := loginVals.Username password := loginVals.Password // …