ようへいの日々精進XP

よかろうもん

2018 年 08 月 19 日 (日)

ジョギング

  • 香椎浜 x 2 周
  • ゆっくりとダラッと走った

日課

  • 引き続き, 腰と腰に痛みがあるので休み中

次の住処を決めてきた

  • 今度は, 奥さん待望のちょっと広めの部屋
  • 引っ越しは来月というタイトなスケジュールだけど無理せず頑張ろう

今日の AWS ~ AWS 認定デベロッパー – アソシエイトレベルサンプル試験を解く (4) ~

公開されているサンプル試験問題を解く. なぜ, その答えになるのかをちゃんと理解する必要がある. 尚, 今回は英語版のサンプル問題である為, 翻訳には Google 翻訳を利用している.

Q1. CloudFormation 展開時のエラー

設問

1) Your CloudFormation template launches a two-tier web application in us-east-1. When you attempt to create a development stack in us-west-1, the process fails.

  • 二層の Web アプリケーションを us-east-1 に CloudFormation を利用して展開しようとしている
  • このテンプレートを us-west-1 で展開しようとすると失敗する

What could be the problem?

A) The AMIs referenced in the template are not available in us-west-1.
B) The IAM roles referenced in the template are not valid in us-west-1.
C) Two ELB Classic Load Balancers cannot have the same Name tag.
D) CloudFormation templates can be launched only in a single region.

何が問題なのか.

A) テンプレートで参照されている AMI は us-west-1 では使用できない
B) テンプレートで参照されている IAM ロールは us-west-1 では無効である
C) 2 つの ELB クラシックロードバランサは同じ名前タグを持つことが出来ない
D) CloudFormation テンプレートは、単一の領域でのみ起動出来る

正答

A) The AMIs referenced in the template are not available in us-west-1. (テンプレートで参照されている AMI は us-west-1 では使用できない)

メモ

解答のコメントより引用.

AMIs are stored in a region and cannot be accessed in other regions. To use the AMI in another region, you must copy it to that region. IAM roles are valid across the entire account.

  • AMI はリージョン毎に格納され, 他のリージョンからアクセス出来ない
  • 別のリージョンで利用する場合には AMI をコピーする必要がある
  • IAM ロールはアカウント全体で有効となる

Q2. SQS の仕様

設問

Your application reads commands from an SQS queue and sends them to web services hosted by your partners. When a partner's endpoint goes down, your application continually returns their commands to the queue. The repeated attempts to deliver these commands use up resources. Commands that can’t be delivered must not be lost.

  • アプリケーションは SQS キューからコマンドを読み取り, パートナーがホストする Web サービスにコマンドを送信する
  • パートナーの Web サービスが停止した場合, アプリケーションはコマンドをキューに継続的に送信してしまう
  • 継続的に送信するとリソースが消費されてしまう
  • 配信されなかったコマンドは失われてはいけない

How can you accommodate the partners' broken web services without wasting your resources?

A) Create a delay queue and set DelaySeconds to 30 seconds.
B) Requeue the message with a VisibilityTimeout of 30 seconds.
C) Create a dead letter queue and set the Maximum Receives to 3.
D) Requeue the message with a DelaySeconds of 30 seconds.

リソースを浪費することなく, 停止されるパートナーの Web サービスに対してどのように対応できるか?

A) 遅延キューを作成し, DelaySeconds を 30 秒に設定します
B) 30 秒の VisibilityTimeout でメッセージを再キューします
C) デッドレターキューを作成し, 最大受信数を 3 に設定します
D) 30 秒の DelaySeconds でメッセージを再キューします

正答

なんだろう...このような場合には Long Polling が有効のような気がするけど...

C) Create a dead letter queue and set the Maximum Receives to 3. (デッドレターキューを作成し, 最大受信数を 3 に設定します)

メモ

解答のコメントより引用.

After a message is taken from the queue and returned for the maximum number of retries, it is automatically sent to a dead letter queue, if one has been configured. It stays there until you retrieve it for forensic purposes.

  • デッドレターキューが設定されている場合, メッセージ取得の最大試行回数を超えると, 自動的にデッドレターキューに送信される
  • forensic purposes = 法医学って訳されるので, ちょっとここはよく意味が分からない

設問に「配信されなかったコマンドは失われてはいけない」とあるので, デッドレターキューを設定し, 正常に処理出来なかったメッセージを後から処理出来るようにしておく必要があるということかな.

Q3. 安全に SQS にデータを書き込む為に必要な AWS の資格情報をどのように管理するか的な

設問

Your application must write to an SQS queue. Your corporate security policies require that AWS credentials are always encrypted and are rotated at least once a week.

  • アプリケーションは SQS キューにメッセージを書き込む必要がある
  • 企業のセキュリティポリシーでは, AWS 資格情報は常に暗号化され, 少なくとも1週間に1回ローテーションされる

How can you securely provide credentials that allow your application to write to the queue?

A) Have the application fetch an access key from an Amazon S3 bucket at run time.
B) Launch the application's Amazon EC2 instance with an IAM role.
C) Encrypt an access key in the application source code.
D) Enroll the instance in an Active Directory domain and use AD authentication.

アプリケーションがキューに書き込むための資格情報を安全に提供するにはどうすればよいか?

A) 実行時にアプリケーションが Amazon S3 バケットからアクセスキーをフェッチするようにします.
B) IAM Role が付与された Amazon EC2 インスタンスでアプリケーションを起動します.
C) アプリケーションソースコード内のアクセスキーを暗号化します.
D) インスタンスを Active Directory ドメインに登録し, AD 認証を使用します.

正答

B) Launch the application's Amazon EC2 instance with an IAM role. (IAM Role が付与された Amazon EC2 インスタンスでアプリケーションを起動します.)

メモ

解答のコメントより引用.

IAM roles are based on temporary security tokens, so they are rotated automatically. Keys in the source code cannot be rotated (and are a very bad idea). It’s impossible to retrieve credentials from an S3 bucket if you don’t already have credentials for that bucket. Active Directory authorization will not grant access to AWS resources.

  • IAM ロールは一時的なセキュリティトークンに基づいている為, 自動的にローテーションされる
  • ソースコード内のキーはローテーション出来ない (とても悪い実装である)
  • S3 バケットへの資格情報がない場合, S3 バケットから資格情報を取得することは不可能である
  • Active Directory の承認は, AWS リソースへのアクセスを許可しない (そりゃそうだ...)

フムフム.

俺の A Tour of Go (1)

A Tour of Go

https://go-tour-jp.appspot.com/ を写経していく.

成果は...

github.com

こちらに.

Packages

  • https://go-tour-jp.appspot.com/basics/1
  • Go は package で構成されている
  • プログラムは main パッケージから開始される
  • 以下のプログラムでは "fmt""math/rand" パッケージをインポート( import )している
  • 規約では, パッケージ名はインポートパスの最後の要素と同じ名前になる
  • 例えば, インポートパスが "math/rand" のパッケージは, package rand ステートメントで始まるファイル群で構成する
// filename: codes/packages.go
package main

import (
    "fmt"
    "math/rand"
)

func main() {
    fmt.Println("My favorite number is", rand.Intn(10))
}

もし, import パスが "golang.org/x/net/websocket" のような URL が含まれる場合には, package websocket となる.

# コードの実行結果
$ ./_run.sh packages.go 
My favorite number is 1

Imports

// filename: codes/imports.go
package main

import (
    "fmt"
    "math"
)

func main() {
    fmt.Printf("Now you have %g problems.", math.Sqrt(7))
}

factored (要素化, グループ化, 整理済み) インポートステートメントの方がより良いスタイルである.

# コードの実行結果
$ ./_run.sh imports.go 
Now you have 2.6457513110645907 problems.

Exported names

  • https://go-tour-jp.appspot.com/basics/3
  • 最初の文字が大文字で始まる名前は, 外部パッケージから参照できるエクスポート(公開)された名前 ( exported name )
  • 小文字ではじまる pi 等はエクスポートされていない名前
  • パッケージをインポートすると, そのパッケージがエクスポートしている名前を参照することができる
  • エクスポートされていない名前(小文字ではじまる名前)は, 外部のパッケージからアクセスすることはできない
// filename: codes/exported-names.go
package main

import (
    "fmt"
    "math"
)

func main() {
    fmt.Println(math.pi)
}

pi という名前ではエクポートされていないので, 実行するとエラーとなる.

$ ./_run.sh exported-names.go 
# command-line-arguments
/sandbox/exported-names.go:10:14: cannot refer to unexported name math.pi
/sandbox/exported-names.go:10:14: undefined: math.pi

以下のように修正する.

// filename: codes/exported-names.go
package main

import (
    "fmt"
    "math"
)

func main() {
    fmt.Println(math.Pi)
}

改めて実行すると...

$ ./_run.sh exported-names.go 
3.141592653589793

Functions

  • https://go-tour-jp.appspot.com/basics/4
  • 関数は, 0 個以上の引数を取ることができる
  • 以下のコードにおいて, add 関数は int 型の 2 つのパラメータを取る
  • 変数名の後ろに型名を書く
// filename: codes/functions.go
package main

import "fmt"

func add(x int, y int) int {
    return x + y
}

func main() {
    fmt.Println(add(42, 13))
}

実行.

$ ./_run.sh functions.go 
55

Functions continued

// filename: codes/function-continued.go
package main

import "fmt"

func add(x, y int) int {
    return x + y
}

func main() {
    fmt.Println(add(42, 13))
}

実行.

$ ./_run.sh function-continued.go 
55

Multiple results

// filename: codes/multiple-results.go
package main

import "fmt"

func swap(x, y string) (string, string) {
    return y, x
}

func main() {
    a, b := swap("hello", "world")
    fmt.Println(a, b)
}

実行.

s$ ./_run.sh multiple-results.go 
world hello

Named return values

  • https://go-tour-jp.appspot.com/basics/7
  • 戻り値となる変数に名前をつける( named return value )ことが出来る
  • 戻り値に名前をつけると, 関数の最初で定義した変数名として扱われる
  • 戻り値の名前は, 戻り値の意味を示す名前とすることで, 関数のドキュメントとして表現するようにする
  • 名前をつけた戻り値の変数を使うと, return ステートメントに何も書かずに戻すことが出来る (これを "naked" return と呼ぶ)
// filename: codes/named-results.go
package main

import "fmt"

func split(sum int) (x, y int) {
    x = sum * 4 / 9
    y = sum - x
    return
}

func main() {
    fmt.Println(split(17))
}

"naked" return ステートメントは, 短い関数でのみ利用すべき. 長い関数で使うと読みやすさ( readability )に悪影響がある.

$ ./_run.sh named-results.go 
7 10

Go, Go, Go, Go 〜 (郷ひろみ風)

以上, Go, Go, Go, Go 〜でした.

2018 年 08 月 18 日 (土)

ジョギング

  • 香椎浜 x 2 周
  • カラッとして走りやすかったけど, なんか体が重いし, 体が動かない...

日課

  • 引き続き, 腰と腰に痛みがあるので止めといた

ミッション・インポッシブル

missionimpossible.jp

最新のミッション・インポッシブル〜フォールアウト〜を観てきた.

細かいことを言うと, ストーリ的に「んっ??」ってなる部分もあったけど, 一貫して冷や冷やしたし, トム・クルーズがガチでアクションしてて「すごい」としか思えなかった.

今日のるびぃ exercism 編 〜 Difference Of Squares (1) 〜

ギョームで Ruby を触ることが無さすぎるので, exercism の問題を解くことにした.

概要

総和の二乗と各自然数の二乗の総和の差分を求める.

  • The square of the sum of the first ten natural numbers is (1 + 2 + ... + 10)² = 55² = 3025.
  • The sum of the squares of the first ten natural numbers is 1² + 2² + ... + 10² = 385.

上記の 3025 と 385 の差分を求める.

テスト

require 'minitest/autorun'
require_relative 'difference_of_squares'

# Common test data version: 1.1.0 7a1108b
class DifferenceOfSquaresTest < Minitest::Test
  def test_square_of_sum_1
    # skip
    assert_equal 1, Squares.new(1).square_of_sum
  end

  def test_square_of_sum_5
    # skip
    assert_equal 225, Squares.new(5).square_of_sum
  end

  def test_square_of_sum_100
    # skip
    assert_equal 25_502_500, Squares.new(100).square_of_sum
  end

  def test_sum_of_squares_1
    # skip
    assert_equal 1, Squares.new(1).sum_of_squares
  end

  def test_sum_of_squares_5
    # skip
    assert_equal 55, Squares.new(5).sum_of_squares
  end

  def test_sum_of_squares_100
    # skip
    assert_equal 338_350, Squares.new(100).sum_of_squares
  end

  def test_difference_of_squares_1
    # skip
    assert_equal 0, Squares.new(1).difference
  end

  def test_difference_of_squares_5
    # skip
    assert_equal 170, Squares.new(5).difference
  end

  def test_difference_of_squares_100
    # skip
    assert_equal 25_164_150, Squares.new(100).difference
  end

...
  
  def test_bookkeeping
    skip
    assert_equal 4, BookKeeping::VERSION
  end
end

実装

class Squares
  def initialize(n)
    @n = n
  end

  def square_of_sum
    sum = (0..@n).inject(:+)
    # sum = (0..@n).inject(0) { |sum, n| sum + n }
    sum ** 2
  end

  def sum_of_squares
    sum = (0..@n).inject(0) { |sum, n| sum + n ** 2 }
    sum
  end

  def difference
    square_of_sum - sum_of_squares
  end
end

injectreduce に置き換えても OK 牧場.

class Squares
  def initialize(n)
    @n = n
  end

  def square_of_sum
    sum = (0..@n).reduce(:+)
    sum ** 2
  end

  def sum_of_squares
    sum = (0..@n).reduce(0) { |sum, n| sum + n ** 2 }
    sum
  end

  def difference
    square_of_sum - sum_of_squares
  end
end

Run Test

$ ruby difference_of_squares_test.rb
Run options: --seed 16699

# Running:

........S.

Finished in 0.001553s, 6439.1500 runs/s, 5795.2350 assertions/s.

10 runs, 9 assertions, 0 failures, 0 errors, 1 skips

You have skipped tests. Run with --verbose for details.

いい感じ.

メモ

  • inject 結構便利
  • reduce は inject のエイリアス (と言っていいのかな??)

今日の AWS ~ AWS 認定デベロッパー – アソシエイトレベルサンプル試験を解く (3) ~

公開されているサンプル試験問題を解く. なぜ, その答えになるのかをちゃんと理解する必要がある.

Q8. STS について

設問

企業ウェブアプリケーションAmazon VPC 内にデプロイし、IPSec VPN 経由で企業データセンターに接続しています。このアプリケーションは、オンプレミスの LDAP サーバーに対して認証を行う必要があります。認証後、ログインしたユーザーは、そのユーザーに固有の S3 キー空間のみにアクセスできます。この目的を満たすことができる方法を、次の中から 1 つ選んでください。

A. アプリケーションを LDAP に対して認証する。次に、アプリケーションで IAM Security Token Service を呼び出して、LDAP 認証情報を使用して IAM にログインする。アプリケーションでは、IAM の一時的な認証情報を使用して適切な S3 バケットにアクセスできる。
B. アプリケーションを LDAP に対して認証し、ユーザーに関連する IAM ロールを取得する。次に、IAM Security Token Service を呼び出して、その IAM ロールを引き受ける。アプリケーションでは、一時的な認証情報を使用して適切な S3 バケットにアクセスできる。
C. LDAP 認証情報を使用して、アプリケーションを IAM Security Token Service に対して認証する。これらの一時的な AWS セキュリティ認証情報を使用して、適切な S3 バケットにアクセスする。
D. LDAP に対して認証を行う認証ブローカーを開発し、IAM Security Token Service を使用して IAM フェデレーションユーザー認証情報を取得する。アプリケーションで認証ブローカーを呼び出して、適切な S3 バケットへのアクセスを有する IAM フェデレーションユーザー認証情報を取得する。
E. IAM Security Token Service に対して認証を行って IAM ロールを引き受け、一時的な AWS セキュリティ認証情報を取得する認証ブローカーを開発する。アプリケーションで認証ブローカーを呼び出して、適切な S3 バケットへのアクセスを有する AWS の一時的なセキュリティ認証情報を取得する。

正答

  • D (LDAP に対して認証を行う認証ブローカーを開発し、IAM Security Token Service を使用して IAM フェデレーションユーザー認証情報を取得する。アプリケーションで認証ブローカーを呼び出して、適切な S3 バケットへのアクセスを有する IAM フェデレーションユーザー認証情報を取得する。)

メモ

  • 設問や選択肢自体の日本語が分かり辛い
  • 設問としては, LDAP で認証させたユーザーに対して, 一時的に AWS リソースへのアクセスを許可するにはどうしたら良いか ということを問われているような気がする
  • 解答としては, ユーザー (アプリ) は認証ブローカーにリクエストを投げて, ブローカーが LDAP で認証し, 認証されたら STS に一時的な認証情報の取得を要求し, その情報を以て S3 にアクセスさせる...ってことなのかな

このあたりの理解は深めたいなー.

Q9. S3 の署名付き URL について

設問

広告収益モデルの写真共有ウェブサイトを運営しており、サイト訪問者への写真配信に S3 を使用しています。いつからかその写真に他のサイトが直接リンクを張るようになり、広告収益の減少を招いていることに気づきました。この影響を緩和するにはどの対策が効果的ですか?

A. 静的コンテンツに CloudFront ディストリビューションを使用する。
B. パブリックの読み込み権限を削除し、有効期限付きの署名 URL を使用する。
C. 被害を及ぼしているウェブサイトの IP をセキュリティグループで遮断する。
D. 写真をウェブサーバーの EBS ボリュームに保存する。

正答

  • B (パブリックの読み込み権限を削除し、有効期限付きの署名 URL を使用する。)

メモ

  • 署名付き (有効期限付き) URL を発行する

Q10. S3 の仕様

設問

アプリケーションで 6 GB のファイルを Simple Storage Service にアップロードしようとしていますが、「指定されたアップロードは、アップロード可能な最大オブジェクトサイズを超えています。」というメッセージが表示されます。これを解決する方法はありますか?

A. ない。Simple Storage Service オブジェクトは 5 GB に制限されている。
B. このオブジェクトにマルチパートアップロード API を使用する。
C. このオブジェクトに大きなオブジェクトのアップロード API を使用する。
D. サポートに連絡してオブジェクトサイズ制限を増やす。
E. 異なるリージョンにアップロードする。

正答

  • B (このオブジェクトにマルチパートアップロード API を使用する。)

メモ

  • 1 ファイル最大 5TB まで
  • 1 回にアップロード (1 つの PUT) 出来るサイズは 5GB まで, 5GB を超える場合にはマルチパートアップロード API を利用する
  • バケット内のオブジェクト数は無制限

フムフム.

2018 年 08 月 17 日 (金)

ジョギング

  • 香椎浜 x 2 周
  • 涼しくてだいぶん走りやすかった...けど, やっぱり汗だくにはなった

日課

  • 引き続き, 腰と腰に痛みがあるので止めといた

父の 70 回目の誕生日

プレゼントに Web カメラを送ったら, 早速, 喜んでくれて接続テストがてら zoom.us した. 顔が見れるのが良い.

JAWS-UG 福岡もくもく会 #5

近日中に Developer アソシエイトとか受けるのでその勉強をした.

その後, 懇親会で俺たちの「家康」で.

もくもくの後, ワイワイで楽しい会だった. 次は再来週くらいを考えているけど, ま, 無理の無い程度にゆるーくなが~く続けられればなあ.

今日の AWS ~ AWS 認定デベロッパー – アソシエイトレベルサンプル試験を解く (2) ~

公開されているサンプル試験問題を解く. なぜ, その答えになるのかをちゃんと理解する必要がある.

Q4. S3 仕様について

設問

...Amazon S3 で US‐STANDARD リージョンにオブジェクトを格納したところ、正常に格納できたという確認メッセージ を受信しました。その直後に、別の API を呼び出して、このオブジェクトを読み込もうとしました。しかし S3 から、オブ ジェクトが存在しないというメッセージが返されました。どのような原因が考えられますか?

A. US‐STANDARD で結果整合性を使用していて、バケットでオブジェクトが読み込み可能になるまでに時間がかかることがある。
B. Amazon S3 のオブジェクトは、第 2 のリージョンに複製されるまでは表示されない。
C. US‐STANDARD では、新しいオブジェクトが読み込み可能になるまでに 1 秒の遅延が課されている。
D. バケットのオブジェクト制限を超えたため。この制限を増やすと、オブジェクトが表示される。

正答

  • A (US‐STANDARD で結果整合性を使用していて、バケットでオブジェクトが読み込み可能になるまでに時間がかかることがある。)

メモ

  • US‐STANDARD リージョンは新規オブジェクト作成については結果整合性 (書き込み後の読み込み整合性もサポートされている)
  • 他のリージョンについては, 新規オブジェクト作成については書き込み後の読み込み整合性となる

Q5. CloudFormation の仕様について

設問

リージョンの CloudFormation スタックの数についてのアカウント制限に達しました。制限を増やすには、どうすればよいですか?

A. API を呼び出す。
B. AWS に連絡する。
C. マネージメントコンソールを使用する。
D. 制限を増やすことはできない。

正答

  • B (AWS に連絡する。)

メモ

  • CloudFromation のスタック数の上限 200 個
  • AWS サポートに上限緩和申請を行う

Q6. DynamoDB の仕様について

設問

DynamoDB について正しいことを述べている文はどれですか?(正解を 2 つ選択)

A. DynamoDB では、ペシミスティックロックモデルを使用する。
B. DynamoDB では、楽観的オプティミスティック同時実行制御を使用する。
C. DynamoDB では、一貫性を実現するために条件付き書き込みを使用する。
D. DynamoDB では、読み込み時の項目アクセスを制限する。
E. DynamoDB では、書き込み時の項目アクセスを制限する。

正答

  • B (DynamoDB では、楽観的オプティミスティック同時実行制御を使用する。)
  • C (DynamoDB では、一貫性を実現するために条件付き書き込み (Consistent Read) を使用する。)

メモ

  • AWS Black Belt Online Seminar 2017 Amazon DynamoDB
  • DynamoDB の結果整合性モデル
    • Write
      • 少なくとも 2 つの AZ で書き込み完了が確認された時点で Ack となる
    • Read
      • デフォルト
        • 結果整合性のある読み込み
        • 最新の書き込み結果が即時読み取り処理に反映されない可能性がある
      • Consistent Read オプションをつけた場合
        • GetItem, Query, Scan では強力な整合性のある読み込みオプションが指定可能
        • Read リクエストを受け取る前までの Write が全て反映されたレスポンスを保証
        • Capacity Unit を 2 倍消費する

Q7. EBS-backed インスタンスと Instance store-backed インスタンスの違い

設問

Amazon EBS‐backed インスタンスと Instance store‐backed インスタンスの違いは何ですか?

A. Instance store‐backed インスタンスは停止と再開ができる。
B. Auto Scaling には Amazon EBS‐backed インスタンスを使う必要がある。
C. Amazon EBS‐backed インスタンスは停止と再開ができる。
D. Virtual Private Cloud には EBS‐backed インスタンスが必要である。

正答

メモ

こちら より引用.

すべての AMI が Amazon EBS-Backed と Instance Store-Backed のいずれかに分類されます。前者は、AMI から起動されるインスタンスのルートデバイスが、Amazon EBS スナップショットから作成される Amazon EBS ボリュームであるということです。後者は、AMI から起動されるインスタンスのルートデバイスが、Amazon S3 に格納されたテンプレートから作成されるインスタンスストアボリュームであるということです

さらに, こちら から引用.

Amazon EC2 のサービス開始当初は、すべての AMI が「Amazon EC2 インスタンスストア backed」でした。つまり、AMI から起動されるインスタンスのルートデバイスは、Amazon S3 に格納されたテンプレートから作成されるインスタンスストアボリュームです。Amazon EBS の導入後は Amazon EBS を基にした AMI も導入されました。つまり、AMI から起動されるインスタンスのルートデバイスが、Amazon EBS スナップショットから作成される Amazon EBS ボリュームであるということです。

フムフム.

2018 年 08 月 16 日 (木)

ジョギング

日課

  • 腰と腰に痛みがあるので止めといた

パスタ

  • 夕飯はパスタ
  • 好評だったが, 奥さんはゲップが止まらない感じだった

2018 年 08 月 15 日 (水)

ジョギング

  • 香椎浜 x 2 周
  • ギョーム後, 夜の方が涼しくて走りやすい...でも, 汗だくだった

日課

  • 腰と腰に痛みがあるので止めといた

香椎ミートアップ

  • 香椎近隣に住んでいるエンジニアの皆さんともりすで呑む
  • 色々と喋れて楽しかった

今日のるびぃ exercism 編 〜 Raindrops (1) 〜

ギョームで Ruby を触ることが無さすぎるので, exercism の問題を解くことにした.

概要

fizzbuzz っぽいやつ.

  • If the number has 3 as a factor, output 'Pling'.
  • If the number has 5 as a factor, output 'Plang'.
  • If the number has 7 as a factor, output 'Plong'.
  • If the number does not have 3, 5, or 7 as a factor,

テスト

require 'minitest/autorun'
require_relative 'raindrops'

# Common test data version: 1.0.0 9db5371
class RaindropsTest < Minitest::Test
  def test_the_sound_for_1_is_1
    # skip
    assert_equal "1", Raindrops.convert(1)
  end

  def test_the_sound_for_3_is_pling
    # skip
    assert_equal "Pling", Raindrops.convert(3)
  end

  def test_the_sound_for_5_is_plang
    # skip
    assert_equal "Plang", Raindrops.convert(5)
  end

  def test_the_sound_for_7_is_plong
    # skip
    assert_equal "Plong", Raindrops.convert(7)
  end

  def test_the_sound_for_6_is_pling_as_it_has_a_factor_3
    # skip
    assert_equal "Pling", Raindrops.convert(6)
  end

  def test_2_to_the_power_3_does_not_make_a_raindrop_sound_as_3_is_the_exponent_not_the_base
    # skip
    assert_equal "8", Raindrops.convert(8)
  end

  def test_the_sound_for_9_is_pling_as_it_has_a_factor_3
    # skip
    assert_equal "Pling", Raindrops.convert(9)
  end

  def test_the_sound_for_10_is_plang_as_it_has_a_factor_5
    # skip
    assert_equal "Plang", Raindrops.convert(10)
  end

  def test_the_sound_for_14_is_plong_as_it_has_a_factor_of_7
    # skip
    assert_equal "Plong", Raindrops.convert(14)
  end

  def test_the_sound_for_15_is_plingplang_as_it_has_factors_3_and_5
    # skip
    assert_equal "PlingPlang", Raindrops.convert(15)
  end

  def test_the_sound_for_21_is_plingplong_as_it_has_factors_3_and_7
    # skip
    assert_equal "PlingPlong", Raindrops.convert(21)
  end

  def test_the_sound_for_25_is_plang_as_it_has_a_factor_5
    # skip
    assert_equal "Plang", Raindrops.convert(25)
  end

  def test_the_sound_for_27_is_pling_as_it_has_a_factor_3
    # skip
    assert_equal "Pling", Raindrops.convert(27)
  end

  def test_the_sound_for_35_is_plangplong_as_it_has_factors_5_and_7
    # skip
    assert_equal "PlangPlong", Raindrops.convert(35)
  end

  def test_the_sound_for_49_is_plong_as_it_has_a_factor_7
    # skip
    assert_equal "Plong", Raindrops.convert(49)
  end

  def test_the_sound_for_52_is_52
    # skip
    assert_equal "52", Raindrops.convert(52)
  end

  def test_the_sound_for_105_is_plingplangplong_as_it_has_factors_3_5_and_7
    # skip
    assert_equal "PlingPlangPlong", Raindrops.convert(105)
  end

  def test_the_sound_for_3125_is_plang_as_it_has_a_factor_5
    # skip
    assert_equal "Plang", Raindrops.convert(3125)
  end

... 略 ...

  def test_bookkeeping
    skip
    assert_equal 3, BookKeeping::VERSION
  end
end

実装

最初の実装 (だいぶんイケてない)

class Raindrops
  class << self
    def convert(num)
      if num % 3 == 0 && num % 5 == 0 && num % 7 == 0 then
        'PlingPlangPlong'
      elsif num % 3 == 0 && num % 5 == 0 then
        'PlingPlang'
      elsif num % 3 == 0 && num % 7 == 0 then
        'PlingPlong'
      elsif num % 5 == 0 && num % 7 == 0 then
        'PlangPlong'
      elsif num % 3 == 0 then
        'Pling'
      elsif num % 5 == 0 then
        'Plang'
      elsif num % 7 == 0 then
        'Plong'
      else
        num.to_s
      end
    end
  end
end

一応, テストは通る.

$ ruby raindrops_test.rb
Run options: --seed 43598

# Running:

..............S....

Finished in 0.001604s, 11845.3866 runs/s, 11221.9452 assertions/s.

19 runs, 18 assertions, 0 failures, 0 errors, 1 skips

You have skipped tests. Run with --verbose for details.

次の実装 (ググった)

あまりにイケてなかったので, ググったらいくつかサンプルが公開されていたので, 参考にさせて頂いて以下のような実装にしてみた.

class Raindrops
  def self.convert(num)
    res = ''

    {
      3 => 'Pling',
      5 => 'Plang',
      7 => 'Plong'
    }.each do |n, w|
      res << w if num % n == 0
    end

    res.empty? ? num.to_s : res
  end
end

Run Test

$ ruby raindrops_test.rb
Run options: --seed 32293

# Running:

...............S...

Finished in 0.002184s, 8699.6337 runs/s, 8241.7582 assertions/s.

19 runs, 18 assertions, 0 failures, 0 errors, 1 skips

You have skipped tests. Run with --verbose for details.

いい感じ.

メモ

  • 最初の実装くらいしか出てこないのが, 今の自分の実力である...

2018 年 08 月 14 日 (火)

ジョギング

  • 香椎浜 x 2 周
  • まだ腰が痛い...背中も痛い

日課

  • 腰と腰に痛みがあるので止めといた

さつま牛

実家から送ってもらった牛肉が超絶美味しくてびっくりした. 今日は薄切りだったのでサッと焼いて大根おろしカイワレ大根を巻いて食べた. サイコー.

2018 年 08 月 13 日 (月)

ジョギング

  • 香椎浜 x 2 周
  • うーむ, 左の腰からおしりにかけて痛い (一昨日のマッサージの影響)

日課

  • 腰に痛みがあるので止めといた

世の中的に

お休みな雰囲気. 三号線を行き交う車もだいぶん少ない感じ.

体調がイマイチで, 終日, 倦怠感が続いている.

2018 年 08 月 12 日 (日)

ジョギング

  • 昨日のマッサージの際に腰を痛めた感じになっているのでお休み...

日課

  • 同上

終日

ダラダラと過ごす.

何気なく Datadog について調べていたら, APMPHP が対応しはじめていたのでライブラリのドキュメントを読んでみると OpenTracing という標準化実装があるらしいので, ざくっと調べてブロクに認めた. なんか, 久しぶりにブログを書いた気がして疲れたし, 内容が薄っぺらいなあと反省.

inokara.hateblo.jp

夕飯はステーキ

実家から和牛のステーキが送られてきた. 見様見真似で家庭用のフライパンで焼いて食べたら超絶美味しかった. 感謝.

Datadog APM について調べていたら, OpenTracing に辿り着いた (1)

tl;dr

Datadog APMPHP にも対応するということで, DD Trace PHP について調べていたら, ドキュメントに以下のように書かれていたので OpenTracing について少しだけ深掘りしてみた.

In order to be familiar with tracing elements it is recommended to read the OpenTracing specification.

OpenTracing について

OpenTracing とは

こちら の資料から引用させて頂いた.

  • 分散トレーシングシステムの標準化を目的とした実装
  • ベンダーニュートラルな実装である為, 最小限のコード変更により, OpenTracing に準拠した分散トレースバックエンドから別の分散トレースバックエンドにアプリケーションを簡単に移植することが出来る
  • OpenTracing プロジェクトは 2015 年に始まり, 2016 年 10 月には Kubernetesプロジェクトなどを主催する CNCF に受け入れている

そもそも分散トレーシングとは

こちらの記事より抜粋させて頂いた.

  • マイクロサービス化により, モノリシックアーキテクチャと比較して, システム全体としての振る舞いを把握することが難しい
    • システム障害発生時の原因究明が難しくなったり, パフォーマンスの分析が難しくなる
  • 分散トレーシングは, 特定のクライアントリクエストを処理する為に関わったサービスを探したり, レイテンシに関するパフォーマンスをデバッグする時に利用される
  • 実装のアプローチは大別すると以下の 2 種類
    • Black-box schemes ... システム (コード) に手を入れる必要がないことが利点, 特定のリクエストに対する分析が出来ない
    • Annotation-based schemes ... 各サービスに分散トレーシング用のメタデータを付加して下流サービスへと伝播させる実装が必要になるが, 特定のリクエストを分析することが出来る

ありがとうございます.

Datadog x OpenTraning

こちら のブログによると, Datadog APM においても OpenTracing をサポートしており, ライブラリをインクルードして数行のコードを記述することで OpenTracing API を利用したトレースを開始出来るとある.

OpenTracing の用語

OpenTracing というか, 分散トレーシングに出てくる各種用語を簡単に.

こちら より引用させて頂いた.

  • Span
    • 一つのサービス (上図だと, Client や billing 等) 内の処理
  • Trace
    • Span の開始 (Start) から終了 (Finish) までを含む Span の集合体

こちら の資料から引用させて頂いた.

その他, Operation Name, Start, Finish の Timestamp, Span Context については必須となっている.

Jaeger で体験する OpenTracing

Jaeger

Jaeger はアプリケーションのトレース情報を可視化する OpenTracing に準拠した OSS 実装 (Go で実装されている) である. OpenTracing ドキュメントの Getting Started にも紹介されているので, これを使って OpenTracing を体験してみる. 尚, 本セクションを記述するにあたっては, 以下の記事を参考させて頂いた.

ありがとうございます.

Jaeger の起動

以下のように Jaeger が起動する

docker run -d -e COLLECTOR_ZIPKIN_HTTP_PORT=9411 -p5775:5775/udp -p6831:6831/udp -p6832:6832/udp \
  -p5778:5778 -p16686:16686 -p14268:14268 -p9411:9411 jaegertracing/all-in-one:latest

Jaeger を起動後, ブラウザで http://localhost:16686/ にアクセスすると, 以下のように Jaeger UI にアクセスすることが出来る.

f:id:inokara:20180812133742p:plain

Rack アプリケーション (Sinatra) を利用してトレース情報を送信する

利用するライブラリの導入

Ruby のバージョンは以下の通り.

$ ruby -v
ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin17]

以下のように Gemfile を用意する.

# frozen_string_literal: true

source "https://rubygems.org"

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

gem "sinatra"
gem "opentracing"
gem "rack-tracer"
gem "jaeger-client"

シンプルなアプリケーション

以下, 本当にシンプルなアプリケーション.

require 'sinatra'

require 'opentracing'
require 'jaeger/client'
require 'rack/tracer'

OpenTracing.global_tracer = Jaeger::Client.build(service_name: 'hello')

use Rack::Tracer
random = Random.new

get '/' do
  sleep(random.rand(0.1))
  'Hello'
end

アプリケーションを起動.

bundle exec ruby hello.rb &

curl で適当にアクセスする.

watch 'curl -s localhost:4567 -w "\n"'

しばらく放置.

トレース情報を確認

トレース一覧.

f:id:inokara:20180812134151p:plain

トレース一覧をクリックすると, 下図のように Span ページが表示される.

f:id:inokara:20180812134204p:plain

Span をクリックするとリクエストの詳細等が表示される.

f:id:inokara:20180812134540p:plain

以上

OpenTracing について, 簡単にチュートリアルしてみた. 引き続き, もう少し複雑なアプリケーションを利用して Trace や Span 等の各要素について理解を深めていきたい.

参考

以下の各記事を参考にさせて頂いた.

ありがとうございます. 引き続き, よろしくお願いいたします.