ようへいの日々精進XP

よかろうもん

2018 年 08 月 25 日 (土)

ジョギング

  • 香椎浜 x 2 周
  • 右足の太腿に強い張り
  • んー, 暑さが堪える...

日課

  • そろそろ始めなきゃな...と思ってるところ

星野源のアイデア

www.youtube.com

新しい感じがしたり, 色々とアイデアが詰まったミュージック・ビデオで良かった. 特に 2 番以降, ガラッと雰囲気が変わったと思ったら, いきなりアコースティック・ギターでの弾き語りがあったりして, そんなに音楽を真剣に聞かない自分だけどすごく印象深い作品だと思う.

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

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

Q4. 一貫性の無い結果を返す操作

設問

Which operation could return temporarily inconsistent results?

  • 一時的に一貫性のない結果を返す操作はどれか
A) Getting an object from Amazon S3 after it was initially created
B) Selecting a row from an Amazon RDS database after it was inserted
C) Selecting a row from an Amazon RDS database after it was deleted
D) Getting an object from Amazon S3 after it was deleted

どれか.

A) Amazon S3 において, 初めてオブジェクトを作成した直後にオブジェクトを取得する
B) Amazon RDS において, データベースを挿入した後にその行を選択する
C) Amazon RDS において, 行を削除した直後に行を選択する
D) Amazon S3 において, オブジェクトを削除した直後にオブジェクトを取得する

正答

D) Getting an object from Amazon S3 after it was deleted (Amazon S3 において, オブジェクトを削除した直後にオブジェクトを取得する)

メモ

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

S3 has eventual consistency for overwrite PUTS and DELETES.

S3 の PUT と DELETE は結果整合性となる.

Q5. DynamoDB の実装

設問

You are creating a DynamoDB table with the following attributes:

* PurchaseOrderNumber (partition key)
* CustomerID
* PurchaseDate
* TotalPurchaseValue

One of your applications must retrieve items from the table to calculate the total value of purchases for a particular customer over a date range.

以下のような属性を持った DynamoDB テーブルを作成しようとしている.

  • PurchaseOrderNumber (partition key)
  • CustomerID
  • PurchaseDate
  • TotalPurchaseValue

アプリケーションでは, テーブルから項目を取得して, 特定の顧客を特定の期間にわたって特定する. (ちょっと日本語がアレ)

What secondary index do you need to add to the table?

A) Local secondary index with a partition key of CustomerID and sort key of PurchaseDate; project the TotalPurchaseValue attribute
B) Local secondary index with a partition key of PurchaseDate and sort key of CustomerID; project the TotalPurchaseValue attribute
C) Global secondary index with a partition key of CustomerID and sort key of PurchaseDate; project the TotalPurchaseValue attribute
D) Global secondary index with a partition key of PurchaseDate and sort key of CustomerID; project the TotalPurchaseValue attribute

テーブルに追加するセカンダリインデックスはどれか?

A) CustomerID のパーティションキーと PurchaseDate のソートキーを持つローカルのセカンダリインデックス. TotalPurchaseValue 属性を投影する.
B) PurchaseDate のパーティションキーと CustomerID のソートキーを持つローカルのセカンダリインデックス. TotalPurchaseValue 属性を投影する.
C) CustomerID のパーティションキーと PurchaseDate のソートキーを持つグローバルセカンダリインデックス. TotalPurchaseValue 属性を投影する.
D) PurchaseDate のパーティションキーと CustomerID のソートキーを持つグローバルセカンダリインデックス. TotalPurchaseValue 属性を投影する.

正答

C) Global secondary index with a partition key of CustomerID and sort key of PurchaseDate; project the TotalPurchaseValue attribute (CustomerID のパーティションキーと PurchaseDate のソートキーを持つグローバルセカンダリインデックス. TotalPurchaseValue 属性を投影する.)

メモ

The query is for a particular CustomerID, so a Global Secondary Index is needed for a different partition key. To retrieve only the desired date range, the PurchaseDate must be the sort key. Projecting the TotalPurchaseValue into the index provides all the data needed to satisfy the use case.

  • クエリは特定のCustomerIDのため, 別のパーティションキーにはグローバルセカンダリインデックスが必要
  • 目的の日付範囲のみを取得するには, PurchaseDate がソートキーでなければならない
  • TotalPurchaseValue をインデックスに投影すると, ユースケースを満たすために必要なすべてのデータが提供される

Q6. CloudFormation の実装

設問

Your CloudFormation template has the following Mappings section:

あんたの CloudFormation テンプレートにおいて, Mappings セクションは以下の通りである.

"Mappings" : {
 "RegionMap" : {
 "us-east-1" : { "32" : "ami-6411e20d"},
 "us-west-1" : { "32" : "ami-c9c7978c"}
 }
}

Which JSON snippet will result in the value "ami-6411e20d" when a stack is launched in us-east-1?

us-east-1 でスタックを起動した場合, JSON スニペットの値が ami-6411e20d になるのはなぜか.

A) { "Fn::FindInMap" : [ "Mappings", { "RegionMap" : ["us-east-1", "us-west-1"] }, "32"]}
B) { "Fn::FindInMap" : [ "Mappings", { "Ref" : "AWS::Region" }, "32"]}
C) { "Fn::FindInMap" : [ "RegionMap", { "Ref" : "AWS::Region" }, "32"]}
D) { "Fn::FindInMap" : [ "RegionMap", { "RegionMap" : "AWS::Region" }, "32"]}

正答

C) { "Fn::FindInMap" : [ "RegionMap", { "Ref" : "AWS::Region" }, "32"]}

メモ

以下, ドキュメントより引用.

{
  "AWSTemplateFormatVersion" : "2010-09-09",

  "Mappings" : {
    "RegionMap" : {
      "us-east-1" : { "32" : "ami-6411e20d", "64" : "ami-7a11e213" },
      "us-west-1" : { "32" : "ami-c9c7978c", "64" : "ami-cfc7978a" },
      "eu-west-1" : { "32" : "ami-37c2f643", "64" : "ami-31c2f645" },
      "ap-southeast-1" : { "32" : "ami-66f28c34", "64" : "ami-60f28c32" },
      "ap-northeast-1" : { "32" : "ami-9c03a89d", "64" : "ami-a003a8a1" }
    }
  },

  "Resources" : {
    "myEC2Instance" : {
      "Type" : "AWS::EC2::Instance",
      "Properties" : {
        "ImageId" : { "Fn::FindInMap" : [ "RegionMap", { "Ref" : "AWS::Region" }, "32"]},
        "InstanceType" : "m1.small"
      }
    }
  }
}

上記の例だと, FindInMap 関数 (AWS::Region 擬似パラメーターを使用して) を用いて, スタックの作成先となるリージョンとしてキーを指定し, 対応付ける値の名前として 32 を指定している.

フムフム.

俺の A Tour of Go (2)

A Tour of Go

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

Variables

// filename: variables.go
package main

import "fmt"

var c, python, java bool

func main() {
    var i int
    fmt.Println(i, c, python, java)
}

以下, 実行結果.

$ ./_run.sh variables.go 
0 false false false

Variables with initializers

  • https://go-tour-jp.appspot.com/basics/9
  • var 宣言では, 変数毎に初期化子 (initializer) を与えることができる
  • 初期化子が与えられている場合は型を省略出来, その変数は初期化子が持つ型となる
// filename: variables-with-initializers.go
package main

import "fmt"

var i, j int = 1, 2

func main() {
    var c, python, java = true, false, "no!"
    fmt.Println(i, j, c, python, java)
}

以下, 実行結果.

$ ./_run.sh variables-with-initializers.go 
1 2 true false no!

あまり関係ないかもしれないけど, 変数にスコープって存在しないのかなと思ったりした.

Short variable declarations

  • https://go-tour-jp.appspot.com/basics/10
  • 関数の中では, var 宣言の代わりに, 短い := の代入文を使って暗黙的な型宣言が出来る
  • 関数外では, キーワードではじまる宣言 (var, func, など) が必要で := での暗黙的な宣言は利用出来ない
// filename: short-variable-declarations.go
package main

import "fmt"

func main() {
    var i, j int = 1, 2
    k := 3
    c, python, java := true, false, "no!"

    fmt.Println(i, j, k, c, python, java)
}

変数 kvar で宣言されていないが, 代入文として := が利用されている為, 3 が代入されている.

$ ./_run.sh short-variable-declarations.go 
1 2 3 true false no!

Basic types

Go 言語の基本型 (組み込み型) は以下の通り.

bool

string

int  int8  int16  int32  int64
uint uint8 uint16 uint32 uint64 uintptr

byte // uint8 の別名

rune // int32 の別名
     // Unicode のコードポイントを表す

float32 float64

complex64 complex128
  • https://go-tour-jp.appspot.com/basics/11
  • int, uint, uintptr 型は, 32-bit のシステムでは 32 bit で, 64-bit のシステムでは 64 bit を表現する
  • サイズ, 符号なし (unsigned) 整数の型を使うための特別な理由がない限り, 整数の変数が必要な場合は int を使うようにする
// filename: basic-types.go
package main

import (
    "fmt"
    "math/cmplx"
)

var (
    ToBe   bool       = false
    MaxInt uint64     = 1<<64 - 1
    z      complex128 = cmplx.Sqrt(-5 + 12i)
)

func main() {
    fmt.Printf("Type: %T Value: %v\n", ToBe, ToBe)
    fmt.Printf("Type: %T Value: %v\n", MaxInt, MaxInt)
    fmt.Printf("Type: %T Value: %v\n", z, z)

以下, 実行結果.

$ ./_run.sh basic-types.go 
Type: bool Value: false
Type: uint64 Value: 18446744073709551615
Type: complex128 Value: (2+3i)

%T で変数の型, %v で変数の中身にアクセスすることが出来るようだ.

// filename: basic-types2.go
package main

import (
    "fmt"
)

var (
    Foo    string     = "Foo"
)

func main() {
    fmt.Printf("Type: %T Value: %v\n", Foo, Foo)
}

以下, 実行結果.

$ ./_run.sh basic-types2.go 
Type: string Value: Foo

Zero values

  • https://go-tour-jp.appspot.com/basics/12
  • 変数に初期値を与えずに宣言すると, ゼロ値 (zero value) が与えられる
  • ゼロ値は型によって以下のように与えられる
    • 数値型 (int,float など): 0
    • bool 型: false
    • string 型: "" (空文字列 (empty string))
// filename: zero.go
package main

import "fmt"

func main() {
    var i int
    var f float64
    var b bool
    var s string
    fmt.Printf("%v %v %v %q\n", i, f, b, s)
}

以下, 実行結果.

$ ./_run.sh zero.go 
0 0 false ""

Type conversions

以下, 変換の例.

var i int = 42
var f float64 = float64(i)
var u uint = uint(f)

# よりシンプルに
i := 42
f := float64(i)
u := uint(f)

C 言語とは異なり, Go での型変換は明示的な変換が必要となる.

// filename: type-conversions.go
package main

import (
    "fmt"
    "math"
)

func main() {
    var x, y int = 3, 4
    var f float64 = math.Sqrt(float64(x*x + y*y))
    var z uint = uint(f)
    fmt.Println(x, y, z)
}

以下, 実行結果.

$ ./_run.sh type-conversions.go 
3 4 5

以下, float64 に型変換しなかった場合の実行結果.

$ ./_run.sh type-conversions.go 
# command-line-arguments
/sandbox/type-conversions.go:11:33: cannot use x * x + y * y (type int) as type float64 in argument to math.Sqrt

Type inference

  • https://go-tour-jp.appspot.com/basics/14
  • 明示的な型を指定せずに変数を宣言する場合 (:= や var = のいずれか), 変数の型は右側の変数から型推論される
  • 以下のように, 右側の変数が型を持っている場合, 左側の新しい変数は同じ型になる
var i int
j := i // j の型は int になる

上記を念の為, 確認する.

// filename: type-inference-check1.go
package main

import (
    "fmt"
)

func main() {
  var i int = 100
  j := i
  fmt.Printf("Type: %T Value: %v\n", j, j)
}

実行してみると...

$ ./_run.sh type-inference-check.go 
Type: int Value: 100

右側に型を指定しない数値である場合, 左側の新しい変数は右側の定数の精度に基いて int, float64, complex128 の型となる.

i := 42           // int
f := 3.142        // float64
g := 0.867 + 0.5i // complex128

こちらも念の為に確認.

// filename: type-inference-check2.go
package main

import (
    "fmt"
)

func main() {
  i := 42
  f := 3.142
  g := 0.867 + 0.5i
  fmt.Printf("Type: %T Value: %v\n", i, i)
  fmt.Printf("Type: %T Value: %v\n", f, f)
  fmt.Printf("Type: %T Value: %v\n", g, g)
}

実行してみると...

$ ./_run.sh type-inference-check2.go 
Type: int Value: 42
Type: float64 Value: 3.142
Type: complex128 Value: (0.867+0.5i)

以下, ツアーのコード.

// filename: type-inference.go
package main

import "fmt"

func main() {
    v := 42 // change me!
    fmt.Printf("v is of type %T\n", v)
}

以下, 実行.

$ ./_run.sh type-inference.go 
v is of type int

例えば, v の値を "foo" にした場合には以下のような結果となった.

$ ./_run.sh type-inference.go 
v is of type string

Constants

  • https://go-tour-jp.appspot.com/basics/15
  • 定数 (constant) は, const キーワードを使って変数と同じように宣言可
  • 定数は, 文字 (character), 文字列 (string), boolean, 数値 (numeric) のみで利用可能
  • 定数は := を使って宣言不可
// filename: constants.go
package main

import "fmt"

const Pi = 3.14

func main() {
    const World = "世界"
    fmt.Println("Hello", World)
    fmt.Println("Happy", Pi, "Day")

    const Truth = true
    fmt.Println("Go rules?", Truth)
}

以下, 実行結果.

$ ./_run.sh constants.go 
Hello 世界
Happy 3.14 Day
Go rules? true

Numeric Constants

// filename: numeric-constants.go
package main

import "fmt"

const (
    // Create a huge number by shifting a 1 bit left 100 places.
    // In other words, the binary number that is 1 followed by 100 zeroes.
    Big = 1 << 100
    // Shift it right again 99 places, so we end up with 1<<1, or 2.
    Small = Big >> 99
)

func needInt(x int) int { return x*10 + 1 }
func needFloat(x float64) float64 {
    return x * 0.1
}

func main() {
    fmt.Println(needInt(Small))
    fmt.Println(needFloat(Small))
    fmt.Println(needFloat(Big))
}

以下, 実行例.

$ ./_run.sh numeric-constants.go 
21
0.2
1.2676506002282295e+29

コードの needInt(Big) を出力した場合...

$ ./_run.sh numeric-constants.go 
# command-line-arguments
/sandbox/numeric-constants.go:20:21: constant 1267650600228229401496703205376 overflows int

int は 64-bit の整数を保持出来るが, それでは足りないことがある場合に const を活用する.

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

以上, Basics が終了〜でした.

2018 年 08 月 24 日 (金)

ジョギング

  • 右足甲と右太腿に痛みがあったので, 香椎浜まで散歩
  • 右太腿の痛みはいつものやつだと思うんだけど, 強い張りを感じている

日課

  • そろそろ始めなきゃな...と思ってるところ

体調

あまり良くない. 夏バテが今頃きている感じ.

Software Design 2018 年 9 月号

gihyo.jp

今すぐデータサイエンス云々をどうこうするつもりは無いけど, 「統計学」というワードに惹かれたので購入. 読み始めている. とにかくちんぷんかんである.

久しぶりに

Go を触っている. 以前にギョームで見様見真似で作ったツールの改修. Hello World からやり直ししなければいけないなと反省しているところ.

2018 年 08 月 23 日 (木)

ジョギング

  • 香椎浜 x 2 周
  • 右足甲と右太腿に痛み
  • 明日は散歩に切り替えるつもり

日課

  • そろそろ始めなきゃな...と思ってるところ

放送大学

Ruby 認定試験と同日に受験した放送大学の単位認定試験だったけど, その結果が学生専用サイトで公開されていた. レポート自体は「優」を頂いていたけど, 試験自体は自信が無かったのでどーなるだろうなあと思っていたが, 良い結果に倒れたので安心している.

レポート書いたり, 試験受けたり大変だったけど, 久しぶりの経験で少し学生生活に浸ることが出来て楽しかった.

2018 年 08 月 22 日 (水)

ジョギング

  • 香椎浜 x 2 周
  • 右足甲に痛み
  • 疲れが溜まっている感があり, すごくキツかった

日課

  • そろそろ始めなきゃな...

Serverless Meetup Fukuoka #2

serverless.connpass.com

サーバーがあるからサーバーレスというバズワードが生まれたとするならば, きっと, 数年後にはサーバーレスという言葉も無くなって, なんにも, 誰もその存在を意識しないアプリケーションの実行環境という感じになるんじゃないかなーという話を懇親会で話したのがハイライトだった.

2018 年 08 月 21 日 (火)

ジョギング

  • 右足太ももに違和感が痛みになったのでお休み

日課

  • だらだらーっとお休みしてしまった
  • そろそろ始めなきゃな...

明日は

serverless.connpass.com

次は勉強して登壇したいな.

2018 年 08 月 20 日 (月)

ジョギング

  • 香椎浜 x 2 周
  • ゆっくりとダラッと走った
  • 右足太ももに違和感, ちょと休もうかな

日課

  • 引き続き, 腰に痛みがあるので休み中
  • そろそろ始めなきゃな...

奥さん

  • 体調を崩す
  • 涼しかったり, 暑かったり, 昨日は色々と大変だったからな...

疲れていたので

  • 日記も書かずに寝てしまっていた

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 を利用する
  • バケット内のオブジェクト数は無制限

フムフム.